diff --git a/.env b/.env new file mode 100644 index 0000000..cb3a8ac --- /dev/null +++ b/.env @@ -0,0 +1,99 @@ +APP_DEBUG =true + +[APP] +DEFAULT_TIMEZONE = Asia/Shanghai +CROSS_ORIGIN = true + +[DATABASE] +TYPE = mysql +HOSTNAME = 127.0.0.1 +DATABASE = bourse +USERNAME = root +PASSWORD = Meetingyou0))2024$ +HOSTPORT = 23306 +CHARSET = utf8 +DEBUG = true +prefix = bot_ + +[LANG] +default_lang = zh-cn + +[REDIS] +HOST = 127.0.0.1 +PORT = 26379 +SELECT = 0 +PASSWORD = 7d00cb62-1d1c-4c86-b50a-ebf9f00cc9fd + +[EMAIL] +# 多个以逗号隔开 +DENY_EMAIL_TYPE = 163.com,qq.com,126.com,sina.com,sohu.com.aliyun.com,139.com,189.cn +Host= smtpdm-ap-southeast-1.aliyun.com +Username=service@reg.macquariegig.com +Password=rE51XlFpjJeMhLoHooX +From=service@reg.macquariegig.com + +[NATION] +# 多个以逗号隔开 +DENY_NATION = 86,886,852,853 + +[ENCRYPT] +SALT = #$%^issoeasy%$#$^ +ADMINSALT = #1%^issoeasy%$%$^ +[SMS] +# 短信秘钥对 可拼接多个 key@secret,key@secret +CONFIG = LTAI5tMYUS9asodB6n2qSL9Y@TIMy9s5m7mHSPZN4uRahok4GRdWH1p + +[LOGIN] +PER_IP_REGISTER_NUM_EVERY_DAY = 100 +PER_IP_GET_CODE_NUM = 1000 +PER_PHONE_GET_CODE_NUM = 5 + +[USER] +DEFAULT_HEAD_IMG_PATH = /bs/image/default.jpeg + +[BACKEND] +BASE_URL=http://testmg.coincosmic.net +[AGENT] +AGENT_GROUP_ID=6 + +[QUOTE] +BASE_URL=10.154.0.8:88 +DEAL_BASE_URL=http://10.154.0.7:8000 + + + +[FEATURE] +HAS_TEAM = true +HAS_DIGITAL = true +HAS_CONTRACT = true +HAS_STOCK_US = true + +[PAY] +NOTIFY_URL= https://api.twinim.com +[WALLET] +NAME=test +WALLET_TYPE=TRC-20 +HTTP_URL=https://wallet.orcoin.net + +[QEAE_PAY] +#key +KEY=399fd368dbd84b3fbee7012f20ca0b45 +#代付 key +DF_KEY=UQBCGZ3IWBVWUUDXYU8ZDXZ2QOQAC2DN +#商户号 +MERCHANT=400029056 + +[REG_USER] +INVITE_CODE_REQUIRED = 1 + +[OPTION_REFRESH] +OPTION_REFRESH_IN_URL=https://quotes.sysdev8.cc/option/php/list?country=India + +[USER_ARREARS] +HAS_USER_ARREARS = 3 + +[USER_LEVEL] +NO_APPLY=1 + +[ACCOUT_TYPE] +ALL_IN_ONE=1 diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..736ef12 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,8 @@ + + Options +FollowSymlinks -Multiviews + RewriteEngine On + + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] + \ No newline at end of file diff --git a/app/404.html b/app/404.html new file mode 100644 index 0000000..f3d1a5c --- /dev/null +++ b/app/404.html @@ -0,0 +1,10 @@ + + + + + 404 + + +宝藏不见了 + + \ No newline at end of file diff --git a/app/AppService.php b/app/AppService.php new file mode 100644 index 0000000..8b09c45 --- /dev/null +++ b/app/AppService.php @@ -0,0 +1,22 @@ +app = $app; + $this->request = $this->app->request; + + // 控制器初始化 + $this->initialize(); + } + + // 初始化 + protected function initialize() + {} + + /** + * 验证数据 + * @access protected + * @param array $data 数据 + * @param string|array $validate 验证器名或者验证规则数组 + * @param array $message 提示信息 + * @param bool $batch 是否批量验证 + * @return array|string|true + * @throws ValidateException + */ + protected function validate(array $data, $validate, array $message = [], bool $batch = false) + { + if (is_array($validate)) { + $v = new Validate(); + $v->rule($validate); + } else { + if (strpos($validate, '.')) { + // 支持场景 + [$validate, $scene] = explode('.', $validate); + } + $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate); + $v = new $class(); + if (!empty($scene)) { + $v->scene($scene); + } + } + + $v->message($message); + + // 是否批量验证 + if ($batch || $this->batchValidate) { + $v->batch(true); + } + + return $v->failException(true)->check($data); + } + +} diff --git a/app/ExceptionHandle.php b/app/ExceptionHandle.php new file mode 100644 index 0000000..9031efc --- /dev/null +++ b/app/ExceptionHandle.php @@ -0,0 +1,58 @@ +addUser($this->request->param()); + return json($result); + } + + public function updateInfo() + { + $service = new AdminService(); + $result = $service->updateInfo($this->request->user_id,$this->request->param()); + return json($result); + } + public function getUserInfo() + { + $service = new AdminService(); + $result = $service->getUserInfo($this->request->user_id); + return json($result); + } + + public function updatePassword() + { + $service = new AdminService(); + $result = $service->updatePassword($this->request->user_id,$this->request->param()); + return json($result); + } + + //账号列表 + public function getUserList() + { + $returnData = (new AdminService())->getUserList($this->request->param()); + return json($returnData); + } + //编辑账号 + public function updateAccount(){ + $returnData = (new AdminService())->updateAccount($this->request->param('id'),$this->request->param()); + return json($returnData); + } + + //更新账号状态 + public function updateAccountStauts(){ + $returnData = (new AdminService())->updateAccountStauts($this->request->param('id'),$this->request->param()); + return json($returnData); + } + + //删除指定用户 + public function del(){ + $returnData = (new AdminService())->del($this->request->param('id')); + return json($returnData); + } + //获取用户权限代码 + public function getPermCode(){ + $returnData = (new AdminService())->getPermCode($this->request->user_id); + return json($returnData); + } + + //退出登陆 + public function logout() + { + $returnData = (new AdminService())->logout($this->request->user_id); + return json($returnData); + } + + //操作日志 + public function log() + { + $returnData = (new AdminService())->logList($this->request->param()); + return json($returnData); + } + + public function inviteCode(){ + $returnData = (new AdminService())->inviteCode(); + return json($returnData); + } +} diff --git a/app/admin/controller/AdminBaseController.php b/app/admin/controller/AdminBaseController.php new file mode 100644 index 0000000..1a0dd9c --- /dev/null +++ b/app/admin/controller/AdminBaseController.php @@ -0,0 +1,15 @@ +request->user_id; + } + +} \ No newline at end of file diff --git a/app/admin/controller/Agent.php b/app/admin/controller/Agent.php new file mode 100644 index 0000000..a0027ed --- /dev/null +++ b/app/admin/controller/Agent.php @@ -0,0 +1,33 @@ +index(); + return json($result); + } + + // 代理用户列表 + public function user() + { + $service = new AgentService(); + $result = $service->user($this->request->param()); + return json($result); + } + + // 管理用户 + public function manager() + { + $service = new AgentService(); + $result = $service->manager($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/Config.php b/app/admin/controller/Config.php new file mode 100644 index 0000000..2e6daf7 --- /dev/null +++ b/app/admin/controller/Config.php @@ -0,0 +1,58 @@ +request->param(); + if (empty($param['name'])) return json(['code' => '1', 'message' => '参数错误', 'data' => []]); + $name = $param['name']; + $type = $param['type'] ?? 'string'; + $value = $param['value'] ?? ''; + $tip = $param['tip'] ?? ''; + + $insertData = [ + 'name' => $name, + 'group' => 'config', + 'title' => $name, + 'tip' => $tip, + 'type' => $type, + 'value' => $value, + ]; + + $config = ConfigModel::where('name', $name)->find(); + if (empty($config)) { + $bool = ConfigModel::insert($insertData); + if (!$bool) return json(['code' => '100500', 'message' => '设置失败', 'data' => []]); + } else { + $bool = ConfigModel::where('name', $name)->update($insertData); + if (!$bool) return json(['code' => '100500', 'message' => '设置失败', 'data' => []]); + } + + return json(['code' => '0', 'message' => 'Request successful', 'data' => []]); + } catch (\Exception $exception) { + return json(['code' => '100500', 'message' => '系统繁忙', 'data' => [$exception->getMessage()]]); + } + } + + public function getConfig() + { + try { + $param = $this->request->param(); + if (empty($param['name'])) return json(['code' => '1', 'message' => '参数错误', 'data' => []]); + $name = $param['name']; + $value = ConfigModel::where('name', $name)->value('value'); + + return json(['code' => '0', 'message' => 'Request successful', 'data' => ['value' => $value]]); + } catch (\Exception $exception) { + return json(['code' => '100500', 'message' => '系统繁忙', 'data' => [$exception->getMessage()]]); + } + } +} \ No newline at end of file diff --git a/app/admin/controller/Country.php b/app/admin/controller/Country.php new file mode 100644 index 0000000..346fd8c --- /dev/null +++ b/app/admin/controller/Country.php @@ -0,0 +1,41 @@ +isEmpty()){ + $deny = explode(',', env('NATION.DENY_NATION')); + foreach ($res as $item) { + $active = 1; + if(in_array($item['code'],$deny )){ + $active = 0; + } + $returnData[] = [ + 'id' => $item['id'], + 'nameCn' => $item['name_cn'], + 'nameEn' => $item['name_en'], + 'nation' => $item['code'], + 'active' => $active, + ]; + } + } + return json(['code' => '0', 'message' => '请求成功','data' => $returnData]); + }catch (\Exception $exception){ + return json(['code' => '100500', 'message' => '系统繁忙','data' => []]); + } + + } +} \ No newline at end of file diff --git a/app/admin/controller/Flow.php b/app/admin/controller/Flow.php new file mode 100644 index 0000000..929f0bc --- /dev/null +++ b/app/admin/controller/Flow.php @@ -0,0 +1,99 @@ +digital($this->request->param(),$this->getAdminId()); + return json($result); + } + + public function stock() + { + $service = new FlowService(); + $result = $service->stock($this->request->param(),$this->getAdminId()); + return json($result); + } + + public function contract() + { + $service = new FlowService(); + $result = $service->contract($this->request->param(),$this->getAdminId()); + return json($result); + } + + public function forex() + { + $service = new FlowService(); + $result = $service->forex($this->request->param(),$this->getAdminId()); + return json($result); + } + + public function transfer() + { + $service = new FlowService(); + $result = $service->transfer($this->request->param(),$this->getAdminId()); + return json($result); + } + + public function fee() + { + $service = new FlowService(); + $result = $service->fee($this->request->param(),$this->getAdminId()); + return json($result); + } + + public function brokerage() + { + $service = new FlowService(); + $result = $service->brokerage($this->request->param(),$this->getAdminId()); + return json($result); + } + + ################################ 股票资产流水 ##################################### + + // 股票流水 + public function StockLogs() + { + $service = new FlowService(); + $result = $service->StockLogs($this->request->param(),$this->getAdminId()); + return json($result); + } + + // 基金流水 + public function fundStock() + { + $service = new FlowService(); + $result = $service->fundStock($this->request->param(),$this->getAdminId()); + return json($result); + } + + // 印度期权流水 + public function inOptionStock() + { + $service = new FlowService(); + $result = $service->inOptionStock($this->request->param(),$this->getAdminId()); + return json($result); + } + + // 印度期权流水 + public function blockStock() + { + $service = new FlowService(); + $result = $service->blockStock($this->request->param(),$this->getAdminId()); + return json($result); + } + public function allList() + { + $service = new FlowService(); + $result = $service->allList($this->request->param(),$this->getAdminId()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/Index.php b/app/admin/controller/Index.php new file mode 100644 index 0000000..abedeab --- /dev/null +++ b/app/admin/controller/Index.php @@ -0,0 +1,1076 @@ +getName(); + $digitalTradeTableName = $prefix . (new DigitalTradeModel())->getName(); + $rechargeApplyTableName = $prefix . (new RechargeApplyModel())->getName(); + $stockTradeTableName = $prefix . (new StockTradeModel())->getName(); + $stockMysTradeTableName = $prefix . (new StockMysTradeModel())->getName(); + $stockThaTradeTableName = $prefix . (new StockThaTradeModel())->getName(); + $stockIdnTradeTableName = $prefix . (new StockIdnTradeModel())->getName(); + $stockInTradeTableName = $prefix . (new StockInTradeModel())->getName(); + + $userTableName = $prefix . (new UserModel())->getName(); + $userWithdrawTableName = $prefix . (new UserWithdrawalModel())->getName(); + + + // 总注册人数(用户的总数) + $totalRegisterNum = Db::table($userTableName)->count(); + + // 总充值用户(充值用户的个数 以用户id分组) + $totalRechargeNum = Db::table($rechargeApplyTableName)->where('status', 1)->group('user_id')->count(); + + // 总交易用户(合约 股票 现货 交易的用户去重 订单状态为持仓 和 完成 订单) + $contractTradeUserId = Db::table($ContractTradeTableName)->where('status', 'in', [1, 3])->distinct(true)->column('user_id'); + $stockTradeUserId = Db::table($stockTradeTableName)->where('status', 'in', [1, 3])->distinct(true)->column('user_id'); + $stockMysTradeUserId = Db::table($stockMysTradeTableName)->where('status', 'in', [1, 3])->distinct(true)->column('user_id'); + $stockThaTradeUserId = Db::table($stockThaTradeTableName)->where('status', 'in', [1, 3])->distinct(true)->column('user_id'); + $stockIdnTradeUserId = Db::table($stockIdnTradeTableName)->where('status', 'in', [1, 3])->distinct(true)->column('user_id'); + $stockInTradeUserId = Db::table($stockInTradeTableName)->where('status', 'in', [1, 3])->distinct(true)->column('user_id'); + $digitalTradeUserId = Db::table($digitalTradeTableName)->where('status', 'in', [1, 3])->distinct(true)->column('user_id'); + + $totalArrayMerge = array_unique(array_merge($contractTradeUserId, $stockTradeUserId, $digitalTradeUserId, $stockMysTradeUserId, $stockIdnTradeUserId, $stockThaTradeUserId, $stockInTradeUserId)); + $totalTradeNum = count($totalArrayMerge); + + // 总提现用户(以用户id 分组查询数量) + $totalWithdrawalNum = Db::table($userWithdrawTableName)->group('user_id')->count(); + + // 总充值金额 充值完成 + $totalRechargeAmount = Db::table($rechargeApplyTableName)->where('status', 1)->sum('recharge_num'); + + // 总提款金额 提款完成 + $totalWithdrawAmount = Db::table($userWithdrawTableName)->where('status', 2)->sum('apply_num'); + + + // 今日注册用户 + $today = date('Y-m-d'); // 今天凌晨 + $tomorrow = date('Y-m-d', strtotime('tomorrow')); // 明天凌晨 + $todayRegisterNum = Db::table($userTableName)->whereTime('create_time', 'between', [$today, $tomorrow])->count(); + + // 今日充值用户 完成状态 + $todayRechargeNum = Db::table($userTableName)->where('status', 1) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->group('user_id')->count(); + + // 今日交易用户 + // 合约 + $todayContractTradeUserId = Db::table($ContractTradeTableName)->where('status', 'in', [1, 3]) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->distinct(true)->column('user_id'); + //股票 + $todayStockTradeUserId = Db::table($stockTradeTableName)->where('status', 'in', [1, 3]) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->distinct(true)->column('user_id'); + $todayStockMysTradeUserId = Db::table($stockMysTradeTableName)->where('status', 'in', [1, 3]) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->distinct(true)->column('user_id'); + $todayStockThaTradeUserId = Db::table($stockThaTradeTableName)->where('status', 'in', [1, 3]) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->distinct(true)->column('user_id'); + $todayStockIndTradeUserId = Db::table($stockIdnTradeTableName)->where('status', 'in', [1, 3]) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->distinct(true)->column('user_id'); + $todayStockInTradeUserId = Db::table($stockInTradeTableName)->where('status', 'in', [1, 3]) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->distinct(true)->column('user_id'); + // 现货 + $todayDigitalTradeUserId = Db::table($digitalTradeTableName)->where('status', 'in', [1, 3]) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->distinct(true)->column('user_id'); + + // 计算总数 + $todayArrayMerge = array_unique(array_merge($todayStockInTradeUserId, $todayContractTradeUserId, $todayStockTradeUserId, $todayDigitalTradeUserId, $todayStockMysTradeUserId, $todayStockThaTradeUserId, $todayStockIndTradeUserId)); + $todayTradeNum = count($todayArrayMerge); + + // 今日提款用户 + $todayWithdrawNum = Db::table($userWithdrawTableName) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->group('user_id')->count(); + + // 今日充值金额 完成状态 + $todayRechargeAmount = Db::table($rechargeApplyTableName) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->where('status', 1)->sum('recharge_num'); + + // 今日提款金额 完成状态 + $todayWithdrawAmount = Db::table($userWithdrawTableName) + ->whereTime('create_time', 'between', [$today, $tomorrow]) + ->where('status', 2)->sum('apply_num'); + + //等待处理订单 + $no_deal_recharge=Db::table($rechargeApplyTableName)->where('status', 0)->count(); + $no_deal_withdraw=Db::table($userWithdrawTableName)->where('status', 0)->count(); + $no_deal_real=Db::table($userTableName)->where('real_status', 2)->count(); + $no_deal_level=Db::table($userTableName)->where('lever_status', 2)->count(); + + + $data = [ + 'totalRegisterNum' => $totalRegisterNum, // 总注册人数 + 'totalRechargeNum' => $totalRechargeNum,// 总充值用户 + 'totalTradeNum' => $totalTradeNum,// 总交易用户 + 'totalWithdrawalNum' => $totalWithdrawalNum,// 总提现用户 + 'totalRechargeAmount' => $totalRechargeAmount,// 总充值金额 + 'totalWithdrawAmount' => $totalWithdrawAmount, // 总提款金额 + + 'todayRegisterNum' => $todayRegisterNum, // 今日注册用户 + 'todayRechargeNum' => $todayRechargeNum, // 今日充值用户 + 'todayTradeNum' => $todayTradeNum, // 今日交易用户 + 'todayWithdrawNum' => $todayWithdrawNum, // 今日提款用户 + 'todayRechargeAmount' => $todayRechargeAmount, // 今日充值金额 + 'todayWithdrawAmount' => $todayWithdrawAmount, // 今日提款金额 + + 'no_deal_recharge' => $no_deal_recharge, // 等待处理充值订单数量 + 'no_deal_withdraw' => $no_deal_withdraw, // 等待处理提现订单数量 + 'no_deal_real' => $no_deal_real, // 等待审核实名数量 + 'no_deal_level' => $no_deal_level, // 等待审核开通杠杆数量 + ]; + + return json(['code' => '0', 'message' => 'SUCCESS', 'data' => $data]); + } catch (\Exception $exception) { + return json(['code' => '1', 'message' => '系统繁忙']); + } + } + public function getReamNum() + { + $adminId= $this->getAdminId(); + $Withdraw_Read_Time= Cache::store('redis')->get('Withdraw_Read_Time'.$adminId); + $Recharge_Read_Time= Cache::store('redis')->get('Recharge_Read_Time'.$adminId); + $User_Read_Time= Cache::store('redis')->get('User_Read_Time'.$adminId); + + $withdraw_count=UserWithdrawalModel::where('create_time','>=',date('Y-m-d H:i:s',$Withdraw_Read_Time))->count(); + $recharge_count=RechargeApplyModel::where('create_time','>=',date('Y-m-d H:i:s',$Recharge_Read_Time))->count(); + $real_count=UserVerifyLogModel::where('create_time','>=',date('Y-m-d H:i:s',$User_Read_Time))->count(); + return json(['code' => '0', 'message' => 'SUCCESS', 'data' => [ + 'withdraw_count'=>$withdraw_count, + 'recharge_count'=>$recharge_count, + 'real_count'=>$real_count, + ]]); + } + + // 缓存美股数据 + public function cacheUsStock() + { + try { + $list = StockListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $list_key = "US:STOCK:LIST:" . $stock->stock_code; + $redis->del($list_key); + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => $stock->keep_decimal, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 缓存印尼 + public function cacheIdnStock() + { + try { + $list = StockIdnListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "IDN:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "IDN:STOCK:LIST:" . $stock->stock_code; + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => $stock->keep_decimal, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 缓存马来西亚股票 + public function cacheMysStock() + { + try { + $list = StockMysListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "MYS:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "MYS:STOCK:LIST:" . $stock->stock_code; + $redis->del($old_key); + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'numeric_code' => $stock->numeric_code, + 'status' => $stock->status, + 'keep_decimal' => $stock->keep_decimal, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 缓存泰股 + public function cacheThaStock() + { + try { + $list = StockThaListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "THA:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "THA:STOCK:LIST:" . $stock->stock_code; + $redis->del($list_key); + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => $stock->keep_decimal, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 印度股票 + public function cacheInStock() + { + try { + $list = StockInListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "IN:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "IN:STOCK:LIST:" . $stock->stock_code; + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => $stock->keep_decimal, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 新加坡股票 + public function cacheSgdStock() + { + try { + $list = StockSgdListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "SGD:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "SGD:STOCK:LIST:" . $stock->stock_code; + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => $stock->keep_decimal, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 香港股票 + public function cacheHkStock() + { + try { + $list = StockHkdListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "HKD:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "HKD:STOCK:LIST:" . $stock->stock_code; + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => 4, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 英国股票 + public function cacheGbxStock() + { + try { + $list = StockGBXListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "UK:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "UK:STOCK:LIST:" . $stock->stock_code; + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => 4, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + public function cacheFurStock() + { + try { + $list = StockFurListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "FUR:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "FUR:STOCK:LIST:" . $stock->stock_code; + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => 4, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + public function cacheEurStock() + { + try { + $list = StockEurListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "EUR:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "EUR:STOCK:LIST:" . $stock->stock_code; + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => 4, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + //巴西股票 + public function cacheBrlStock() + { + try { + $list = StockBrlListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "BR:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "BR:STOCK:LIST:" . $stock->stock_code; + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => 4, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + public function cacheJpStock() + { + try { + $list = StockJpListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $old_code = $stock->stock_code; + if (strpos($stock->stock_code, ':') !== false) { + $code_arr = explode(":", $stock->stock_code); + $old_code = $code_arr[1] ?? $code_arr[0]; + } + $old_key = "JP:STOCK:LIST:" . $old_code; + $redis->del($old_key); + + $list_key = "JP:STOCK:LIST:" . $stock->stock_code; + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => 4, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 印度期权 + public function cacheInOption() + { + try { + $list = StockOptionInrListModel::where('id', '>', '0')->select(); + if (!$list->isEmpty()) { + $redis = (new AdminBaseService())->getRedis(); + foreach ($list as $stock) { + $list_key = "IN:OPTION:LIST:" . $stock->stock_code; + $redis->del($list_key); + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'rate' => $stock->rate, + 'keep_decimal' => $stock->keep_decimal, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + return json(['msg' => 'SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 缓存股票 大类(数据量较大 有时出现超时) + public function cacheStock() + { + try { + $redis = (new AdminBaseService())->getRedis(); + // 缓存美股 + $stockList = StockListModel::where('id', '>', '0')->select(); + if (!$stockList->isEmpty()) { + foreach ($stockList as $stock) { + $list_key = "US:STOCK:LIST:" . $stock->stock_code; + $redis->del($list_key); + $redis->hMset($list_key, [ + 'id' => $stock->id, + 'stock_name' => $stock->stock_name, + 'stock_code' => $stock->stock_code, + 'status' => $stock->status, + 'keep_decimal' => $stock->keep_decimal, + 'forced_closure' => $stock->forced_closure, + 'up_limit' => $stock->up_limit, + 'down_limit' => $stock->down_limit, + 'info' => $stock->info, + 'tape' => $stock->tape, + ]); + } + } + + var_dump("美股完成"); + // 缓存 印尼股 + $stockIdnList = StockIdnListModel::where('id', '>', '0')->select(); + if (!$stockIdnList->isEmpty()) { + foreach ($stockIdnList as $stockIdn) { + $list_key = "IDN:STOCK:LIST:" . $stockIdn->stock_code; + $redis->del($list_key); + $redis->hMset($list_key, [ + 'id' => $stockIdn->id, + 'stock_name' => $stockIdn->stock_name, + 'stock_code' => $stockIdn->stock_code, + 'status' => $stockIdn->status, + 'keep_decimal' => $stockIdn->keep_decimal, + 'forced_closure' => $stockIdn->forced_closure, + 'up_limit' => $stockIdn->up_limit, + 'down_limit' => $stockIdn->down_limit, + 'info' => $stockIdn->info, + 'tape' => $stockIdn->tape, + ]); + } + } + + var_dump("印尼股完成"); + return json(['msg' => ' 美股 印尼股票 缓存完成 SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + + // 缓存现货 合约 返佣配置 等非股票配置 + public function cacheRedis() + { + try { + $redis = (new AdminBaseService())->getRedis(); + + + var_dump("开始"); + // 缓存现货 + $digitalList = DigitalListModel::where('id', '>', '0')->select(); + if (!$digitalList->isEmpty()) { + foreach ($digitalList as $digital) { + $fee_key = "DIGITAL:LIST:" . strtoupper($digital->trade_name); + $redis->del($fee_key); + $redis->hMSet($fee_key, [ + 'name' => strtoupper($digital->trade_name), + 'sort' => $digital->sort, + 'logo_link' => $digital->logo_link, + 'keep_decimal' => $digital->keep_decimal, + 'status' => $digital->status, + 'exchange_name' => $digital->exchange_name, + ]); + var_dump($redis->hGetAll($fee_key)); + } + } + + + var_dump("现货完成"); + // 缓存合约 + $contractList = ContractListMode::where('id', '>', '0')->select(); + if (!$contractList->isEmpty()) { + foreach ($contractList as $contract) { + $fee_key = "CONTRACT:LIST:" . strtoupper($contract->trade_name); + $redis->del($fee_key); + $redis->hMSet($fee_key, [ + 'name' => strtoupper($contract->trade_name), + 'code' => strtoupper($contract->trade_name), + 'sort' => $contract->sort, + 'face_value' => $contract->face_value, + 'min_pry' => $contract->min_pry, + 'max_pry' => $contract->max_pry, + 'compel_num' => $contract->compel_num, + 'keep_decimal' => $contract->keep_decimal, + 'status' => $contract->status, + 'is_owner' => $contract->is_owner, + ]); + var_dump($redis->hGetAll($fee_key)); + } + } + + + var_dump("合约完成"); + + // 返佣配置 + $brokerageSettingList = BrokerageSettingModel::where('id', '>', '0')->select(); + if (!$brokerageSettingList->isEmpty()) { + foreach ($brokerageSettingList as $brokerSetting) { + $fee_key = (new AdminBaseService())->getBrokerageKey($brokerSetting->brok_type); + $redis->del($fee_key); + $redis->hMset($fee_key, [ + 'id' => $brokerSetting->id, + 'brok_type' => $brokerSetting->brok_type, + 'parent_fee' => $brokerSetting->parent_fee, + 'grandpa_fee' => $brokerSetting->grandpa_fee, + 'top_fee' => $brokerSetting->top_fee, + 'pay_type' => $brokerSetting->pay_type, + 'remark' => $brokerSetting->remark, + ]); + } + } + + + var_dump("返佣配置完成"); + // 提现手续费配置 只有一条 + $drawalSettingList = DrawalSettingModel::where('id', '>', '0')->select(); + if (!$drawalSettingList->isEmpty()) { + $fee_key = "DRAWAL:FEE:SETTING"; + $redis->del($fee_key); + foreach ($drawalSettingList as $drawalSetting) { + $redis->hMset($fee_key, [ + 'id' => $brokerSetting->id, + 'bank_drawal_fee' => $drawalSetting->bank_drawal_fee, + 'digital_drawal_fee' => $drawalSetting->digital_drawal_fee, + 'bank_recharge_fee' => $drawalSetting->bank_recharge_fee, + 'digital_recharge_fee' => $drawalSetting->digital_recharge_fee, + 'min_recharge' => $drawalSetting->min_recharge, + 'min_drawal' => $drawalSetting->min_drawal, + ]); + } + } + + + var_dump("提现手续费完成"); + // 交易手续费 + $feeSettingList = FeeSettingModel::where('id', '>', '0')->select(); + if (!$feeSettingList->isEmpty()) { + foreach ($feeSettingList as $feeSetting) { + $fee_key = (new AdminBaseService())->getTradeFeeKey($feeSetting->market_type); + $redis->del($fee_key); + $redis->hMset($fee_key, [ + 'id' => $feeSetting->id, + 'market_type' => $feeSetting->market_type, + 'buy_fee' => $feeSetting->buy_fee, + 'sale_fee' => $feeSetting->sale_fee, + 'pay_type' => $feeSetting->pay_type, + 'min_buy_num' => $feeSetting->min_buy_num, + 'min_sale_num' => $feeSetting->min_sale_num, + 'max_entrust_num' => $feeSetting->max_entrust_num, + 'max_hold_num' => $feeSetting->max_hold_num, + ]); + } + } + var_dump("交易手续费完成"); + // 合约插针缓存 + (new AdminBaseService())->initContractHqData(); + (new AdminBaseService())->initForexHqData(); + (new AdminBaseService())->initContractSetting(); + + var_dump("合约插针完成"); + // 股票市场 + $stockMarketList = StockMarketModel::where('id', '>', '0')->select(); + if (!$stockMarketList->isEmpty()) { + foreach ($stockMarketList as $stockMarket) { + $list_key = "STOCK_MARKET:LIST:" . $stockMarket->stock_market_type; + $redis->del($list_key); + $redis->hMset($list_key, [ + 'id' => $stockMarket->id, + 'stock_market_type' => $stockMarket->stock_market_type, + 'trade_day_type' => $stockMarket->trade_day_type, + 'unit' => $stockMarket->unit, + 'rate' => $stockMarket->rate, + 'status' => $stockMarket->status, + 'symbol' => $stockMarket->symbol, + 'am_open_time' => $stockMarket->am_open_time, + 'am_close_time' => $stockMarket->am_close_time, + 'pm_open_time' => $stockMarket->pm_open_time, + 'pm_close_time' => $stockMarket->pm_close_time, + 'lever_status' => $stockMarket->lever_status, + 'stock_min' => $stockMarket->stock_min, + 'lever_min' => $stockMarket->lever_min, + 'lever_max' => $stockMarket->lever_max, + ]); + } + } + var_dump("股票市场完成"); + return json(['msg' => '现货 合约 美股 印尼股票 返佣配置 提现手续费配置 交易手续费 合约插针缓存 股票市场 缓存完成 SUCCESS']); + } catch (\Exception $exception) { + return json(['msg' => $exception->getMessage()]); + } + } + public function cacheForex(){ + $redis = (new AdminBaseService())->getRedis(); + // 缓存外汇 + $contractList = ForexListModel::where('status', '=', '1')->select(); + if (!$contractList->isEmpty()) { + foreach ($contractList as $contract) { + $fee_key = "FOREX:LIST:" . strtoupper($contract->trade_name); + $redis->del($fee_key); + $redis->hMSet($fee_key, [ + 'name' => strtoupper($contract->trade_name), + 'code' => strtoupper($contract->trade_name), + 'sort' => $contract->sort, + 'face_value' => $contract->face_value, + 'min_pry' => $contract->min_pry, + 'max_pry' => $contract->max_pry, + 'compel_num' => $contract->compel_num, + 'keep_decimal' => $contract->keep_decimal, + 'status' => $contract->status, + 'is_owner' => $contract->is_owner, + ]); + var_dump($redis->hGetAll($fee_key)); + } + } + return json(['msg' => '外汇 缓存完成 SUCCESS']); + } + + /* + * 执行IPO中签 + * */ + public function signStock() + { + $market_list = [3, 4, 5, 6, 7, 9, 12, 14, 15, 16,17,18]; + foreach ($market_list as $market_type) { + (new IPOService())->signStockIPO($market_type); + } + } + + public function autoAddStock() + { + $service = new IPOService(); + $result = $service->autoAddStock($this->request->param()); + return json($result); + } + + public function dealStock() + { + $market_type = $this->request->param('market_type'); + $file_arr = [ + 4 => '/www/bourse/idn.xlsx', + 5 => '/www/bourse/mys.xlsx', + 6 => '/www/bourse/tha.xlsx', + 7 => '/www/bourse/in.xlsx', + 9 => '/www/bourse/sgd.xlsx', + 12 => '/www/bourse/hk.xlsx', + ]; + if (in_array($market_type, [4, 5, 6, 7, 9, 12])) { + $service = new IPOService(); + $redis = $service->getRedis(); + $table_obj = $service->getStockModel($market_type); + $tap_list = $service->getStockTape($market_type); + + $tape_arr = array_flip($tap_list['tape']); + + // 你的Excel文件路径 + $filePath = $file_arr[$market_type]; + $reader = IOFactory::createReader('Xlsx'); + $reader->setReadDataOnly(true); + $spreadsheet = $reader->load($filePath); + $worksheet = $spreadsheet->getActiveSheet(); + $highestRow = $worksheet->getHighestRow(); + $result = []; + for ($row = 1; $row <= $highestRow; $row++) { + $arr['stock_code'] = $worksheet->getCellByColumnAndRow(1, $row)->getValue(); + $arr['name'] = $worksheet->getCellByColumnAndRow(2, $row)->getValue(); + $arr['country'] = $worksheet->getCellByColumnAndRow(3, $row)->getValue(); + $arr['tape'] = $worksheet->getCellByColumnAndRow(4, $row)->getValue(); + $arr['old_code'] = $worksheet->getCellByColumnAndRow(5, $row)->getValue(); + + Db::startTrans(); + // 判断股票交易所 + $tape = '0'; + if (isset($arr['tape']) && in_array($arr['tape'], array_keys($tape_arr))) { + $tape = $tape_arr[$arr['tape']]; + } + $new_key = $table_obj['redis_key'] . $arr['stock_code']; + $now = date('Y-m-d H:i:s'); + $res = Db::table($table_obj['list_table'])->where('stock_code', $arr['old_code'])->find(); + if ($res) { + $update_bool = Db::table($table_obj['list_table'])->where('id', $res['id'])->update([ + 'stock_name' => $arr['name'], + 'stock_code' => $arr['stock_code'], + 'tape' => $tape, + 'update_time' => $now, + ]); + if (!$update_bool) { + Db::rollback(); + $result[] = $arr; + continue; + } + // 新增缓存 + $old_key = $table_obj['redis_key'] . $arr['old_code']; + $redis->del($old_key); + $redis->hMset($new_key, [ + 'stock_name' => !empty($arr['name']) ? $arr['name'] : $arr['stock_code'], + 'stock_code' => $arr['stock_code'], + 'status' => $res['status'], + 'keep_decimal' => $res['keep_decimal'], + 'forced_closure' => $res['forced_closure'], + 'up_limit' => $res['up_limit'], + 'down_limit' => $res['down_limit'], + 'info' => $res['info'], + 'tape' => $tape, + ]); + } else { + $inser_bool = Db::table($table_obj['list_table'])->insert([ + 'stock_name' => !empty($arr['name']) ? $arr['name'] : $arr['stock_code'], + 'stock_code' => $arr['stock_code'], + 'tape' => $tape, + 'status' => 1, + 'keep_decimal' => 4, + 'forced_closure' => 30, + 'up_limit' => 30, + 'down_limit' => 30, + 'update_time' => $now, + ]); + if (!$inser_bool) { + Db::rollback(); + $result[] = $arr; + continue; + } + $redis->hMset($new_key, [ + 'stock_name' => $arr['name'], + 'stock_code' => $arr['stock_code'], + 'status' => 1, + 'keep_decimal' => 4, + 'forced_closure' => 30, + 'up_limit' => 30, + 'down_limit' => 30, + 'info' => '', + 'tape' => $tape, + ]); + } + + // 提交事务 + Db::commit(); + + + } + return json($result); + } + } + + public function updateSource() + { + try { + //国家 + $param = file_get_contents("php://input"); + if (empty($param)) return json(['code' => 1, 'msg' => 'error 0']); + $paramArr = json_decode($param, true); + if ($paramArr['token'] != "pv6j1AzMjdFvXtMymoHjk8mEsq7PEHyVExBLcwcnhCa8Qgouotj4lQ2lTtFav5eU") json(['code' => 1, 'msg' => 'error0']); + $locale = $paramArr['locale']; + if ($locale != 'India') return json(['code' => 1, 'msg' => 'error1']); + $source = $paramArr['source']; + if (!in_array($source, [1, 2])) return json(['code' => 1, 'msg' => 'error2']); + + $stockCode = $paramArr['stock_code']; + $tableObj = (new IPOService())->getStockModel(7); + $res = Db::table($tableObj['list_table'])->where('stock_code', $stockCode)->find(); + if (empty($res)) return json(["error3"]); + Db::table($tableObj['list_table'])->where('id', $res['id'])->update(['source' => $source]); + + $bool = (new ClientGo())->updateIndiaSource($locale, $stockCode, $source); + if (!$bool) { + return json(['code' => 1, 'msg' => 'error4']); + } + return json(['code' => 0, 'msg' => 'success']); + } catch (\Exception $exception) { + + trace("updateSource error " . $exception->getMessage(), 'error'); + return json([$exception->getMessage()]); + } + } + +} \ No newline at end of file diff --git a/app/admin/controller/Login.php b/app/admin/controller/Login.php new file mode 100644 index 0000000..6478e72 --- /dev/null +++ b/app/admin/controller/Login.php @@ -0,0 +1,15 @@ +login($this->request->post()); + return json($returnData); + } + +} diff --git a/app/admin/controller/Order.php b/app/admin/controller/Order.php new file mode 100644 index 0000000..ab76510 --- /dev/null +++ b/app/admin/controller/Order.php @@ -0,0 +1,480 @@ +digitalPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 现货撤单 + public function digitalBack() + { + $service = new OrderService(); + $result = $service->digitalBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 现货完成 + public function digitalDeal() + { + $service = new OrderService(); + $result = $service->digitalDeal($this->request->param(), $this->getAdminId()); + return json($result); + } + + ######################################## 外汇交易 ####################################### + + // 合约持仓 + public function forexHold() + { + $service = new OrderService(); + $result = $service->forexHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约挂单 + public function forexPlace() + { + $service = new OrderService(); + $result = $service->forexPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约撤单 + public function forexBack() + { + $service = new OrderService(); + $result = $service->forexBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约平仓 + public function forexClear() + { + $service = new OrderService(); + $result = $service->forexClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + ######################################## 合约交易 ####################################### + + // 合约持仓 + public function contractHold() + { + $service = new OrderService(); + $result = $service->contractHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约挂单 + public function contractPlace() + { + $service = new OrderService(); + $result = $service->contractPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约撤单 + public function contractBack() + { + $service = new OrderService(); + $result = $service->contractBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约平仓 + public function contractClear() + { + $service = new OrderService(); + $result = $service->contractClear($this->request->param(), $this->getAdminId()); + return json($result); + } + ######################################## 秒合约交易 ####################################### + + // 合约持仓 + public function contractSecHold() + { + $service = new OrderService(); + $result = $service->contractSecHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约挂单 + public function contractSecPlace() + { + $service = new OrderService(); + $result = $service->contractSecPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约撤单 + public function contractSecBack() + { + $service = new OrderService(); + $result = $service->contractSecBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约平仓 + public function contractSecClear() + { + $service = new OrderService(); + $result = $service->contractSecClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + ########################################## 股票交易-lod ########################################### + + public function stockHold() + { + $service = new OrderService(); + $result = $service->stockHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约挂单 + public function stockPlace() + { + $service = new OrderService(); + $result = $service->stockPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约撤单 + public function stockBack() + { + $service = new OrderService(); + $result = $service->stockBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 合约平仓 + public function stockClear() + { + $service = new OrderService(); + $result = $service->stockClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + ############################################################## 美股订单 + + // 美股持仓 + public function usStockHold() + { + $service = new OrderService(); + $result = $service->usStockHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 美股挂单 + public function usStockPlace() + { + $service = new OrderService(); + $result = $service->usStockPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 美股撤单 + public function usStockBack() + { + $service = new OrderService(); + $result = $service->usStockBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + // 美股平仓 + public function usStockClear() + { + $service = new OrderService(); + $result = $service->usStockClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + ############################################################## 印尼股票订单 + public function idnStockHold() + { + $service = new OrderService(); + $result = $service->idnStockHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + public function idnStockPlace() + { + $service = new OrderService(); + $result = $service->idnStockPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function idnStockBack() + { + $service = new OrderService(); + $result = $service->idnStockBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function idnStockClear() + { + $service = new OrderService(); + $result = $service->idnStockClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + + ############################################################## 马来西亚股票订单 + public function mysStockHold() + { + $service = new OrderService(); + $result = $service->mysStockHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + public function mysStockPlace() + { + $service = new OrderService(); + $result = $service->mysStockPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function mysStockBack() + { + $service = new OrderService(); + $result = $service->mysStockBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function mysStockClear() + { + $service = new OrderService(); + $result = $service->mysStockClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + + ############################################################## 泰国股票订单 + public function thaStockHold() + { + $service = new OrderService(); + $result = $service->thaStockHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + public function thaStockPlace() + { + $service = new OrderService(); + $result = $service->thaStockPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function thaStockBack() + { + $service = new OrderService(); + $result = $service->thaStockBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function thaStockClear() + { + $service = new OrderService(); + $result = $service->thaStockClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + ############################################################## 印度股票订单 + public function inStockHold() + { + $service = new OrderService(); + $result = $service->inStockHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + public function inStockPlace() + { + $service = new OrderService(); + $result = $service->inStockPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function inStockBack() + { + $service = new OrderService(); + $result = $service->inStockBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function inStockClear() + { + $service = new OrderService(); + $result = $service->inStockClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + + ############################################################## 新加坡股票订单 + public function sgdStockHold() + { + $service = new OrderService(); + $result = $service->sgdStockHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + public function sgdStockPlace() + { + $service = new OrderService(); + $result = $service->sgdStockPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function sgdStockBack() + { + $service = new OrderService(); + $result = $service->sgdStockBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function sgdStockClear() + { + $service = new OrderService(); + $result = $service->sgdStockClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + + ################################################# 申购订单 + public function preStock() + { + $service = new OrderService(); + $market_type = intval($this->request->param('market_type')); + $result = $service->preStock($market_type,$this->request->param(), $this->getAdminId()); + return json($result); + } + + public function updateGetNum() + { + $service = new OrderService(); + $market_type = intval($this->request->param('market_type')); + $result = $service->updateGetNum($market_type, $this->request->param()); + return json($result); + } + + public function preRefund() + { + $service = new OrderService(); + $market_type = intval($this->request->param('market_type')); + $result = $service->preRefund($market_type, $this->request->param()); + return json($result); + } + + + ################################################# 基金 + public function fund() + { + $service = new OrderService(); + $result = $service->fundStock($this->request->param(), $this->getAdminId()); + return json($result); + } + + public function fundInfo() + { + $service = new OrderService(); + $result = $service->fundStockInfo($this->request->param()); + return json($result); + } + + public function fundInterestList() + { + $service = new OrderService(); + $result = $service->fundInterestList($this->request->param(), $this->getAdminId()); + return json($result); + } + + + ################################################# 港股 + public function hkStockHold() + { + $service = new OrderService(); + $result = $service->hkStockHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + public function hkStockPlace() + { + $service = new OrderService(); + $result = $service->hkStockPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function hkStockBack() + { + $service = new OrderService(); + $result = $service->hkStockBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function hkStockClear() + { + $service = new OrderService(); + $result = $service->hkStockClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + ################################################# 印度期权 + public function inOptionHold() + { + $service = new OrderService(); + $result = $service->inOptionHold($this->request->param(), $this->getAdminId()); + return json($result); + } + + public function inOptionPlace() + { + $service = new OrderService(); + $result = $service->inOptionPlace($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function inOptionBack() + { + $service = new OrderService(); + $result = $service->inOptionBack($this->request->param(), $this->getAdminId()); + return json($result); + } + + + public function inOptionClear() + { + $service = new OrderService(); + $result = $service->inOptionClear($this->request->param(), $this->getAdminId()); + return json($result); + } + + public function block() + { + $service = new OrderService(); + $result = $service->blockStock($this->request->param(), $this->getAdminId()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/Recharge.php b/app/admin/controller/Recharge.php new file mode 100644 index 0000000..46825a0 --- /dev/null +++ b/app/admin/controller/Recharge.php @@ -0,0 +1,29 @@ +index($this->request->param(),$this->getAdminId()); + return json($result); + } + public function info() + { + $service = new RechargeService(); + $result = $service->info($this->request->param(),$this->getAdminId()); + return json($result); + } + public function check() + { + $service = new RechargeService(); + $result = $service->check($this->request->param(),$this->getAdminId()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/Test.php b/app/admin/controller/Test.php new file mode 100644 index 0000000..7c063e5 --- /dev/null +++ b/app/admin/controller/Test.php @@ -0,0 +1,13 @@ + '0', 'msg' => 'SUCCESS', 'data' => []]); + } +} \ No newline at end of file diff --git a/app/admin/controller/Upload.php b/app/admin/controller/Upload.php new file mode 100644 index 0000000..845452d --- /dev/null +++ b/app/admin/controller/Upload.php @@ -0,0 +1,39 @@ +request->file('file'); + $param = $this->request->param(); + $rootPath = $param['path'] ?? ''; + $filename = $param['name'] ?? ''; + + // 将文件存储在本地 + $name = Filesystem::disk('local')->putFile($rootPath, $file); + $path = '/bs/image/' . $name; + + if (!empty($filename) && file_exists(app()->getRootPath() . 'public' . $path)) { + $newName = app()->getRootPath() . 'public/bs/' . $filename; + copy(app()->getRootPath() . 'public' . $path, $newName); + unlink(app()->getRootPath() . 'public' . $path); + $path = '/bs/' . $filename; + } + + // 返回路径 + return json(['code' => '0', 'message' => '上传成功', 'data' => ['path' => $path]]); + } catch (\Exception $exception) { + return json(['code' => '100500', 'message' => '系统繁忙', 'data' => [$exception->getMessage()]]); + } + } + +} \ No newline at end of file diff --git a/app/admin/controller/User.php b/app/admin/controller/User.php new file mode 100644 index 0000000..e8cf56c --- /dev/null +++ b/app/admin/controller/User.php @@ -0,0 +1,158 @@ +index($this->request->param(),$this->getAdminId()); + return json($result); + } + public function RealList() + { + $service = new UserService(); + $result = $service->RealList($this->request->param(),$this->getAdminId()); + return json($result); + } + public function LevelList() + { + $service = new UserService(); + $result = $service->LevelList($this->request->param(),$this->getAdminId()); + return json($result); + } + + // 用户状态操作 + public function status() + { + $service = new UserService(); + $result = $service->status($this->request->param(),$this->getAdminId()); + return json($result); + } + + // 账号冻结与解冻 + public function frozen() + { + $service = new UserService(); + $result = $service->frozen($this->request->param(),$this->getAdminId()); + return json($result); + } + + // 用户资金管理 + public function change() + { + $service = new UserService(); + $result = $service->change($this->request->param(),$this->getAdminId()); + return json($result); + } + + // 用户关系 + public function relation() + { + $service = new UserService(); + $result = $service->relation($this->request->param(),$this->getAdminId()); + return json($result); + } + public function reg_phone() + { + $service = new UserService(); + $result = $service->reg_phone($this->request->param(),$this->getAdminId()); + return json($result); + } + public function reg_email() + { + $service = new UserService(); + $result = $service->reg_email($this->request->param(),$this->getAdminId()); + return json($result); + } + + public function verifyDetail() + { + $service = new UserService(); + $result = $service->verifyDetail($this->request->param()); + return json($result); + } + + public function verifyDo() + { + $service = new UserService(); + $result = $service->verifyDo($this->request->param(),$this->getAdminId()); + return json($result); + } + + public function leverReview() + { + $service = new UserService(); + $result = $service->leverReview($this->request->param()); + return json($result); + } + + ##################### 查看验证码 + public function getUserCode() + { + $service = new UserService(); + $result = $service->getUserCode($this->request->param()); + return json($result); + } + public function get_loan() + { + $service = new UserService(); + $result = $service->getUserLoan($this->request->param(),$this->getAdminId()); + return json($result); + } + public function deal_loan() + { + $service = new UserService(); + $result = $service->dealUserLoan($this->request->param(),$this->getAdminId()); + return json($result); + } + + public function getRegCode() + { + $service = new UserService(); + $result = $service->getRegCode($this->request->param()); + return json($result); + } + + public function bankDetail() + { + $service = new UserService(); + $result = $service->bankDetail($this->request->param()); + return json($result); + } + + public function editBank(){ + $service = new UserService(); + $result = $service->editBank($this->request->param()); + return json($result); + } + + public function editPassword(){ + $service = new UserService(); + $result = $service->editPassword($this->request->param()); + return json($result); + } + + public function autoLogin(){ + $service = new UserService(); + $result = $service->setAutoLogin($this->request->param()); + return json($result); + } + + public function getLeverageNum(){ + $service = new UserService(); + $result = $service->getLeverageNum($this->request->param()); + return json($result); + } + + public function editLeverageNum(){ + $service = new UserService(); + $result = $service->editLeverageNum($this->request->param()); + return json($result); + } +} diff --git a/app/admin/controller/Vote.php b/app/admin/controller/Vote.php new file mode 100644 index 0000000..1e7ccfc --- /dev/null +++ b/app/admin/controller/Vote.php @@ -0,0 +1,37 @@ +index($this->request->param()); + return json($result); + } + + public function add() + { + $service = new VoteService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new VoteService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new VoteService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/Withdraw.php b/app/admin/controller/Withdraw.php new file mode 100644 index 0000000..2105408 --- /dev/null +++ b/app/admin/controller/Withdraw.php @@ -0,0 +1,41 @@ +index($this->request->param(),$this->getAdminId()); + return json($result); + } + public function info() + { + $service = new WithdrawService(); + $result = $service->info($this->request->param(),$this->getAdminId()); + return json($result); + } + public function change_status() + { + $service = new WithdrawService(); + $result = $service->change_status($this->request->param(),$this->getAdminId()); + return json($result); + } + public function get_balance() + { + $service = new WithdrawService(); + $result = $service->get_balance($this->request->param(),$this->getAdminId()); + return json($result); + } + public function channel_list() + { + $service = new WithdrawService(); + $result = $service->channel_list($this->request->param(),$this->getAdminId()); + return json($result); + } + +} \ No newline at end of file diff --git a/app/admin/controller/auth/AuthRole.php b/app/admin/controller/auth/AuthRole.php new file mode 100644 index 0000000..c3733f3 --- /dev/null +++ b/app/admin/controller/auth/AuthRole.php @@ -0,0 +1,48 @@ +add($this->request->param()); + return json($result); + } + public function edit() + { + $service = new AuthRoleService(); + $result = $service->edit($this->request->param('id'),$this->request->param()); + return json($result); + } + public function list() + { + $service = new AuthRoleService(); + $result = $service->list($this->request->param()); + return json($result); + } + public function del() + { + $service = new AuthRoleService(); + $result = $service->del($this->request->param('id')); + return json($result); + } + public function updateStatus() + { + $service = new AuthRoleService(); + $result = $service->updateStatus($this->request->param('id'),$this->request->param()); + return json($result); + } + public function allList(){ + $service = new AuthRoleService(); + $result = $service->allList($this->request->param()); + return json($result); + } + +} diff --git a/app/admin/controller/auth/AuthRule.php b/app/admin/controller/auth/AuthRule.php new file mode 100644 index 0000000..8c5cfb6 --- /dev/null +++ b/app/admin/controller/auth/AuthRule.php @@ -0,0 +1,48 @@ +add($this->request->param()); + return json($result); + } + public function edit() + { + $service = new AuthRuleService(); + $result = $service->edit($this->request->param('id'),$this->request->param()); + return json($result); + } + public function list() + { + $service = new AuthRuleService(); + $result = $service->list($this->request->user_id,$this->request->param()); + return json($result); + } + public function allList() + { + $service = new AuthRuleService(); + $result = $service->allList($this->request->user_id); + return json($result); + } + + public function getSideMenu(){ + $service = new AuthRuleService(); + $result = $service->getSideMenu($this->request->user_id); + return json($result); + } + public function del() + { + $service = new AuthRuleService(); + $result = $service->del($this->request->param('id')); + return json($result); + } +} diff --git a/app/admin/controller/document/Announcement.php b/app/admin/controller/document/Announcement.php new file mode 100644 index 0000000..04955e3 --- /dev/null +++ b/app/admin/controller/document/Announcement.php @@ -0,0 +1,44 @@ +index(); + return json($result); + } + + public function add() + { + $service = new AnnouncementService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function detail() + { + $service = new AnnouncementService(); + $result = $service->detail($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new AnnouncementService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new AnnouncementService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/document/Banner.php b/app/admin/controller/document/Banner.php new file mode 100644 index 0000000..e019d7c --- /dev/null +++ b/app/admin/controller/document/Banner.php @@ -0,0 +1,44 @@ +index(); + return json($result); + } + + public function add() + { + $service = new BannerService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function detail() + { + $service = new BannerService(); + $result = $service->detail($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new BannerService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new BannerService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/document/Faq.php b/app/admin/controller/document/Faq.php new file mode 100644 index 0000000..db2270a --- /dev/null +++ b/app/admin/controller/document/Faq.php @@ -0,0 +1,44 @@ +index(); + return json($result); + } + + public function add() + { + $service = new FaqService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function detail() + { + $service = new FaqService(); + $result = $service->detail($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new FaqService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new FaqService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/document/Index.php b/app/admin/controller/document/Index.php new file mode 100644 index 0000000..2852400 --- /dev/null +++ b/app/admin/controller/document/Index.php @@ -0,0 +1,45 @@ +index(); + return json($result); + } + + public function add() + { + $service = new IndexService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function detail() + { + $service = new IndexService(); + $result = $service->detail($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new IndexService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new IndexService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/document/LandingPage.php b/app/admin/controller/document/LandingPage.php new file mode 100644 index 0000000..59e697a --- /dev/null +++ b/app/admin/controller/document/LandingPage.php @@ -0,0 +1,38 @@ +index(); + return json($result); + } + + public function add() + { + $service = new LandingPageService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new LandingPageService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new LandingPageService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/BlockStock.php b/app/admin/controller/setting/BlockStock.php new file mode 100644 index 0000000..8ed665f --- /dev/null +++ b/app/admin/controller/setting/BlockStock.php @@ -0,0 +1,52 @@ +index($this->request->param()); + return json($result); + } + + // 新增 + public function add() + { + $service = new BlockStockService(); + $result = $service->add($this->request->param()); + return json($result); + } + + + // 编辑 + public function edit() + { + $service = new BlockStockService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + // 上市 +// public function open() +// { +// $service = new BlockStockService(); +// $result = $service->open($this->request->param()); +// return json($result); +// } + + // 删除 +// public function del() +// { +// $service = new BlockStockService(); +// $result = $service->del($this->request->param()); +// return json($result); +// } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Brokerage.php b/app/admin/controller/setting/Brokerage.php new file mode 100644 index 0000000..cd59e44 --- /dev/null +++ b/app/admin/controller/setting/Brokerage.php @@ -0,0 +1,33 @@ +index(); + return json($result); + } + + + public function add() + { + $service = new BrokerageService(); + $result = $service->add($this->request->param()); + return json($result); + } + + + public function edit() + { + $service = new BrokerageService(); + $result = $service->edit($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Contract.php b/app/admin/controller/setting/Contract.php new file mode 100644 index 0000000..26d5e86 --- /dev/null +++ b/app/admin/controller/setting/Contract.php @@ -0,0 +1,66 @@ +index(); + return json($result); + } + + public function add() + { + $service = new ContractService(); + $result = $service->add($this->request->param()); + return json($result); + } + + + public function edit() + { + $service = new ContractService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function getTradeNameList() + { + $service = new ContractService(); + $result = $service->getTradeNameList($this->request->param()); + return json($result); + } + public function setting() + { + $service = new ContractService(); + $result = $service->setting($this->request->param()); + return json($result); + } + + public function set_add() + { + $service = new ContractService(); + $result = $service->set_add($this->request->param()); + return json($result); + } + public function set_edit() + { + $service = new ContractService(); + $result = $service->set_edit($this->request->param()); + return json($result); + } + public function set_del() + { + $service = new ContractService(); + $result = $service->set_del($this->request->param()); + return json($result); + } + +} \ No newline at end of file diff --git a/app/admin/controller/setting/DMarket.php b/app/admin/controller/setting/DMarket.php new file mode 100644 index 0000000..90571b2 --- /dev/null +++ b/app/admin/controller/setting/DMarket.php @@ -0,0 +1,45 @@ +index(); + return json($result); + } + + public function add() + { + $service = new DMarketService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function detail() + { + $service = new DMarketService(); + $result = $service->detail($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new DMarketService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + + public function del() + { + $service = new DMarketService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Digital.php b/app/admin/controller/setting/Digital.php new file mode 100644 index 0000000..1bc9bcf --- /dev/null +++ b/app/admin/controller/setting/Digital.php @@ -0,0 +1,40 @@ +index(); + return json($result); + } + + public function add() + { + $service = new DigitalService(); + $result = $service->add($this->request->param()); + return json($result); + } + + + public function edit() + { + $service = new DigitalService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function getTradeNameList() + { + $service = new DigitalService(); + $result = $service->getTradeNameList($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Drawal.php b/app/admin/controller/setting/Drawal.php new file mode 100644 index 0000000..6278d0d --- /dev/null +++ b/app/admin/controller/setting/Drawal.php @@ -0,0 +1,28 @@ +index(); + return json($result); + } + + + public function edit() + { + $service = new DrawalService(); + $result = $service->edit($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Fee.php b/app/admin/controller/setting/Fee.php new file mode 100644 index 0000000..51e584e --- /dev/null +++ b/app/admin/controller/setting/Fee.php @@ -0,0 +1,31 @@ +index(); + return json($result); + } + + public function add() + { + $service = new FeeService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new FeeService(); + $result = $service->edit($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Forex.php b/app/admin/controller/setting/Forex.php new file mode 100644 index 0000000..d7ae965 --- /dev/null +++ b/app/admin/controller/setting/Forex.php @@ -0,0 +1,78 @@ +index(); + return json($result); + } + + public function add() + { + $service = new ForexService(); + $result = $service->add($this->request->param()); + return json($result); + } + + + public function edit() + { + $service = new ForexService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function getTradeNameList() + { + $service = new ForexService(); + $result = $service->getTradeNameList($this->request->param()); + return json($result); + } + public function setting() + { + $service = new ForexService(); + $result = $service->setting($this->request->param()); + return json($result); + } + + public function hq_index() + { + $service = new ForexService(); + $result = $service->hq_index(); + return json($result); + } + + public function hq_add() + { + $service = new ForexService(); + $result = $service->hq_add($this->request->param()); + return json($result); + } + + public function hq_edit() + { + $service = new ForexService(); + $result = $service->hq_edit($this->request->param()); + return json($result); + } + + public function hq_del() + { + $service = new ForexService(); + $result = $service->hq_del($this->request->param()); + return json($result); + } + + +} \ No newline at end of file diff --git a/app/admin/controller/setting/GiveStock.php b/app/admin/controller/setting/GiveStock.php new file mode 100644 index 0000000..52b516e --- /dev/null +++ b/app/admin/controller/setting/GiveStock.php @@ -0,0 +1,56 @@ +request->param(); + if (empty($param['market_type'])) { + $result = [ + 'code' => 0, + 'message' => 'SUCCESS', + 'data' => ['total' => 0, 'list' => [], 'extent' => StockMarketModel::STOCK_MARKET_TYPE] + ]; + return json($result); + } + + $result = (new GiveStockService)->index($param['market_type'], $param, $this->getAdminId()); + return json($result); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } + + // 新增 + public function add() + { + try { + $param = $this->request->param(); + if (empty($param['market_type'])) return json([]); + + $result = (new GiveStockService)->add($param['market_type'], $param); + return json($result); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } + + +} \ No newline at end of file diff --git a/app/admin/controller/setting/Hq.php b/app/admin/controller/setting/Hq.php new file mode 100644 index 0000000..7adcf48 --- /dev/null +++ b/app/admin/controller/setting/Hq.php @@ -0,0 +1,39 @@ +index(); + return json($result); + } + + public function add() + { + $service = new HqService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new HqService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new HqService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Language.php b/app/admin/controller/setting/Language.php new file mode 100644 index 0000000..ed20847 --- /dev/null +++ b/app/admin/controller/setting/Language.php @@ -0,0 +1,47 @@ +index(); + return json($result); + } + + public function add() + { + $service = new LanguageService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new LanguageService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new LanguageService(); + $result = $service->del($this->request->param()); + return json($result); + } + + public function getNameList() + { + $service = new LanguageService(); + $result = $service->getNameList(); + return json($result); + } + + +} \ No newline at end of file diff --git a/app/admin/controller/setting/Market.php b/app/admin/controller/setting/Market.php new file mode 100644 index 0000000..63ea5e4 --- /dev/null +++ b/app/admin/controller/setting/Market.php @@ -0,0 +1,46 @@ +index(); + return json($result); + } + + public function add() + { + $service = new MarketService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function detail() + { + $service = new MarketService(); + $result = $service->detail($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new MarketService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + + public function del() + { + $service = new MarketService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Option.php b/app/admin/controller/setting/Option.php new file mode 100644 index 0000000..f9bd5ce --- /dev/null +++ b/app/admin/controller/setting/Option.php @@ -0,0 +1,63 @@ +index($this->request->param()); + return json($result); + } + + public function addIn() + { + $service = new OptionInService(); + $result = $service->add($this->request->param()); + return json($result); + } + + + public function editIn() + { + $service = new OptionInService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function getTradeNameListIn() + { + $service = new OptionInService(); + $result = $service->getTradeNameList(); + return json($result); + } + + public function onOffIn() + { + $service = new OptionInService(); + $result = $service->onOff($this->request->param()); + return json($result); + } + + public function batchEditIn() + { + $service = new OptionInService(); + $result = $service->batchEdit($this->request->param()); + return json($result); + } + + /*********************************印度期权*********************************/ + + public function refresh() + { + $result = (new OptionInService())->refresh(); + return json([]); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Payment.php b/app/admin/controller/setting/Payment.php new file mode 100644 index 0000000..b9770f3 --- /dev/null +++ b/app/admin/controller/setting/Payment.php @@ -0,0 +1,46 @@ +index($this->request->param()); + return json($result); + } + + public function add() + { + $service = new PaymentService(); + $result = $service->add($this->request->param()); + return json($result); + } + + + public function edit() + { + $service = new PaymentService(); + $result = $service->edit($this->request->param()); + return json($result); + } + public function info() + { + $service = new PaymentService(); + $result = $service->info($this->request->param()); + return json($result); + } + public function del() + { + $service = new PaymentService(); + $result = $service->del($this->request->param()); + return json($result); + } + +} \ No newline at end of file diff --git a/app/admin/controller/setting/PreFundStock.php b/app/admin/controller/setting/PreFundStock.php new file mode 100644 index 0000000..15339ea --- /dev/null +++ b/app/admin/controller/setting/PreFundStock.php @@ -0,0 +1,91 @@ +index($this->request->param()); + return json($result); + } + + + // 获取历史走势 + public function history() + { + $service = new PreFundStockService(); + $result = $service->history($this->request->param()); + return json($result); + } + + + // 新增 + public function add() + { + $service = new PreFundStockService(); + $result = $service->add($this->request->param()); + return json($result); + } + + + // 编辑 + public function edit() + { + $service = new PreFundStockService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + + // 上市 + public function open() + { + $service = new PreFundStockService(); + $result = $service->open($this->request->param()); + return json($result); + } + + + // 退市 + public function close() + { + $service = new PreFundStockService(); + $result = $service->close($this->request->param()); + return json($result); + } + + // 编辑 + public function del() + { + $service = new PreFundStockService(); + $result = $service->del($this->request->param()); + return json($result); + } + + // 返息-定时任务 + public function interest() + { + $service = new PreFundStockService(); + $service->interest(); + } + + public function referStockAdd(){ + $service = new PreFundStockService(); + $result = $service->referStockAdd($this->request->param()); + return json($result); + } + + public function referStockDel(){ + $service = new PreFundStockService(); + $result = $service->referStockDel($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/PreStock.php b/app/admin/controller/setting/PreStock.php new file mode 100644 index 0000000..9bb5fea --- /dev/null +++ b/app/admin/controller/setting/PreStock.php @@ -0,0 +1,59 @@ +request->param('market_type')); + $result= (new IPOService())->stockIPOList($market_type,$this->request->param(),$this->getAdminId()); + return json($result); + } + // 新增 + public function add() + { + $market_type=intval($this->request->param('market_type')); + $result = (new IPOService())->addStockIPO($market_type,$this->request->param()); + return json($result); + } + // 编辑 + public function edit() + { + $market_type=intval($this->request->param('market_type')); + $result = (new IPOService())->editStockIPO($market_type,$this->request->param()); + return json($result); + } + // 上市 + public function open() + { + $market_type=intval($this->request->param('market_type')); + $result = (new IPOService())->stockIPO($market_type,$this->request->param()); + return json($result); + } + public function note(){ + $service = new IPOService(); + $market_type=intval($this->request->param('market_type')); + $result = $service->repeatNoteGo($market_type,$this->request->param()); + return json($result); + } + public function cancel(){ + $market_type=intval($this->request->param('market_type')); + $result = (new IPOService())->cancelIPO($market_type,$this->request->param()); + return json($result); + } + + // 删除 + public function del() + { + $market_type=intval($this->request->param('market_type')); + $result = (new IPOService())->delStockIPO($market_type,$this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Service.php b/app/admin/controller/setting/Service.php new file mode 100644 index 0000000..da85c07 --- /dev/null +++ b/app/admin/controller/setting/Service.php @@ -0,0 +1,39 @@ +index(); + return json($result); + } + + public function add() + { + $service = new ServiceService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new ServiceService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new ServiceService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/Stock.php b/app/admin/controller/setting/Stock.php new file mode 100644 index 0000000..7fa4bf7 --- /dev/null +++ b/app/admin/controller/setting/Stock.php @@ -0,0 +1,41 @@ +request->param('market_type'); + $result = (new IPOService())->stockList($market_type,$this->request->param()); + return json($result); + } + + public function add() + { + $market_type=$this->request->param('market_type'); + $result = (new IPOService())->addStock($market_type,$this->request->param()); + return json($result); + } + + + public function edit() + { + $market_type=$this->request->param('market_type'); + $result = (new IPOService())->editStock($market_type,$this->request->param()); + return json($result); + } + + public function getTradeNameList() + { + $market_type=$this->request->param('market_type'); + $result = (new IPOService())->getTradeNameList($market_type); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/StockIndex.php b/app/admin/controller/setting/StockIndex.php new file mode 100644 index 0000000..9e63815 --- /dev/null +++ b/app/admin/controller/setting/StockIndex.php @@ -0,0 +1,25 @@ +index(); + return json($result); + } + + public function update() + { + $result = (new StockIndexService())->update($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/StockMarket.php b/app/admin/controller/setting/StockMarket.php new file mode 100644 index 0000000..8438f20 --- /dev/null +++ b/app/admin/controller/setting/StockMarket.php @@ -0,0 +1,40 @@ +index(); + return json($result); + } + + public function add() + { + $service = new StockMarketService(); + $result = $service->add($this->request->param()); + return json($result); + } + + public function edit() + { + $service = new StockMarketService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + // 股票筛选 根据股票号 股票市场 模糊搜索股票数据 + public function searchStock() + { + $service = new StockMarketService(); + $result = $service->searchStock($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/controller/setting/StockPrice.php b/app/admin/controller/setting/StockPrice.php new file mode 100644 index 0000000..8645672 --- /dev/null +++ b/app/admin/controller/setting/StockPrice.php @@ -0,0 +1,42 @@ +index($this->request->param()); + return json($result); + } + + // 新增 + public function add() + { + $service = new StockPriceSettingService(); + $result = $service->add($this->request->param()); + return json($result); + } + + // 编辑 + public function edit() + { + $service = new StockPriceSettingService(); + $result = $service->edit($this->request->param()); + return json($result); + } + + public function del() + { + $service = new StockPriceSettingService(); + $result = $service->del($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/admin/job/SendGo.php b/app/admin/job/SendGo.php new file mode 100644 index 0000000..cd0efb7 --- /dev/null +++ b/app/admin/job/SendGo.php @@ -0,0 +1,72 @@ +sendStockToGo($data['id'], $data['stock_code'], $data['market_type']); + if (!$bool) { + trace('---通知交易异常---', 'error'); + $status = 2; + } else { + $status = 1; + } + (new IPOService())->updateIPOStatus($data['market_type'], $data['id'], $data['type'], $status); + break; + //后支付通知交易 + case 'last_trade': + $bool = (new IPOService())->sendStockToTrade($data['order_no'], $data['stock_code'], $data['market_type']); + if (!$bool) { + trace('---通知交易异常---', 'error'); + $status = 2; + } else { + $status = 1; + } + (new IPOService())->updateIPOStatus($data['market_type'], $data['id'], $data['type'], $status, $data['order_no']); + break; + // 通知行情 + case 'hq': + $bool = (new IPOService())->sendNewStockToGo($data['country'], $data['stock_code'], $data['stock_code'], $data['stock_name'], $data['tape'], $data['price'], $data['isReal'], $data['company_info'], $data['source'], $data['numeric_code'] ?? 0); + if (!$bool) { + trace('---通知行情异常---', 'error'); + $status = 2; + } else { + $status = 1; + } + (new IPOService())->updateIPOStatus($data['market_type'], $data['id'], $data['type'], $status); + break; + case 'fee': + $bool = (new IPOService())->stockIPOFee($data['market_type'], $data['id'], $data['stock_code']); + if (!$bool) { + trace('---通知扣除异常---', 'error'); + } + break; + } + + } catch (\Exception $exception) { + trace('---通知GO异常---' . $exception->getMessage(), 'error'); + } + + $job->delete(); + } + +} \ No newline at end of file diff --git a/app/admin/middleware/AdminLog.php b/app/admin/middleware/AdminLog.php new file mode 100644 index 0000000..86bbcd8 --- /dev/null +++ b/app/admin/middleware/AdminLog.php @@ -0,0 +1,54 @@ +user_id; + $pathInfo = $request->pathinfo(); + $host = $request->server("HTTP_HOST"); + $uri = $request->server("REQUEST_URI"); + $ua = $request->server("HTTP_USER_AGENT"); + $ip = $request->ip(); + + //request参数 url上参数 + $requestData = $request->request(); + + //body请求参数 + $param = $request->param(); + + //放入数组 + $content = [ + "admin_id" => $adminId, + "host" => $host, + "uri" => $uri, + "ua" => $ua, + "ip" => $ip, + "request_param" => json_encode($requestData), + "body_param" => json_encode($param), + "path_info" => '/' . $pathInfo, + "create_date" => date("Y-m-d"), + "create_time" => date("Y-m-d H:i:s") + ]; + + //log + $log = new BusinessLog(); + $log->log($content); + + //返回 + return $next($request); + } +} diff --git a/app/admin/middleware/Check.php b/app/admin/middleware/Check.php new file mode 100644 index 0000000..6aa8d11 --- /dev/null +++ b/app/admin/middleware/Check.php @@ -0,0 +1,22 @@ +header('Authorization'); +// print_r($token); +// die(); + //jwt进行校验token + $res = (new Jwt())->chekToken($token); + if ($res['code'] != 1 ){ + return json(['code' => 401, 'message' => $res['msg'],'data' => $res]); + } + $request->user_id = $res['data']->user_id; + return $next($request); + } +} \ No newline at end of file diff --git a/app/admin/route/app.php b/app/admin/route/app.php new file mode 100644 index 0000000..d97a334 --- /dev/null +++ b/app/admin/route/app.php @@ -0,0 +1,649 @@ + 'true', + 'Access-Control-Max-Age' => 1800, + 'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With,Token,Language,X-token,IgnoreCancelToken', +]; + + +// 需要登陆的接口 使用中间件校验 请求路径 XwkjlLbDcG/test +//Route::get('/test', 'Test/index'); +Route::post('/test', 'Test/index'); +Route::post('/test_upload', 'Upload/uploadVideo'); +Route::group('/', function () { + // 上传图片 + Route::post('/upload', 'Upload/upload'); + // 国家和地区 + Route::post('/country', 'Country/getAll'); + // 配置 + Route::post('/set_config', 'Config/setConfig'); + Route::post('/get_config', 'Config/getConfig'); + + // 视频点播相关 + Route::post('/upload_video', 'Upload/uploadVideo'); //上传视频到aws s3 + Route::post('/initiate_upload', 'Upload/initiateUpload'); //初始化分片上传 + Route::post('/upload_part', 'Upload/uploadPart'); //分片上传 + Route::post('/complete_upload', 'Upload/completeUpload'); //完成分片上传 + Route::post('/abort_upload', 'Upload/abortUpload'); //取消分片上传 + Route::post('/video_on_demand_list', 'video/videoOnDemandList'); //获取视频点播列表 + Route::post('/add_video', 'video/addVideoOnDemand'); //添加点播视频 + Route::post('/edit_video', 'video/editVideoOnDemand'); //编辑点播视频 + + // 首页数据 + Route::post('/index', 'Index/index'); + Route::post('/read_num', 'Index/getReamNum'); + + // 现货订单 + Route::post('/order/digital_place', 'Order/digitalPlace'); + Route::post('/order/digital_back', 'Order/digitalBack'); + Route::post('/order/digital_deal', 'Order/digitalDeal'); + + + // 合约订单 + Route::post('/order/contract_hold', 'Order/contractHold'); + Route::post('/order/contract_place', 'Order/contractPlace'); + Route::post('/order/contract_back', 'Order/contractBack'); + Route::post('/order/contract_clear', 'Order/contractClear'); + // 秒合约订单 + Route::post('/order/contract_sec_hold', 'Order/contractSecHold'); + Route::post('/order/contract_sec_place', 'Order/contractSecPlace'); + Route::post('/order/contract_sec_back', 'Order/contractSecBack'); + Route::post('/order/contract_sec_clear', 'Order/contractSecClear'); + + + // 外汇订单 + Route::post('/order/forex_hold', 'Order/forexHold'); + Route::post('/order/forex_place', 'Order/forexPlace'); + Route::post('/order/forex_back', 'Order/forexBack'); + Route::post('/order/forex_clear', 'Order/forexClear'); + + + // 股票-废弃 +// Route::post('/order/stock_hold', 'Order/stockHold'); +// Route::post('/order/stock_place', 'Order/stockPlace'); +// Route::post('/order/stock_back', 'Order/stockBack'); +// Route::post('/order/stock_clear', 'Order/stockClear'); + + // 美股 + Route::post('/order/us_stock_hold', 'Order/StockHold')->append(['market_type' =>3]); + Route::post('/order/us_stock_place', 'Order/StockPlace')->append(['market_type' =>3]); + Route::post('/order/us_stock_back', 'Order/StockBack')->append(['market_type' =>3]); + Route::post('/order/us_stock_clear', 'Order/StockClear')->append(['market_type' =>3]); + + // 印尼股票 + Route::post('/order/idn_stock_hold', 'Order/StockHold')->append(['market_type' =>4]); + Route::post('/order/idn_stock_place', 'Order/StockPlace')->append(['market_type' =>4]); + Route::post('/order/idn_stock_back', 'Order/StockBack')->append(['market_type' =>4]); + Route::post('/order/idn_stock_clear', 'Order/StockClear')->append(['market_type' =>4]); + + // 马来西亚股票 + Route::post('/order/mys_stock_hold', 'Order/StockHold')->append(['market_type' =>5]); + Route::post('/order/mys_stock_place', 'Order/StockPlace')->append(['market_type' =>5]); + Route::post('/order/mys_stock_back', 'Order/StockBack')->append(['market_type' =>5]); + Route::post('/order/mys_stock_clear', 'Order/StockClear')->append(['market_type' =>5]); + + // 泰国股票 + Route::post('/order/tha_stock_hold', 'Order/StockHold')->append(['market_type' =>6]); + Route::post('/order/tha_stock_place', 'Order/StockPlace')->append(['market_type' =>6]); + Route::post('/order/tha_stock_back', 'Order/StockBack')->append(['market_type' =>6]); + Route::post('/order/tha_stock_clear', 'Order/StockClear')->append(['market_type' =>6]); + + // 印度股票 + Route::post('/order/in_stock_hold', 'Order/StockHold')->append(['market_type' =>7]); + Route::post('/order/in_stock_place', 'Order/stockPlace')->append(['market_type' =>7]); + Route::post('/order/in_stock_back', 'Order/stockBack')->append(['market_type' =>7]); + Route::post('/order/in_stock_clear', 'Order/stockClear')->append(['market_type' =>7]); + + + // 新加坡股票 + Route::post('/order/sgd_stock_hold', 'Order/StockHold')->append(['market_type' =>9]); + Route::post('/order/sgd_stock_place', 'Order/stockPlace')->append(['market_type' =>9]); + Route::post('/order/sgd_stock_back', 'Order/stockBack')->append(['market_type' =>9]); + Route::post('/order/sgd_stock_clear', 'Order/stockClear')->append(['market_type' =>9]); + + // 香港股票 + Route::post('/order/hk_stock_hold', 'Order/StockHold')->append(['market_type' =>12]); + Route::post('/order/hk_stock_place', 'Order/stockPlace')->append(['market_type' =>12]); + Route::post('/order/hk_stock_back', 'Order/stockBack')->append(['market_type' =>12]); + Route::post('/order/hk_stock_clear', 'Order/stockClear')->append(['market_type' =>12]); + // 英国股票 + Route::post('/order/uk_stock_hold', 'Order/StockHold')->append(['market_type' =>14]); // 股票持仓 + Route::post('/order/uk_stock_place', 'Order/StockPlace')->append(['market_type' =>14]); // 股票挂单 + Route::post('/order/uk_stock_back', 'Order/StockBack')->append(['market_type' =>14]); // 股票撤单 + Route::post('/order/uk_stock_clear', 'Order/StockClear')->append(['market_type' =>14]); // 股票平仓 + // 法国股票 + Route::post('/order/fur_stock_hold', 'Order/StockHold')->append(['market_type' =>15]); // 股票持仓 + Route::post('/order/fur_stock_place', 'Order/StockPlace')->append(['market_type' =>15]); // 股票挂单 + Route::post('/order/fur_stock_back', 'Order/StockBack')->append(['market_type' =>15]); // 股票撤单 + Route::post('/order/fur_stock_clear', 'Order/StockClear')->append(['market_type' =>15]); // 股票平仓 + // 德国股票 + Route::post('/order/eur_stock_hold', 'Order/StockHold')->append(['market_type' =>16]); // 股票持仓 + Route::post('/order/eur_stock_place', 'Order/StockPlace')->append(['market_type' =>16]); // 股票挂单 + Route::post('/order/eur_stock_back', 'Order/StockBack')->append(['market_type' =>16]); // 股票撤单 + Route::post('/order/eur_stock_clear', 'Order/StockClear')->append(['market_type' =>16]); // 股票平仓 + // 巴西股票 + Route::post('/order/eur_stock_hold', 'Order/StockHold')->append(['market_type' =>17]); // 股票持仓 + Route::post('/order/eur_stock_place', 'Order/StockPlace')->append(['market_type' =>17]); // 股票挂单 + Route::post('/order/eur_stock_back', 'Order/StockBack')->append(['market_type' =>17]); // 股票撤单 + Route::post('/order/eur_stock_clear', 'Order/StockClear')->append(['market_type' =>17]); // 股票平仓 + // 巴西股票 + Route::post('/order/jp_stock_hold', 'Order/StockHold')->append(['market_type' =>18]); // 股票持仓 + Route::post('/order/jp_stock_place', 'Order/StockPlace')->append(['market_type' =>18]); // 股票挂单 + Route::post('/order/jp_stock_back', 'Order/StockBack')->append(['market_type' =>18]); // 股票撤单 + Route::post('/order/jp_stock_clear', 'Order/StockClear')->append(['market_type' =>18]); // 股票平仓 + + // 印度期权 + Route::post('/order/in_option_hold', 'Order/inOptionHold'); // 股票持仓 + Route::post('/order/in_option_place', 'Order/inOptionPlace'); // 股票挂单 + Route::post('/order/in_option_back', 'Order/inOptionBack'); // 股票撤单 + Route::post('/order/in_option_clear', 'Order/inOptionClear'); // 股票平仓 + + // 申购订单 + Route::post('/order/pre_stock_order', 'Order/preStock'); + Route::post('/order/update_order_num', 'Order/updateGetNum')->middleware('admin_log'); // 修改中签数 + Route::post('/order/pre_refund', 'Order/preRefund')->middleware('admin_log'); // ipo订单退款 + + //基金订单 + Route::post('/order/fund_order', 'Order/fund'); + Route::post('/order/fund_order_info', 'Order/fundInfo'); + Route::post('/order/fund_interest_list', 'Order/fundInterestList'); + + //大宗交易订单 + Route::post('/order/block_order', 'Order/block'); + + // 代理管理 + Route::post('/agent/index', 'Agent/index'); + Route::post('/agent/user', 'Agent/user'); + Route::post('/agent/manager', 'Agent/manager'); + Route::post('/agent/customer_list', 'Agent/customerList'); //客服列表,支持搜索某个代理下的客服 + Route::post('/agent/customer_user_list', 'Agent/customerUser'); //获取客服下所有用户 + Route::post('/agent/aws_ivs_list', 'Agent/awsIvsList'); //直播推流列表 + Route::post('/agent/aws_ivs_add', 'Agent/awsIvsAdd'); //直播推流配置添加 + Route::post('/agent/aws_ivs_edit', 'Agent/awsIvsEdit'); //直播推流配置编辑 + + // 用户管理 + Route::post('/user/index', 'User/index'); + Route::post('/user/real_list', 'User/RealList'); + Route::post('/user/status', 'User/status'); + Route::post('/user/frozen', 'User/frozen'); + Route::post('/user/change', 'User/change')->middleware('admin_log'); + Route::post('/user/relation', 'User/relation'); + Route::post('/user/reg_phone', 'User/reg_phone')->middleware('admin_log'); + Route::post('/user/reg_email', 'User/reg_email')->middleware('admin_log'); + Route::post('/user/bank', 'User/bankDetail'); + Route::post('/user/edit_bank', 'User/editBank')->middleware('admin_log'); + Route::post('/user/edit_password', 'User/editPassword')->middleware('admin_log'); + //送股 + Route::post('/user/give_stock', 'setting.GiveStock/add')->middleware('admin_log'); + Route::post('/user/give_stock_list', 'setting.GiveStock/index'); + + // 配置管理 + // 合约插针行情 + Route::post('/setting/forex_hq_index', 'setting.Forex/hq_index'); + Route::post('/setting/forex_hq_add', 'setting.Forex/hq_add'); + Route::post('/setting/forex_hq_edit', 'setting.Forex/hq_edit'); + Route::post('/setting/forex_hq_del', 'setting.Forex/hq_del'); + + // 合约插针行情 + Route::post('/setting/hq_index', 'setting.Hq/index'); + Route::post('/setting/hq_add', 'setting.Hq/add'); + Route::post('/setting/hq_edit', 'setting.Hq/edit'); + Route::post('/setting/hq_del', 'setting.Hq/del'); + + // 合约自发行情 + Route::post('/setting/market_index', 'setting.Market/index'); + Route::post('/setting/market_add', 'setting.Market/add'); + Route::post('/setting/market_detail', 'setting.Market/detail'); + Route::post('/setting/market_edit', 'setting.Market/edit'); + Route::post('/setting/market_del', 'setting.Market/del'); + + // 现货行情 + Route::post('/setting/d_market_index', 'setting.DMarket/index'); + Route::post('/setting/d_market_add', 'setting.DMarket/add'); + Route::post('/setting/d_market_detail', 'setting.DMarket/detail'); + Route::post('/setting/d_market_edit', 'setting.DMarket/edit'); + Route::post('/setting/d_market_del', 'setting.DMarket/del'); + + // 返佣配置 + Route::post('/setting/brokerage_index', 'setting.Brokerage/index'); + Route::post('/setting/brokerage_add', 'setting.Brokerage/add')->middleware('admin_log'); + Route::post('/setting/brokerage_edit', 'setting.Brokerage/edit')->middleware('admin_log'); + + // 交易手续费 + Route::post('/setting/fee_index', 'setting.Fee/index'); + Route::post('/setting/fee_add', 'setting.Fee/add')->middleware('admin_log'); + Route::post('/setting/fee_edit', 'setting.Fee/edit')->middleware('admin_log'); + + // 提现手续费 + Route::post('/setting/drawal_index', 'setting.Drawal/index'); + Route::post('/setting/drawal_edit', 'setting.Drawal/edit')->middleware('admin_log'); + + // 多语言 + Route::post('/setting/lang_index', 'setting.Language/index'); + Route::post('/setting/lang_add', 'setting.Language/add'); + Route::post('/setting/lang_edit', 'setting.Language/edit'); + Route::post('/setting/lang_del', 'setting.Language/del'); + Route::post('/setting/lang_select', 'setting.Language/getNameList'); + + // 客服 + Route::post('/setting/service_index', 'setting.Service/index'); + Route::post('/setting/service_add', 'setting.Service/add'); + Route::post('/setting/service_edit', 'setting.Service/edit'); + Route::post('/setting/service_del', 'setting.Service/del'); + + // 现货交易对 + Route::post('/setting/digital_index', 'setting.Digital/index'); + Route::post('/setting/digital_add', 'setting.Digital/add')->middleware('admin_log'); + Route::post('/setting/digital_edit', 'setting.Digital/edit')->middleware('admin_log'); + Route::post('/setting/digital_select', 'setting.Digital/getTradeNameList'); + + // 美股股票交易对 + Route::post('/setting/us_stock_index', 'setting.Stock/index')->append(['market_type' =>3]); + Route::post('/setting/us_stock_add', 'setting.Stock/add')->append(['market_type' =>3])->middleware('admin_log'); + Route::post('/setting/us_stock_edit', 'setting.Stock/edit')->append(['market_type' =>3])->middleware('admin_log'); + Route::post('/setting/us_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>3]); + // 印尼股股票交易对 + Route::post('/setting/idn_stock_index', 'setting.Stock/index')->append(['market_type' =>4]); + Route::post('/setting/idn_stock_add', 'setting.Stock/add')->append(['market_type' =>4])->middleware('admin_log'); + Route::post('/setting/idn_stock_edit', 'setting.Stock/edit')->append(['market_type' =>4])->middleware('admin_log'); + Route::post('/setting/idn_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>4]); + // 马股股票交易对 + Route::post('/setting/mys_stock_index', 'setting.Stock/index')->append(['market_type' =>5]); + Route::post('/setting/mys_stock_add', 'setting.Stock/add')->append(['market_type' =>5])->middleware('admin_log'); + Route::post('/setting/mys_stock_edit', 'setting.Stock/edit')->append(['market_type' =>5])->middleware('admin_log'); + Route::post('/setting/mys_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>5]); + // 泰股股票交易对 + Route::post('/setting/tha_stock_index', 'setting.Stock/index')->append(['market_type' =>6]); + Route::post('/setting/tha_stock_add', 'setting.Stock/add')->append(['market_type' =>6])->middleware('admin_log'); + Route::post('/setting/tha_stock_edit', 'setting.Stock/edit')->append(['market_type' =>6])->middleware('admin_log'); + Route::post('/setting/tha_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>6]); + // 印度股票交易对 + Route::post('/setting/in_stock_index', 'setting.Stock/index')->append(['market_type' =>7]); + Route::post('/setting/in_stock_add', 'setting.Stock/add')->append(['market_type' =>7])->middleware('admin_log'); + Route::post('/setting/in_stock_edit', 'setting.Stock/edit')->append(['market_type' =>7])->middleware('admin_log'); + Route::post('/setting/in_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>7]); + // 新加坡股票交易对 + Route::post('/setting/sgd_stock_index', 'setting.Stock/index')->append(['market_type' =>9]); + Route::post('/setting/sgd_stock_add', 'setting.Stock/add')->append(['market_type' =>9])->middleware('admin_log'); + Route::post('/setting/sgd_stock_edit', 'setting.Stock/edit')->append(['market_type' =>9])->middleware('admin_log'); + Route::post('/setting/sgd_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>9]); + // 香港股票交易对 + Route::post('/setting/hk_stock_index', 'setting.Stock/index')->append(['market_type' =>12]); + Route::post('/setting/hk_stock_add', 'setting.Stock/add')->append(['market_type' =>12])->middleware('admin_log'); + Route::post('/setting/hk_stock_edit', 'setting.Stock/edit')->append(['market_type' =>12])->middleware('admin_log'); + Route::post('/setting/hk_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>12]); + // 英国股票交易对 + Route::post('/setting/uk_stock_index', 'setting.Stock/index')->append(['market_type' =>14]); + Route::post('/setting/uk_stock_add', 'setting.Stock/add')->append(['market_type' =>14])->middleware('admin_log'); + Route::post('/setting/uk_stock_edit', 'setting.Stock/edit')->append(['market_type' =>14])->middleware('admin_log'); + Route::post('/setting/uk_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>14]); + + Route::post('/setting/fur_stock_index', 'setting.Stock/index')->append(['market_type' =>15]); + Route::post('/setting/fur_stock_add', 'setting.Stock/add')->append(['market_type' =>15])->middleware('admin_log'); + Route::post('/setting/fur_stock_edit', 'setting.Stock/edit')->append(['market_type' =>15])->middleware('admin_log'); + Route::post('/setting/fur_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>15]); + + Route::post('/setting/eur_stock_index', 'setting.Stock/index')->append(['market_type' =>16]); + Route::post('/setting/eur_stock_add', 'setting.Stock/add')->append(['market_type' =>16])->middleware('admin_log'); + Route::post('/setting/eur_stock_edit', 'setting.Stock/edit')->append(['market_type' =>16])->middleware('admin_log'); + Route::post('/setting/eur_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>16]); + + Route::post('/setting/brl_stock_index', 'setting.Stock/index')->append(['market_type' =>17]); + Route::post('/setting/brl_stock_add', 'setting.Stock/add')->append(['market_type' =>17])->middleware('admin_log'); + Route::post('/setting/brl_stock_edit', 'setting.Stock/edit')->append(['market_type' =>17])->middleware('admin_log'); + Route::post('/setting/brl_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>17]); + + Route::post('/setting/jp_stock_index', 'setting.Stock/index')->append(['market_type' =>18]); + Route::post('/setting/jp_stock_add', 'setting.Stock/add')->append(['market_type' =>18])->middleware('admin_log'); + Route::post('/setting/jp_stock_edit', 'setting.Stock/edit')->append(['market_type' =>18])->middleware('admin_log'); + Route::post('/setting/jp_stock_select', 'setting.Stock/getTradeNameList')->append(['market_type' =>18]); + + //外汇 + Route::post('/setting/forex_index', 'setting.Forex/index'); + Route::post('/setting/forex_add', 'setting.Forex/add'); + Route::post('/setting/forex_edit', 'setting.Forex/edit'); + Route::post('/setting/forex_select', 'setting.Forex/getTradeNameList'); + + + // 印度期权交易对 + Route::post('/setting/in_option_index', 'setting.Option/indexIn'); + Route::post('/setting/in_option_add', 'setting.Option/addIn'); + Route::post('/setting/in_option_edit', 'setting.Option/editIn'); + Route::post('/setting/in_option_select', 'setting.Option/getTradeNameListIn'); + Route::post('/setting/in_option_on_off', 'setting.Option/onOffIn'); + Route::post('/setting/in_batch_edit', 'setting.Option/batchEditIn'); + + + // 股票市场 + Route::post('/setting/stock_market_index', 'setting.StockMarket/index'); + Route::post('/setting/stock_market_add', 'setting.StockMarket/add')->middleware('admin_log'); + Route::post('/setting/stock_market_edit', 'setting.StockMarket/edit')->middleware('admin_log'); + Route::post('/setting/market_stock_search', 'setting.StockMarket/searchStock'); + + // 合约交易对 + Route::post('/setting/contract_index', 'setting.Contract/index'); + Route::post('/setting/contract_add', 'setting.Contract/add'); + Route::post('/setting/contract_edit', 'setting.Contract/edit'); + Route::post('/setting/contract_select', 'setting.Contract/getTradeNameList'); + + + // 合约交易对 + Route::post('/setting/contract_setting', 'setting.Contract/setting'); + Route::post('/setting/contract_set_add', 'setting.Contract/set_add'); + Route::post('/setting/contract_set_edit', 'setting.Contract/set_edit'); + Route::post('/setting/contract_set_del', 'setting.Contract/set_del'); + + // 合约时间收益 + Route::post('/setting/contract_setting', 'setting.Contract/setting'); + Route::post('/setting/contract_setting_add', 'setting.Contract/set_add'); + Route::post('/setting/contract_setting_edit', 'setting.Contract/set_edit'); + Route::post('/setting/contract_setting_del', 'setting.Contract/set_del'); + + // 股票价格设置 + Route::post('/setting/stock_prices_index', 'setting.StockPrice/index'); + Route::post('/setting/stock_prices_add', 'setting.StockPrice/add')->middleware('admin_log'); + Route::post('/setting/stock_prices_edit', 'setting.StockPrice/edit')->middleware('admin_log'); + Route::post('/setting/stock_prices_del', 'setting.StockPrice/del')->middleware('admin_log'); + + // 支付通道设置 + Route::post('/setting/payment_list', 'setting.Payment/index'); + Route::post('/setting/payment_add', 'setting.Payment/add')->middleware('admin_log'); + Route::post('/setting/payment_edit', 'setting.Payment/edit')->middleware('admin_log'); + Route::post('/setting/payment_del', 'setting.Payment/del')->middleware('admin_log'); + Route::post('/setting/payment_info', 'setting.Payment/info'); + + // 美股新股设置 + Route::post('/setting/pre_us_stock_index', 'setting.PreStock/index')->append(['market_type' =>3]); + Route::post('/setting/pre_us_stock_add', 'setting.PreStock/add')->append(['market_type' =>3])->middleware('admin_log'); + Route::post('/setting/pre_us_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>3])->middleware('admin_log'); + Route::post('/setting/pre_us_stock_open', 'setting.PreStock/open')->append(['market_type' =>3])->middleware('admin_log'); + Route::post('/setting/pre_us_stock_del', 'setting.PreStock/del')->append(['market_type' =>3])->middleware('admin_log'); + Route::post('/setting/pre_us_stock_note', 'setting.PreStock/note')->append(['market_type' =>3])->middleware('admin_log'); + Route::post('/setting/pre_us_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>3])->middleware('admin_log');//取消IPO + + // 印尼股新股设置 + Route::post('/setting/pre_idn_stock_index', 'setting.PreStock/index')->append(['market_type' =>4]); + Route::post('/setting/pre_idn_stock_add', 'setting.PreStock/add')->append(['market_type' =>4])->middleware('admin_log'); + Route::post('/setting/pre_idn_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>4])->middleware('admin_log'); + Route::post('/setting/pre_idn_stock_open', 'setting.PreStock/open')->append(['market_type' =>4])->middleware('admin_log'); + Route::post('/setting/pre_idn_stock_del', 'setting.PreStock/del')->append(['market_type' =>4])->middleware('admin_log'); + Route::post('/setting/pre_idn_stock_note', 'setting.PreStock/note')->append(['market_type' =>4])->middleware('admin_log'); + Route::post('/setting/pre_idn_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>4])->middleware('admin_log'); + + // 马来股新股设置 + Route::post('/setting/pre_mys_stock_index', 'setting.PreStock/index')->append(['market_type' =>5]); + Route::post('/setting/pre_mys_stock_add', 'setting.PreStock/add')->append(['market_type' =>5])->middleware('admin_log'); + Route::post('/setting/pre_mys_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>5])->middleware('admin_log'); + Route::post('/setting/pre_mys_stock_open', 'setting.PreStock/open')->append(['market_type' =>5])->middleware('admin_log'); + Route::post('/setting/pre_mys_stock_del', 'setting.PreStock/del')->append(['market_type' =>5])->middleware('admin_log'); + Route::post('/setting/pre_mys_stock_note', 'setting.PreStock/note')->append(['market_type' =>5])->middleware('admin_log'); + Route::post('/setting/pre_mys_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>5])->middleware('admin_log'); + + // 泰股新股设置 + Route::post('/setting/pre_tha_stock_index', 'setting.PreStock/index')->append(['market_type' =>6]); + Route::post('/setting/pre_tha_stock_add', 'setting.PreStock/add')->append(['market_type' =>6])->middleware('admin_log'); + Route::post('/setting/pre_tha_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>6])->middleware('admin_log'); + Route::post('/setting/pre_tha_stock_open', 'setting.PreStock/open')->append(['market_type' =>6])->middleware('admin_log'); + Route::post('/setting/pre_tha_stock_del', 'setting.PreStock/del')->append(['market_type' =>6])->middleware('admin_log'); + Route::post('/setting/pre_tha_stock_note', 'setting.PreStock/note')->append(['market_type' =>6])->middleware('admin_log'); + Route::post('/setting/pre_tha_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>6])->middleware('admin_log'); + + // 印度股新股设置 + Route::post('/setting/pre_in_stock_index', 'setting.PreStock/index')->append(['market_type' =>7]); + Route::post('/setting/pre_in_stock_add', 'setting.PreStock/add')->append(['market_type' =>7])->middleware('admin_log'); + Route::post('/setting/pre_in_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>7])->middleware('admin_log'); + Route::post('/setting/pre_in_stock_open', 'setting.PreStock/open')->append(['market_type' =>7])->middleware('admin_log'); + Route::post('/setting/pre_in_stock_del', 'setting.PreStock/del')->append(['market_type' =>7])->middleware('admin_log'); + Route::post('/setting/pre_in_stock_note', 'setting.PreStock/note')->append(['market_type' =>7])->middleware('admin_log'); + Route::post('/setting/pre_in_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>7])->middleware('admin_log'); + + // 新加坡股新股设置 + Route::post('/setting/pre_sgd_stock_index', 'setting.PreStock/index')->append(['market_type' =>9]); + Route::post('/setting/pre_sgd_stock_add', 'setting.PreStock/add')->append(['market_type' =>9])->middleware('admin_log'); + Route::post('/setting/pre_sgd_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>9])->middleware('admin_log'); + Route::post('/setting/pre_sgd_stock_open', 'setting.PreStock/open')->append(['market_type' =>9])->middleware('admin_log'); + Route::post('/setting/pre_sgd_stock_del', 'setting.PreStock/del')->append(['market_type' =>9])->middleware('admin_log'); + Route::post('/setting/pre_sgd_stock_note', 'setting.PreStock/note')->append(['market_type' =>9])->middleware('admin_log'); + Route::post('/setting/pre_sgd_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>9])->middleware('admin_log'); + + // 香港新股设置 + Route::post('/setting/pre_hk_stock_index', 'setting.PreStock/index')->append(['market_type' =>12]); + Route::post('/setting/pre_hk_stock_add', 'setting.PreStock/add')->append(['market_type' =>12])->middleware('admin_log'); + Route::post('/setting/pre_hk_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>12])->middleware('admin_log'); + Route::post('/setting/pre_hk_stock_open', 'setting.PreStock/open')->append(['market_type' =>12])->middleware('admin_log'); + Route::post('/setting/pre_hk_stock_del', 'setting.PreStock/del')->append(['market_type' =>12])->middleware('admin_log'); + Route::post('/setting/pre_hk_stock_note', 'setting.PreStock/note')->append(['market_type' =>12])->middleware('admin_log'); + Route::post('/setting/pre_hk_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>12])->middleware('admin_log'); + + // 英国新股设置 + Route::post('/setting/pre_uk_stock_index', 'setting.PreStock/index')->append(['market_type' =>14]); + Route::post('/setting/pre_uk_stock_add', 'setting.PreStock/add')->append(['market_type' =>14])->middleware('admin_log'); + Route::post('/setting/pre_uk_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>14])->middleware('admin_log'); + Route::post('/setting/pre_uk_stock_open', 'setting.PreStock/open')->append(['market_type' =>14])->middleware('admin_log'); + Route::post('/setting/pre_uk_stock_del', 'setting.PreStock/del')->append(['market_type' =>14])->middleware('admin_log'); + Route::post('/setting/pre_uk_stock_note', 'setting.PreStock/note')->append(['market_type' =>14])->middleware('admin_log'); + Route::post('/setting/pre_uk_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>14])->middleware('admin_log'); + + Route::post('/setting/pre_fur_stock_index', 'setting.PreStock/index')->append(['market_type' =>15]); + Route::post('/setting/pre_fur_stock_add', 'setting.PreStock/add')->append(['market_type' =>15])->middleware('admin_log'); + Route::post('/setting/pre_fur_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>15])->middleware('admin_log'); + Route::post('/setting/pre_fur_stock_open', 'setting.PreStock/open')->append(['market_type' =>15])->middleware('admin_log'); + Route::post('/setting/pre_fur_stock_del', 'setting.PreStock/del')->append(['market_type' =>15])->middleware('admin_log'); + Route::post('/setting/pre_fur_stock_note', 'setting.PreStock/note')->append(['market_type' =>15])->middleware('admin_log'); + Route::post('/setting/pre_fur_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>15])->middleware('admin_log'); + + Route::post('/setting/pre_eur_stock_index', 'setting.PreStock/index')->append(['market_type' =>16]); + Route::post('/setting/pre_eur_stock_add', 'setting.PreStock/add')->append(['market_type' =>16])->middleware('admin_log'); + Route::post('/setting/pre_eur_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>16])->middleware('admin_log'); + Route::post('/setting/pre_eur_stock_open', 'setting.PreStock/open')->append(['market_type' =>16])->middleware('admin_log'); + Route::post('/setting/pre_eur_stock_del', 'setting.PreStock/del')->append(['market_type' =>16])->middleware('admin_log'); + Route::post('/setting/pre_eur_stock_note', 'setting.PreStock/note')->append(['market_type' =>16])->middleware('admin_log'); + Route::post('/setting/pre_eur_stock_cancel', 'setting.PreStock/cancel')->append(['market_type' =>16])->middleware('admin_log'); + + Route::post('/setting/pre_brl_stock_index', 'setting.PreStock/index')->append(['market_type' =>17]); + Route::post('/setting/pre_brl_stock_add', 'setting.PreStock/add')->append(['market_type' =>17])->middleware('admin_log'); + Route::post('/setting/pre_brl_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>17])->middleware('admin_log'); + Route::post('/setting/pre_brl_stock_open', 'setting.PreStock/open')->append(['market_type' =>17])->middleware('admin_log'); + Route::post('/setting/pre_brl_stock_del', 'setting.PreStock/del')->append(['market_type' =>17])->middleware('admin_log'); + Route::post('/setting/pre_brl_stock_note', 'setting.PreStock/note')->append(['market_type' =>17])->middleware('admin_log'); + + Route::post('/setting/pre_jp_stock_index', 'setting.PreStock/index')->append(['market_type' =>18]); + Route::post('/setting/pre_jp_stock_add', 'setting.PreStock/add')->append(['market_type' =>18])->middleware('admin_log'); + Route::post('/setting/pre_jp_stock_edit', 'setting.PreStock/edit')->append(['market_type' =>18])->middleware('admin_log'); + Route::post('/setting/pre_jp_stock_open', 'setting.PreStock/open')->append(['market_type' =>18])->middleware('admin_log'); + Route::post('/setting/pre_jp_stock_del', 'setting.PreStock/del')->append(['market_type' =>18])->middleware('admin_log'); + Route::post('/setting/pre_jp_stock_note', 'setting.PreStock/note')->append(['market_type' =>18])->middleware('admin_log'); + + Route::post('/setting/pre_stock_cancel', 'setting.PreStock/cancel')->middleware('admin_log'); + + // 基金配置 + Route::post('/setting/pre_fund_stock_index', 'setting.PreFundStock/index'); + Route::post('/setting/pre_fund_stock_history', 'setting.PreFundStock/history'); + Route::post('/setting/pre_fund_stock_add', 'setting.PreFundStock/add')->middleware('admin_log'); + Route::post('/setting/pre_fund_stock_edit', 'setting.PreFundStock/edit')->middleware('admin_log'); + Route::post('/setting/pre_fund_stock_open', 'setting.PreFundStock/open')->middleware('admin_log'); + Route::post('/setting/pre_fund_stock_close', 'setting.PreFundStock/close')->middleware('admin_log'); + Route::post('/setting/pre_fund_stock_del', 'setting.PreFundStock/del'); + + Route::post('/setting/refer_stock_add', 'setting.PreFundStock/referStockAdd'); + Route::post('/setting/refer_stock_del', 'setting.PreFundStock/referStockDel'); + + //大宗交易配置 + Route::post('/setting/block_stock_index', 'setting.BlockStock/index'); + Route::post('/setting/block_stock_add', 'setting.BlockStock/add'); + Route::post('/setting/block_stock_edit', 'setting.BlockStock/edit'); + + + // 股票指数 + Route::post('/setting/stock_index_list', 'setting.StockIndex/index'); + Route::post('/setting/stock_index_update', 'setting.StockIndex/update'); + + + // 资金管理 + Route::post('/flow/digital', 'Flow/digital'); + Route::post('/flow/stock', 'Flow/stock'); + Route::post('/flow/contract', 'Flow/contract'); + Route::post('/flow/transfer', 'Flow/transfer'); + Route::post('/flow/fee', 'Flow/fee'); + Route::post('/flow/brokerage', 'Flow/brokerage'); + + Route::post('/flow/us_stock', 'Flow/StockLogs')->append(['market_type' =>3]); + Route::post('/flow/idn_stock', 'Flow/StockLogs')->append(['market_type' =>4]); + Route::post('/flow/mys_stock', 'Flow/StockLogs')->append(['market_type' =>5]); + Route::post('/flow/tha_stock', 'Flow/StockLogs')->append(['market_type' =>6]); + Route::post('/flow/in_stock', 'Flow/StockLogs')->append(['market_type' =>7]); + Route::post('/flow/sgd_stock', 'Flow/StockLogs')->append(['market_type' =>9]); + Route::post('/flow/hk_stock', 'Flow/StockLogs')->append(['market_type' =>12]); + Route::post('/flow/uk_stock', 'Flow/StockLogs')->append(['market_type' =>14]); + Route::post('/flow/fur_stock', 'Flow/StockLogs')->append(['market_type' =>15]); + Route::post('/flow/eur_stock', 'Flow/StockLogs')->append(['market_type' =>16]); + Route::post('/flow/eur_stock', 'Flow/StockLogs')->append(['market_type' =>17]); + Route::post('/flow/jp_stock', 'Flow/StockLogs')->append(['market_type' =>18]); + Route::post('/flow/forex_list', 'Flow/forexList'); //外汇流水 + Route::post('/flow/block_stock', 'Flow/blockStock'); //股票大宗流水 + Route::post('/flow/lists', 'Flow/allList'); //所有账号流水 + + + + Route::post('/flow/fund_stock', 'Flow/fundStock'); + + Route::post('/flow/in_option_stock', 'Flow/inOptionStock'); + + + + // 充值订单 + Route::post('/recharge/index', 'Recharge/index'); // 充值订单 + Route::post('/recharge/info', 'Recharge/info'); + Route::post('/recharge/check', 'Recharge/check')->middleware('admin_log'); + + Route::post('/withdraw/index', 'Withdraw/index'); + Route::post('/withdraw/info', 'Withdraw/info'); + Route::post('/withdraw/change_status', 'Withdraw/change_status')->middleware('admin_log'); + Route::post('/withdraw/get_balance', 'Withdraw/get_balance'); + Route::post('/withdraw/channel_list', 'Withdraw/channel_list'); + + // 文档管理 + // 首页文章 + Route::post('/document/doc_index', 'document.Index/index'); + Route::post('/document/doc_add', 'document.Index/add'); + Route::post('/document/doc_detail', 'document.Index/detail'); + Route::post('/document/doc_edit', 'document.Index/edit'); + Route::post('/document/doc_del', 'document.Index/del'); + // 公告管理 + Route::post('/document/announcement_index', 'document.Announcement/index'); + Route::post('/document/announcement_add', 'document.Announcement/add'); + Route::post('/document/announcement_detail', 'document.Announcement/detail'); + Route::post('/document/announcement_edit', 'document.Announcement/edit'); + Route::post('/document/announcement_del', 'document.Announcement/del'); + // FAQ + Route::post('/document/faq_index', 'document.Faq/index'); + Route::post('/document/faq_add', 'document.Faq/add'); + Route::post('/document/faq_detail', 'document.Faq/detail'); + Route::post('/document/faq_edit', 'document.Faq/edit'); + Route::post('/document/faq_del', 'document.Faq/del'); + // banner + Route::post('/document/banner_index', 'document.Banner/index'); + Route::post('/document/banner_add', 'document.Banner/add'); + Route::post('/document/banner_detail', 'document.Banner/detail'); + Route::post('/document/banner_edit', 'document.Banner/edit'); + Route::post('/document/banner_del', 'document.Banner/del'); + + + //用户中心 + Route::post('/account/update_info', 'Admin/updateInfo'); + Route::post('/account/add', 'Admin/addUser'); + Route::get('/account/get_user_info', 'Admin/getUserInfo'); + Route::post('/account/update_password', 'Admin/updatePassword'); + Route::post('/account/update_status', 'Admin/updateAccountStauts'); + Route::post('/account/list', 'Admin/getUserList'); + Route::post('/account/del', 'Admin/del'); + Route::get('/account/logout', 'Admin/logout'); + Route::post('/account/update_account', 'Admin/updateAccount'); + Route::get('/account/get_perm_code', 'Admin/getPermCode'); + + //权限菜单 + Route::post('/auth/rule/add', 'auth.AuthRule/add'); + Route::post('/auth/rule/edit', 'auth.AuthRule/edit'); + Route::post('/auth/rule/list', 'auth.AuthRule/list'); + Route::post('/auth/rule/all_list', 'auth.AuthRule/allList'); + Route::post('/auth/rule/del', 'auth.AuthRule/del'); + Route::get('/auth/rule/get_side_menu', 'auth.AuthRule/getSideMenu'); + //权限角色 + Route::post('/auth/role/add', 'auth.AuthRole/add'); + Route::post('/auth/role/edit', 'auth.AuthRole/edit'); + Route::post('/auth/role/list', 'auth.AuthRole/list'); + Route::post('/auth/role/update_status', 'auth.AuthRole/updateStatus'); + Route::post('/auth/role/all_list', 'auth.AuthRole/allList'); + Route::post('/auth/role/del', 'auth.AuthRole/del'); + + // 实名认证操作 + Route::post('/user/verify_detail', 'User/verifyDetail'); + Route::post('/user/verify_do', 'User/verifyDo'); + Route::post('/user/lever_review', 'User/leverReview'); + Route::post('/user/reg_code', 'User/getRegCode'); + Route::post('/user/auto_login', 'User/autoLogin'); + + //设置杠杆 + Route::post('/user/get_leverage', 'User/getLeverageNum'); + Route::post('/user/edit_leverage', 'User/editLeverageNum')->middleware('admin_log'); + + // 投票 + Route::post('/vote/index', 'Vote/index'); + Route::post('/vote/add', 'Vote/add'); + Route::post('/vote/edit', 'Vote/edit'); + Route::post('/vote/del', 'Vote/del'); + // 贷款 + Route::post('/user/loan', 'User/get_loan'); + Route::post('/user/deal_loan', 'User/deal_loan'); + + + // 用户验证码 + Route::post('/user/get_user_code', 'User/getUserCode'); +})->allowCrossDomain($header) + ->middleware('admin_auth'); + + +Route::post('/admin/log', 'Admin/log')->allowCrossDomain($header)->middleware('admin_auth'); + +//登陆 +Route::post('/login/login', 'Login/login')->allowCrossDomain($header); +// 缓存股票数据 +Route::get('/cacheIdnStock', 'Index/cacheIdnStock'); +Route::get('/cacheUsStock', 'Index/cacheUsStock'); +Route::get('/cacheMysStock', 'Index/cacheMysStock'); +Route::get('/cacheThaStock', 'Index/cacheThaStock'); +Route::get('/cacheInStock', 'Index/cacheInStock'); +Route::get('/cacheSgdStock', 'Index/cacheSgdStock'); +Route::get('/cacheHkStock', 'Index/cacheHkStock'); +Route::get('/cacheGbxStock', 'Index/cacheGbxStock'); +Route::get('/cacheFurStock', 'Index/cacheFurStock'); +Route::get('/cacheEurStock', 'Index/cacheEurStock'); +Route::get('/cacheBrlStock', 'Index/cacheBrlStock'); +Route::get('/cacheJpStock', 'Index/cacheJpStock'); + + +Route::get('/cacheForex', 'Index/cacheForex'); +Route::get('/cacheInOption', 'Index/cacheInOption'); +Route::get('/invite_code', 'Admin/inviteCode'); + +//Route::get('/cache_stock', 'Index/cacheStock'); +Route::get('/cache_redis', 'Index/cacheRedis'); +Route::get('/test_send', 'Index/sendToGo'); + +Route::get('/sign_stock', 'Index/signStock'); +Route::post('/add_stock', 'Index/autoAddStock'); + +Route::get('/deal_stock', 'Index/dealStock'); + +// 定时任务 基金返息 +Route::get('/setting/fund_interest', 'setting.PreFundStock/interest'); + +Route::get('/setting/in_option_refresh', 'setting.Option/refresh'); + +// 修改 印度股-source +Route::post('/update_source', 'Index/updateSource'); + diff --git a/app/admin/service/AdminBaseService-pro.php b/app/admin/service/AdminBaseService-pro.php new file mode 100644 index 0000000..5b78c09 --- /dev/null +++ b/app/admin/service/AdminBaseService-pro.php @@ -0,0 +1,927 @@ +connect($config['host'], $config['port'], 10); + } catch (\Exception $exception) { + echo 'redis连接失败'; + } + if (!empty($config['password'])) { + $redis->auth($config['password']); + } + + $redis->select($config['select']); + return $redis; + } + + + /** + * @param string $code // 状态码 + * @param string $msg // 提示信息 + * @param array $result // 返回结果 + * @return array + */ + public function toData(string $code = '', string $msg = '', array $result = []): array + { + return [ + 'code' => $code, + 'message' => $msg, + 'data' => $result + ]; + } + + // 根据是否是代理 以及用户id 获取where条件 + public function getWhereByIsAgentAndUserId($adminId, $where, $userId) + { + // 判断是否是代理 + $isAgent = AdminModel::checkUserIsAgent($adminId); + // 不是代理 + if (!$isAgent) { + if ($userId > 0) { + $where[] = ['user_id', '=', $userId]; + } + return $where; + } + + // 获取管理用户 + $userIds = AdminModel::getUserIdsByAgentId($adminId); + if (empty($userIds)) { + return false; + } + + // 如果用户搜索 + if ($userId > 0) { + $where[] = ['user_id', 'in', $userIds]; + $where[] = ['user_id', '=', $userId]; + return $where; + } + + // 没有用户搜索 + $where[] = ['user_id', 'in', $userIds]; + return $where; + } + + // 校验admin_id 是否可以管理 userId + public function checkUserIdInAgent($adminId, $userId) + { + // 判断是否是代理 + $isAgent = AdminModel::checkUserIsAgent($adminId); + // 不是代理 + if (!$isAgent) { + return true; + } + + $userIds = AdminModel::getUserIdsByAgentId($adminId); + if (in_array($userId, $userIds)) { + return true; + } + + return false; + + } + + + /** + * @param $user_id + * @param $account_type + * @param $change_usable_num + * @param $change_frozen_num + * @param $change_type 变动类型:1-充值,2-提现,3-买入,4-卖出,5-冻结,6-解冻,7-账户转出,8-账户转入 ,9-注册返佣,10-开仓返佣 ,11-平仓返佣,12-调账加钱 13-调账减钱 19-基金返息 20-IPO订单退款 + */ + public function updateUserAsset($user_id, $account_type, $change_type, $change_usable_num, $change_frozen_num = 0, $order_no = "", $change_log_admin_id = 0, $rate = 0) + { + $prefix = env('database.prefix'); + $where['user_id'] = $user_id; + switch ($account_type) { + case 1: + $where['digital_id'] = 'USDT'; + $table = $prefix . 'user_digital'; + $log_table = $prefix . 'user_digital_log'; + $log_data['digital_id'] = 'USDT'; + break; + case 2: + $where['contract_id'] = 'USDT'; + $table = $prefix . 'user_contract'; + $log_table = $prefix . 'user_contract_log'; + $log_data['contract_id'] = 'USDT'; + break; + case 3: + $where['stock_id'] = 'USD'; + $table = $prefix . 'user_stock'; + $log_table = $prefix . 'user_stock_log'; + $log_data['stock_id'] = 'USD'; + break; + case 4: + $where['stock_id'] = 'IDR'; + $table = $prefix . 'user_stock_idn'; + $log_table = $prefix . 'user_stock_idn_log'; + $log_data['stock_id'] = 'IDR'; + break; + case 5: + $where['stock_id'] = 'MYR'; + $table = $prefix . 'user_stock_mys'; + $log_table = $prefix . 'user_stock_mys_log'; + $log_data['stock_id'] = 'MYR'; + break; + case 6: + $where['stock_id'] = 'THB'; + $table = $prefix . 'user_stock_tha'; + $log_table = $prefix . 'user_stock_tha_log'; + $log_data['stock_id'] = 'THB'; + break; + case 7: + $where['stock_id'] = 'INR'; + $table = $prefix . 'user_stock_in'; + $log_table = $prefix . 'user_stock_in_log'; + $log_data['stock_id'] = 'INR'; + break; + case 8: + $where['contract_id'] = 'USDT'; + $table = $prefix . 'user_contract_sec'; + $log_table = $prefix . 'user_contract_sec_log'; + $log_data['contract_id'] = 'USDT'; + break; + case 9: + $where['stock_id'] = 'SGD'; + $table = $prefix . 'user_stock_sgd'; + $log_table = $prefix . 'user_stock_sgd_log'; + $log_data['stock_id'] = 'SGD'; + break; + case 10: + $where['stock_id'] = 'USD'; + $table = $prefix . 'user_stock_fund'; + $log_table = $prefix . 'user_stock_fund_log'; + $log_data['stock_id'] = 'USD'; + break; + case 11: + $where['stock_id'] = 'INR'; + $table = $prefix . 'user_stock_option_inr'; + $log_table = $prefix . 'user_stock_option_inr_log'; + $log_data['stock_id'] = 'INR'; + break; + case 12: + $where['stock_id'] = 'HKD'; + $table = $prefix . 'user_stock_hkd'; + $log_table = $prefix . 'user_stock_hkd_log'; + $log_data['stock_id'] = 'HKD'; + break; + case 14: + $where['stock_id'] = 'GBX'; + $table = $prefix . 'user_stock_gbx'; + $log_table = $prefix . 'user_stock_gbx_log'; + $log_data['stock_id'] = 'GBX'; + break; + case 15: + $where['stock_id'] = 'EUR'; + $table = $prefix . 'user_stock_fur'; + $log_table = $prefix . 'user_stock_fur_log'; + $log_data['stock_id'] = 'EUR'; + break; + case 16: + $where['stock_id'] = 'EUR'; + $table = $prefix . 'user_stock_eur'; + $log_table = $prefix . 'user_stock_eur_log'; + $log_data['stock_id'] = 'EUR'; + break; + case 17: + $where['stock_id'] = 'BRL'; + $table = $prefix . 'user_stock_brl'; + $log_table = $prefix . 'user_stock_brl_log'; + $log_data['stock_id'] = 'BRL'; + break; + case 18: + $where['stock_id'] = 'JPY'; + $table = $prefix . 'user_stock_jp'; + $log_table = $prefix . 'user_stock_jp_log'; + $log_data['stock_id'] = 'JPY'; + break; + case 19: + $where['contract_id'] = 'USD'; + $table = $prefix . 'user_forex'; + $log_table = $prefix . 'user_forex_log'; + $log_data['contract_id'] = 'USD'; + break; + default: + return [ + 'status' => 100, + 'msg' => '账户类型错误' + ]; + break; + } + Db::startTrans(); + try { + //user_stock USD + $account_info = Db::table($table)->where($where)->lock(true)->find(); + if (empty($account_info)) { + $insert_data = [ + 'user_id' => $user_id, + 'usable_num' => 0, + 'frozen_num' => 0, + 'create_time' => date('Y-m-d H:i:s'), + 'update_time' => date('Y-m-d H:i:s') + ]; + if (in_array($account_type, [1, 2, 8,19])) { + $insert_data['contract_id'] = $where['contract_id']; + } else { + $insert_data['stock_id'] = $where['stock_id']; + + } + // 不存在 则新增 + Db::table($table)->insert($insert_data); + + $account_info = Db::table($table)->where($where)->lock(true)->find(); + if (empty($account_info)) { + Db::rollback(); + return [ + 'status' => 300, + 'msg' => '用户资金账号不存在' + ]; + } + + } + + $last_usable_num = bcadd($account_info['usable_num'], $change_usable_num, 18); + $last_frozen_num = bcadd($account_info['frozen_num'], $change_frozen_num, 18); + if ($last_usable_num < 0) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '可用资金不能为负' + ]; + } + + if ($change_type == 6) { + if ($last_frozen_num < 0 && abs($last_frozen_num) > 0.01) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '冻结资金不能为负' + ]; + } elseif (abs($last_frozen_num) < 0.01) { + $last_frozen_num = 0; + } + } else { + if ($last_frozen_num < 0) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '冻结资金不能为负' + ]; + } + } + + $change_data['usable_num'] = $last_usable_num; + $change_data['frozen_num'] = $last_frozen_num; + $change_data['update_time'] = date('Y-m-d H:i:s'); + $change_bool = Db::table($table)->where($where)->update($change_data); + if ($change_bool == 0) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => '账户修改失败' + ]; + } + + //echo Db::table($table)->where($where)->getLastSql(); + $log_data['user_id'] = $user_id; + $log_data['change_type'] = $change_type; + $log_data['before_num'] = $account_info['usable_num']; + $log_data['change_num'] = $change_usable_num; + $log_data['create_time'] = date('Y-m-d H:i:s'); + $log_data['update_time'] = date('Y-m-d H:i:s'); + if (!empty($order_no)) { + $log_data['order_id'] = $order_no; + } + $log_bool = Db::table($log_table)->insert($log_data); + if (!$log_bool) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => '账户流水插入失败' + ]; + } + + //后台系统 变更用户余额 + //需要录入变更日志 bot_user_balance_change_log + if (in_array($change_type, [12, 13]) && $change_log_admin_id > 0 && $rate != 0) { + $balance_change_log["user_id"] = $user_id; + $balance_change_log["type"] = $account_type; + $balance_change_log['before_num'] = bcdiv($account_info['usable_num'], $rate, 18); + $balance_change_log["change_num"] = bcdiv($change_usable_num, $rate, 18); + $balance_change_log["currency_rate"] = $rate; + $balance_change_log["admin_id"] = $change_log_admin_id; + $balance_change_log["create_time"] = date('Y-m-d H:i:s'); + $balance_log_bool = Db::table('bot_user_balance_change_log')->insert($balance_change_log); + if (!$balance_log_bool) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => '上分 - 账户流水插入失败' + ]; + } + } + + Db::commit(); + return [ + 'status' => 200, + 'msg' => 'ok' + ]; + } catch (ValidateException|PDOException|\Exception $e) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => $e->getMessage(), + 'data'=>[$e->getTrace()] + ]; + } + } + public function updateUserAssetNew($user_id,$change_type,$change_usable_num,$change_frozen_num = 0, $order_no = ""){ + Db::startTrans(); + try{ + $account_info = UserMoneyModel::where('user_id',$user_id)->where('stock_id','USD')->lock(true)->find(); + if (empty($account_info)) { + UserMoneyModel::InsertUserMoneyk([ + 'user_id' => $user_id, + 'stock_id' => 'USD', + 'usable_num' => 0, + 'frozen_num' => 0, + ]); + $account_info = UserMoneyModel::where('user_id', $user_id)->where('stock_id', 'USD')->lock(true)->find(); + if (empty($account_info)) { + Db::rollback(); + return [ + 'status' => 300, + 'msg' => '用户资金账号不存在' + ]; + } + } + + $last_usable_num = bcadd($account_info['usable_num'], $change_usable_num, 18); + $last_frozen_num = bcadd($account_info['frozen_num'], $change_frozen_num, 18); + + if ($last_usable_num < 0) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '可用资金不能为负' + ]; + } + if ($change_type == 6) { + if ($last_frozen_num < 0 && abs($last_frozen_num) > 0.01) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '冻结资金不能为负' + ]; + } elseif (abs($last_frozen_num) < 0.01) { + $last_frozen_num = 0; + } + } else { + if ($last_frozen_num < 0) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '冻结资金不能为负' + ]; + } + } + + $res=UserMoneyModel::where('user_id',$user_id)->where('stock_id','USD')->update([ + 'usable_num'=>$last_usable_num, + 'frozen_num'=>$last_frozen_num, + 'update_time'=>date('Y-m-d H:i:s'), + ]); + if(!$res){ + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '资金操作异常' + ]; + } + $log_bool=UserMoneyLogModel::InsertUserBalanceLog([ + 'user_id'=>$user_id, + 'change_type'=>$change_type, + 'stock_id'=>'USD', + 'martket_type'=>0, + 'before_num'=>$account_info['usable_num'], + 'change_num'=>$change_usable_num, + 'create_time'=>date('Y-m-d H:i:s'), + 'update_time'=>date('Y-m-d H:i:s'), + ]); + if (!$log_bool) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => '账户流水插入失败' + ]; + } + Db::commit(); + return [ + 'status' => 200, + 'msg' => 'ok' + ]; + + } catch (ValidateException|PDOException|\Exception $e) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => $e->getMessage(), + 'data' => [$e->getTrace()] + ]; + } + } + + // 合约插针缓存 + public function initContractHqData() + { + $now = date('Y-m-d H:i:s'); + $list = ContractMarketModel::where('type', 0) + ->whereTime('begin_time', '>', $now) + ->field('trade_name as selfContractCode,begin_time as BeginTime,step as Step ,end_time as EndTime,max_price as Price') + ->order('id', 'desc') + ->select(); + $rows = []; + $redis = $this->getRedis(); + if (!$list->isEmpty()) { + $rows = $list->toArray(); + foreach ($rows as $key => $val) { + $keep_decimal = $redis->hget('CONTRACT:LIST:' . $val['selfContractCode'], 'keep_decimal'); + $list[$key]['Digits'] = $keep_decimal; + } + } + + $reds_key = "contract_hq_setting"; + $redis->del($reds_key); + $redis->set($reds_key, json_encode($rows)); + } + + // 外汇插针缓存 + public function initForexHqData() + { + $now = date('Y-m-d H:i:s'); + $list = ForexMarketModel::where('type', 0) + ->whereTime('begin_time', '>', $now) + ->field('trade_name as selfContractCode,begin_time as BeginTime,step as Step ,end_time as EndTime,max_price as Price') + ->order('id', 'desc') + ->select(); + $rows = []; + $redis = $this->getRedis(); + if (!$list->isEmpty()) { + $rows = $list->toArray(); + foreach ($rows as $key => $val) { + $keep_decimal = $redis->hget('FOREX:LIST:' . $val['selfContractCode'], 'keep_decimal'); + $list[$key]['Digits'] = $keep_decimal; + } + } + + $reds_key = "forex_hq_setting"; + $redis->del($reds_key); + $redis->set($reds_key, json_encode($rows)); + } + + public function initContractSetting() + { + $list = ContractSettingModel::getSettingList(); + $redis_key = "contract_time_setting"; + $redis = $this->getRedis(); + $redis->del($redis_key); + $redis->set($redis_key, json_encode($list, JSON_NUMERIC_CHECK)); + } + + // 合约自发行情缓存 + public function initContractMarketData() + { + $redis = $this->getRedis(); + $now = date('Y-m-d H:i:s'); + $list = ContractMarketModel::where('type', 1) + ->whereTime('begin_time', '>', $now) + ->field('trade_name as selfContractCode,end_time as endTime,max_price as maxPrice') + ->order('id', 'desc') + ->select(); + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + } + + $key = "contract_market_setting"; + $redis->set($key, json_encode($rows)); + } + + public function getBrokerageKey($type) + { + switch ($type) { + case 1: + //平仓返佣 + $brokerage_key = 'BROKERAGE:SALE:SETTING'; + break; + case 2: + //开仓返佣 + $brokerage_key = 'BROKERAGE:BUY:SETTING'; + break; + default: + //注册返佣 + $brokerage_key = 'BROKERAGE:REG:SETTING'; + break; + } + return $brokerage_key; + } + + public function getTradeFeeKey($market_type) + { + switch ($market_type) { + case 1: + $fee_key = 'TRADE:FEE:DIGITAL'; + break; + case 2: + $fee_key = 'TRADE:FEE:CONTRACT'; + break; + case 3: + $fee_key = 'TRADE:FEE:US_STOCK'; + break; + case 4: + $fee_key = 'TRADE:FEE:IDN_STOCK'; + break; + case 5: + $fee_key = 'TRADE:FEE:MYS_STOCK'; + break; + case 6: + $fee_key = 'TRADE:FEE:THA_STOCK'; + break; + case 7: + $fee_key = 'TRADE:FEE:IN_STOCK'; + break; + case 8: + $fee_key = 'TRADE:FEE:CONTRACT_SEC'; + break; + case 9: + $fee_key = 'TRADE:FEE:SGD_STOCK'; + break; + case 12: + $fee_key = 'TRADE:FEE:HK_STOCK'; + break; + case 14: + $fee_key = 'TRADE:FEE:UK_STOCK'; + break; + case 15: + $fee_key = 'TRADE:FEE:FUR_STOCK'; + break; + case 16: + $fee_key = 'TRADE:FEE:EUR_STOCK'; + break; + case 17: + $fee_key = 'TRADE:FEE:BR_STOCK'; + break; + case 18: + $fee_key = 'TRADE:FEE:JP_STOCK'; + break; + case 19: + $fee_key = 'TRADE:FEE:FOREX'; + break; + default: + $fee_key = ''; + break; + } + return $fee_key; + } + + /** + * @param $menus + * @param $pid + * @param $showParentName + * @return array|string + */ + function getTreeMenu($menus, $pid = 0, $showParentName = false) + { + $arr = []; + if (empty($menus)) { + return ''; + } + if ($showParentName) { + for ($i = 0; $i < count($menus); $i++) { + $parentId = $menus[$i]['pid']; + if ($parentId == '0') { + $menus[$i]['parent_name'] = ""; + } else { + $parent = array_filter($menus, function ($item) use ($parentId) { + return $item['id'] == $parentId; + }); + + if ($parent) { + $parent = array_values($parent); + if ($parent[0]['name']) { + $menus[$i]['parent_name'] = $parent[0]['name']; + } else if ($parent[0]['title']) { + $menus[$i]['parent_name'] = $parent[0]['title']; + } + } + } + } + } + foreach ($menus as $key => $value) { + if ($value['pid'] == $pid) { + $children = $this->getTreeMenu($menus, $value['id']); + if (!empty($children)) { + $value['children'] = $children; + } + //pid=0为顶级菜单,前端不显示 + if ($pid == '0') { + unset($value['pid']); + } + $arr[] = $value; + } + } + + return $arr; + } + + function getSortTreeMenu($menus, $sort = 'order', $pid = 0) + { + $menuList = getTreeMenu($menus, $pid = 0); + foreach ($menuList as $key => $value) { + if (!empty($value['children'])) { + $sort = array_column($value['children'], $sort); + array_multisort($sort, SORT_DESC, $value['children']); + } + } + return $menuList; + } + + // 给 go 行情 发送 新增的股票 + public function sendNewStockToGo($country, $newStockCode, $oldStockCode, $stockName, $tape, $price = 0, $isReal = 1, $intro = '', $source = 0, $numericCode = 0) + { + try { + switch ($country) { + case 'India': + case 'Thailand': + case 'US': + case 'HongKong': + $price = bcadd($price, 0, 2); + break; + case 'Indonesia': + $price = bcadd($price, 0, 0); + break; + case 'Malaysia': + $price = bcadd($price, 0, 3); + break; + default: + $price = bcadd($price, 0, 2); + } + + $responseArr = [ + 'old_ticker' => $oldStockCode, //新的股票代码 + 'new_ticker' => $newStockCode, //旧的股票代码 (新增的话 ,两个字段都是一样的值) + 'token' => 'asdfsnl123jlknl3nksdf32345ln98sdfsfs8891232nsdfsdfsdfsdxcfvbhnfgh', + 'locale' => $country, //国家 + 'yesterday_close' => $price, //价格 + 'name' => $stockName, //股票name + 'primary_exchange' => $tape, //交易所 + 'is_real' => $isReal, //1正式股票 2测试股票 + 'intro' => $intro //股票简介 + ]; + + if ($source > 0) { + $responseArr['source'] = $source; + } + + if ($country == 'Malaysia') { + $responseArr['numeric_code'] = $numericCode . ''; + } + + $client = new Client(); + $url = env('QUOTE.BASE_URL') . '/spots/list/new/add'; + $response = $client->request("POST", $url, [ + 'json' => $responseArr + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + $responseArr['url'] = $url; + trace('---给行情推送数据---' . json_encode([$res, $responseArr]), 'error'); + + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + + trace('---给行情推送数据异常---' . json_encode([$res, $responseArr]), 'error'); + return false; + } catch (\Exception $exception) { + trace('---给行情推送数据异常1---' . $exception->getMessage(), 'error'); + + } catch (GuzzleException $e) { + trace('---给行情推送数据异常2---' . $e->getMessage(), 'error'); + } + + return false; + } + + // 给 go 行情 发送股票小数位数 + public function sendDecimalToGo($country, $stockCode, int $decimal) + { + try { + $client = new Client(); + $url = env('QUOTE.BASE_URL') . '/spots/update/keep'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'currency' => $country, + 'stockCode' => $stockCode, + 'keepDecimal' => $decimal, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + + Log::error('给行情推送数据异常 ' . json_encode([$res])); + return false; + } catch (\Exception $exception) { + Log::error('给行情推送数据异常1 ' . $exception->getMessage()); + } catch (GuzzleException $e) { + Log::error('给行情推送数据异常2 ' . $e->getMessage()); + } + + return false; + } + + // 给 go 交易 发送股票小数位数 // $preStockId $marketType $stockCode + public function sendStockToGo($preStockId, $stockCode, $marketType) + { + try { + $marketType = $marketType + 0; // 转成数字 + $preStockId = $preStockId . ''; + $client = new Client(); + $url = env('QUOTE.DEAL_BASE_URL') . '/order_sharepre/share_pre_trade'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'code' => $stockCode, + 'id' => $preStockId, + 'stock' => $marketType, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + trace('---给交易推送数据---' . json_encode([$res, [ + 'url' => $url, + 'code' => $stockCode, + 'id' => $preStockId, + 'stock' => $marketType,]]), 'error'); + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + return false; + } catch (\Exception $exception) { + trace('---通知交易异常1---' . $exception->getMessage(), 'error'); + } catch (GuzzleException $e) { + trace('---通知交易异常1---' . $e->getMessage(), 'error'); + } + return false; + } + + public function sendStockToTrade($order_no, $stockCode, $marketType) + { + try { + $marketType = $marketType + 0; // 转成数字 + $order_no = $order_no . ''; + $client = new Client(); + $url = env('QUOTE.DEAL_BASE_URL') . '/order_sharepre/share_pre_trade_by_order_no'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'code' => $stockCode, + 'id' => $order_no, + 'stock' => $marketType, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + trace('---单个订单给交易推送数据---' . json_encode([$res, [ + 'url' => $url, + 'code' => $stockCode, + 'id' => $order_no, + 'stock' => $marketType,]]), 'error'); + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + return false; + } catch (\Exception $exception) { + trace('---通知交易异常1---' . $exception->getMessage(), 'error'); + } catch (GuzzleException $e) { + trace('---通知交易异常1---' . $e->getMessage(), 'error'); + } + return false; + } + + public function sendUpdateCodeGo($newCode, $oldCode, $marketType) + { + try { + $marketType = $marketType + 0; // 转成数字 + $client = new Client(); + $url = env('QUOTE.DEAL_BASE_URL') . '/order_sharepre/update_stock_id'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'code' => $newCode, + 'codeOld' => $oldCode, + 'stock' => $marketType, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + Log::info('给交易推送数据 ' . json_encode([$res, [ + 'url' => $url, + 'code' => $newCode, + 'codeOld' => $oldCode, + 'stock' => $marketType,]])); + + + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + return false; + } catch (\Exception $exception) { + Log::error('给行情推送数据异常1 ' . $exception->getMessage()); + } catch (GuzzleException $e) { + Log::error('给行情推送数据异常2 ' . $e->getMessage()); + } + + return false; + } + + /** + * 给go推送股票指数代码 + * @param $code + * @param $country + * @param $sort + * @param $status + * @return bool + */ + public function sendStockIndexToGo($code, $country, $sort, $status) + { + try { + $client = new Client(); + $url = env('QUOTE.BASE_URL') . '/spots/index/list/new/add'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'ticker' => $code, + 'locale' => $country, + 'state' => $status, + 'sort' => $sort, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + Log::info('给交易推送数据 ' . json_encode([$res, [ + 'url' => $url, + 'ticker' => $code, + 'locale' => $country, + 'state' => $status, + 'sort' => $sort, + ]])); + + + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + return false; + } catch (\Exception $exception) { + Log::error('给行情推送股票指数数据异常1 ' . $exception->getMessage()); + } catch (GuzzleException $e) { + Log::error('给行情推送股票指数数据异常2 ' . $e->getMessage()); + } + + return false; + } + + +} \ No newline at end of file diff --git a/app/admin/service/AdminBaseService.php b/app/admin/service/AdminBaseService.php new file mode 100644 index 0000000..c5f32fb --- /dev/null +++ b/app/admin/service/AdminBaseService.php @@ -0,0 +1,927 @@ +connect($config['host'], $config['port'], 10); + } catch (\Exception $exception) { + echo 'redis连接失败'; + } + if (!empty($config['password'])) { + $redis->auth($config['password']); + } + + $redis->select($config['select']); + return $redis; + } + + + /** + * @param string $code // 状态码 + * @param string $msg // 提示信息 + * @param array $result // 返回结果 + * @return array + */ + public function toData(string $code = '', string $msg = '', array $result = []): array + { + return [ + 'code' => $code, + 'message' => $msg, + 'data' => $result + ]; + } + + // 根据是否是代理 以及用户id 获取where条件 + public function getWhereByIsAgentAndUserId($adminId, $where, $userId) + { + // 判断是否是代理 + $isAgent = AdminModel::checkUserIsAgent($adminId); + // 不是代理 + if (!$isAgent) { + if ($userId > 0) { + $where[] = ['user_id', '=', $userId]; + } + return $where; + } + + // 获取管理用户 + $userIds = AdminModel::getUserIdsByAgentId($adminId); + if (empty($userIds)) { + return false; + } + + // 如果用户搜索 + if ($userId > 0) { + $where[] = ['user_id', 'in', $userIds]; + $where[] = ['user_id', '=', $userId]; + return $where; + } + + // 没有用户搜索 + $where[] = ['user_id', 'in', $userIds]; + return $where; + } + + // 校验admin_id 是否可以管理 userId + public function checkUserIdInAgent($adminId, $userId) + { + // 判断是否是代理 + $isAgent = AdminModel::checkUserIsAgent($adminId); + // 不是代理 + if (!$isAgent) { + return true; + } + + $userIds = AdminModel::getUserIdsByAgentId($adminId); + if (in_array($userId, $userIds)) { + return true; + } + + return false; + + } + + + /** + * @param $user_id + * @param $account_type + * @param $change_usable_num + * @param $change_frozen_num + * @param $change_type 变动类型:1-充值,2-提现,3-买入,4-卖出,5-冻结,6-解冻,7-账户转出,8-账户转入 ,9-注册返佣,10-开仓返佣 ,11-平仓返佣,12-调账加钱 13-调账减钱 19-基金返息 20-IPO订单退款 + */ + public function updateUserAsset($user_id, $account_type, $change_type, $change_usable_num, $change_frozen_num = 0, $order_no = "", $change_log_admin_id = 0, $rate = 0) + { + $prefix = env('database.prefix'); + $where['user_id'] = $user_id; + switch ($account_type) { + case 1: + $where['digital_id'] = 'USDT'; + $table = $prefix . 'user_digital'; + $log_table = $prefix . 'user_digital_log'; + $log_data['digital_id'] = 'USDT'; + break; + case 2: + $where['contract_id'] = 'USDT'; + $table = $prefix . 'user_contract'; + $log_table = $prefix . 'user_contract_log'; + $log_data['contract_id'] = 'USDT'; + break; + case 3: + $where['stock_id'] = 'USD'; + $table = $prefix . 'user_stock'; + $log_table = $prefix . 'user_stock_log'; + $log_data['stock_id'] = 'USD'; + break; + case 4: + $where['stock_id'] = 'IDR'; + $table = $prefix . 'user_stock_idn'; + $log_table = $prefix . 'user_stock_idn_log'; + $log_data['stock_id'] = 'IDR'; + break; + case 5: + $where['stock_id'] = 'MYR'; + $table = $prefix . 'user_stock_mys'; + $log_table = $prefix . 'user_stock_mys_log'; + $log_data['stock_id'] = 'MYR'; + break; + case 6: + $where['stock_id'] = 'THB'; + $table = $prefix . 'user_stock_tha'; + $log_table = $prefix . 'user_stock_tha_log'; + $log_data['stock_id'] = 'THB'; + break; + case 7: + $where['stock_id'] = 'INR'; + $table = $prefix . 'user_stock_in'; + $log_table = $prefix . 'user_stock_in_log'; + $log_data['stock_id'] = 'INR'; + break; + case 8: + $where['contract_id'] = 'USDT'; + $table = $prefix . 'user_contract_sec'; + $log_table = $prefix . 'user_contract_sec_log'; + $log_data['contract_id'] = 'USDT'; + break; + case 9: + $where['stock_id'] = 'SGD'; + $table = $prefix . 'user_stock_sgd'; + $log_table = $prefix . 'user_stock_sgd_log'; + $log_data['stock_id'] = 'SGD'; + break; + case 10: + $where['stock_id'] = 'USD'; + $table = $prefix . 'user_stock_fund'; + $log_table = $prefix . 'user_stock_fund_log'; + $log_data['stock_id'] = 'USD'; + break; + case 11: + $where['stock_id'] = 'INR'; + $table = $prefix . 'user_stock_option_inr'; + $log_table = $prefix . 'user_stock_option_inr_log'; + $log_data['stock_id'] = 'INR'; + break; + case 12: + $where['stock_id'] = 'HKD'; + $table = $prefix . 'user_stock_hkd'; + $log_table = $prefix . 'user_stock_hkd_log'; + $log_data['stock_id'] = 'HKD'; + break; + case 14: + $where['stock_id'] = 'GBX'; + $table = $prefix . 'user_stock_gbx'; + $log_table = $prefix . 'user_stock_gbx_log'; + $log_data['stock_id'] = 'GBX'; + break; + case 15: + $where['stock_id'] = 'EUR'; + $table = $prefix . 'user_stock_fur'; + $log_table = $prefix . 'user_stock_fur_log'; + $log_data['stock_id'] = 'EUR'; + break; + case 16: + $where['stock_id'] = 'EUR'; + $table = $prefix . 'user_stock_eur'; + $log_table = $prefix . 'user_stock_eur_log'; + $log_data['stock_id'] = 'EUR'; + break; + case 17: + $where['stock_id'] = 'BRL'; + $table = $prefix . 'user_stock_brl'; + $log_table = $prefix . 'user_stock_brl_log'; + $log_data['stock_id'] = 'BRL'; + break; + case 18: + $where['stock_id'] = 'JPY'; + $table = $prefix . 'user_stock_jp'; + $log_table = $prefix . 'user_stock_jp_log'; + $log_data['stock_id'] = 'JPY'; + break; + case 19: + $where['contract_id'] = 'USD'; + $table = $prefix . 'user_forex'; + $log_table = $prefix . 'user_forex_log'; + $log_data['contract_id'] = 'USD'; + break; + default: + return [ + 'status' => 100, + 'msg' => '账户类型错误' + ]; + break; + } + Db::startTrans(); + try { + //user_stock USD + $account_info = Db::table($table)->where($where)->lock(true)->find(); + if (empty($account_info)) { + $insert_data = [ + 'user_id' => $user_id, + 'usable_num' => 0, + 'frozen_num' => 0, + 'create_time' => date('Y-m-d H:i:s'), + 'update_time' => date('Y-m-d H:i:s') + ]; + if (in_array($account_type, [1, 2, 8,19])) { + $insert_data['contract_id'] = $where['contract_id']; + } else { + $insert_data['stock_id'] = $where['stock_id']; + + } + // 不存在 则新增 + Db::table($table)->insert($insert_data); + + $account_info = Db::table($table)->where($where)->lock(true)->find(); + if (empty($account_info)) { + Db::rollback(); + return [ + 'status' => 300, + 'msg' => '用户资金账号不存在' + ]; + } + + } + + $last_usable_num = bcadd($account_info['usable_num'], $change_usable_num, 18); + $last_frozen_num = bcadd($account_info['frozen_num'], $change_frozen_num, 18); + if ($last_usable_num < 0) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '可用资金不能为负' + ]; + } + + if ($change_type == 6) { + if ($last_frozen_num < 0 && abs($last_frozen_num) > 0.01) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '冻结资金不能为负' + ]; + } elseif (abs($last_frozen_num) < 0.01) { + $last_frozen_num = 0; + } + } else { + if ($last_frozen_num < 0) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '冻结资金不能为负' + ]; + } + } + + $change_data['usable_num'] = $last_usable_num; + $change_data['frozen_num'] = $last_frozen_num; + $change_data['update_time'] = date('Y-m-d H:i:s'); + $change_bool = Db::table($table)->where($where)->update($change_data); + if ($change_bool == 0) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => '账户修改失败' + ]; + } + + //echo Db::table($table)->where($where)->getLastSql(); + $log_data['user_id'] = $user_id; + $log_data['change_type'] = $change_type; + $log_data['before_num'] = $account_info['usable_num']; + $log_data['change_num'] = $change_usable_num; + $log_data['create_time'] = date('Y-m-d H:i:s'); + $log_data['update_time'] = date('Y-m-d H:i:s'); + if (!empty($order_no)) { + $log_data['order_id'] = $order_no; + } + $log_bool = Db::table($log_table)->insert($log_data); + if (!$log_bool) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => '账户流水插入失败' + ]; + } + + //后台系统 变更用户余额 + //需要录入变更日志 bot_user_balance_change_log + if (in_array($change_type, [12, 13]) && $change_log_admin_id > 0 && $rate != 0) { + $balance_change_log["user_id"] = $user_id; + $balance_change_log["type"] = $account_type; + $balance_change_log['before_num'] = bcdiv($account_info['usable_num'], $rate, 18); + $balance_change_log["change_num"] = bcdiv($change_usable_num, $rate, 18); + $balance_change_log["currency_rate"] = $rate; + $balance_change_log["admin_id"] = $change_log_admin_id; + $balance_change_log["create_time"] = date('Y-m-d H:i:s'); + $balance_log_bool = Db::table('bot_user_balance_change_log')->insert($balance_change_log); + if (!$balance_log_bool) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => '上分 - 账户流水插入失败' + ]; + } + } + + Db::commit(); + return [ + 'status' => 200, + 'msg' => 'ok' + ]; + } catch (ValidateException|PDOException|\Exception $e) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => $e->getMessage(), + 'data'=>[$e->getTrace()] + ]; + } + } + public function updateUserAssetNew($user_id,$change_type,$change_usable_num,$change_frozen_num = 0, $order_no = ""){ + Db::startTrans(); + try{ + $account_info = UserMoneyModel::where('user_id',$user_id)->where('stock_id','USD')->lock(true)->find(); + if (empty($account_info)) { + UserMoneyModel::InsertUserMoneyk([ + 'user_id' => $user_id, + 'stock_id' => 'USD', + 'usable_num' => 0, + 'frozen_num' => 0, + ]); + $account_info = UserMoneyModel::where('user_id', $user_id)->where('stock_id', 'USD')->lock(true)->find(); + if (empty($account_info)) { + Db::rollback(); + return [ + 'status' => 300, + 'msg' => '用户资金账号不存在' + ]; + } + } + + $last_usable_num = bcadd($account_info['usable_num'], $change_usable_num, 18); + $last_frozen_num = bcadd($account_info['frozen_num'], $change_frozen_num, 18); + + if ($last_usable_num < 0) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '可用资金不能为负' + ]; + } + if ($change_type == 6) { + if ($last_frozen_num < 0 && abs($last_frozen_num) > 0.01) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '冻结资金不能为负' + ]; + } elseif (abs($last_frozen_num) < 0.01) { + $last_frozen_num = 0; + } + } else { + if ($last_frozen_num < 0) { + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '冻结资金不能为负' + ]; + } + } + + $res=UserMoneyModel::where('user_id',$user_id)->where('stock_id','USD')->update([ + 'usable_num'=>$last_usable_num, + 'frozen_num'=>$last_frozen_num, + 'update_time'=>date('Y-m-d H:i:s'), + ]); + if(!$res){ + Db::rollback(); + return [ + 'status' => 400, + 'msg' => '资金操作异常' + ]; + } + $log_bool=UserMoneyLogModel::InsertUserBalanceLog([ + 'user_id'=>$user_id, + 'change_type'=>$change_type, + 'stock_id'=>'USD', + 'martket_type'=>0, + 'before_num'=>$account_info['usable_num'], + 'change_num'=>$change_usable_num, + 'create_time'=>date('Y-m-d H:i:s'), + 'update_time'=>date('Y-m-d H:i:s'), + ]); + if (!$log_bool) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => '账户流水插入失败' + ]; + } + Db::commit(); + return [ + 'status' => 200, + 'msg' => 'ok' + ]; + + } catch (ValidateException|PDOException|\Exception $e) { + Db::rollback(); + return [ + 'status' => 100, + 'msg' => $e->getMessage(), + 'data' => [$e->getTrace()] + ]; + } + } + + // 合约插针缓存 + public function initContractHqData() + { + $now = date('Y-m-d H:i:s'); + $list = ContractMarketModel::where('type', 0) + ->whereTime('begin_time', '>', $now) + ->field('trade_name as selfContractCode,begin_time as BeginTime,step as Step ,end_time as EndTime,max_price as Price') + ->order('id', 'desc') + ->select(); + $rows = []; + $redis = $this->getRedis(); + if (!$list->isEmpty()) { + $rows = $list->toArray(); + foreach ($rows as $key => $val) { + $keep_decimal = $redis->hget('CONTRACT:LIST:' . $val['selfContractCode'], 'keep_decimal'); + $list[$key]['Digits'] = $keep_decimal; + } + } + + $reds_key = "contract_hq_setting"; + $redis->del($reds_key); + $redis->set($reds_key, json_encode($rows)); + } + + // 外汇插针缓存 + public function initForexHqData() + { + $now = date('Y-m-d H:i:s'); + $list = ForexMarketModel::where('type', 0) + ->whereTime('begin_time', '>', $now) + ->field('trade_name as selfContractCode,begin_time as BeginTime,step as Step ,end_time as EndTime,max_price as Price') + ->order('id', 'desc') + ->select(); + $rows = []; + $redis = $this->getRedis(); + if (!$list->isEmpty()) { + $rows = $list->toArray(); + foreach ($rows as $key => $val) { + $keep_decimal = $redis->hget('FOREX:LIST:' . $val['selfContractCode'], 'keep_decimal'); + $list[$key]['Digits'] = $keep_decimal; + } + } + + $reds_key = "forex_hq_setting"; + $redis->del($reds_key); + $redis->set($reds_key, json_encode($rows)); + } + + public function initContractSetting() + { + $list = ContractSettingModel::getSettingList(); + $redis_key = "contract_time_setting"; + $redis = $this->getRedis(); + $redis->del($redis_key); + $redis->set($redis_key, json_encode($list, JSON_NUMERIC_CHECK)); + } + + // 合约自发行情缓存 + public function initContractMarketData() + { + $redis = $this->getRedis(); + $now = date('Y-m-d H:i:s'); + $list = ContractMarketModel::where('type', 1) + ->whereTime('begin_time', '>', $now) + ->field('trade_name as selfContractCode,end_time as endTime,max_price as maxPrice') + ->order('id', 'desc') + ->select(); + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + } + + $key = "contract_market_setting"; + $redis->set($key, json_encode($rows)); + } + + public function getBrokerageKey($type) + { + switch ($type) { + case 1: + //平仓返佣 + $brokerage_key = 'BROKERAGE:SALE:SETTING'; + break; + case 2: + //开仓返佣 + $brokerage_key = 'BROKERAGE:BUY:SETTING'; + break; + default: + //注册返佣 + $brokerage_key = 'BROKERAGE:REG:SETTING'; + break; + } + return $brokerage_key; + } + + public function getTradeFeeKey($market_type) + { + switch ($market_type) { + case 1: + $fee_key = 'TRADE:FEE:DIGITAL'; + break; + case 2: + $fee_key = 'TRADE:FEE:CONTRACT'; + break; + case 3: + $fee_key = 'TRADE:FEE:US_STOCK'; + break; + case 4: + $fee_key = 'TRADE:FEE:IDN_STOCK'; + break; + case 5: + $fee_key = 'TRADE:FEE:MYS_STOCK'; + break; + case 6: + $fee_key = 'TRADE:FEE:THA_STOCK'; + break; + case 7: + $fee_key = 'TRADE:FEE:IN_STOCK'; + break; + case 8: + $fee_key = 'TRADE:FEE:CONTRACT_SEC'; + break; + case 9: + $fee_key = 'TRADE:FEE:SGD_STOCK'; + break; + case 12: + $fee_key = 'TRADE:FEE:HK_STOCK'; + break; + case 14: + $fee_key = 'TRADE:FEE:UK_STOCK'; + break; + case 15: + $fee_key = 'TRADE:FEE:FUR_STOCK'; + break; + case 16: + $fee_key = 'TRADE:FEE:EUR_STOCK'; + break; + case 17: + $fee_key = 'TRADE:FEE:BR_STOCK'; + break; + case 18: + $fee_key = 'TRADE:FEE:JP_STOCK'; + break; + case 19: + $fee_key = 'TRADE:FEE:FOREX'; + break; + default: + $fee_key = ''; + break; + } + return $fee_key; + } + + /** + * @param $menus + * @param $pid + * @param $showParentName + * @return array|string + */ + function getTreeMenu($menus, $pid = 0, $showParentName = false) + { + $arr = []; + if (empty($menus)) { + return ''; + } + if ($showParentName) { + for ($i = 0; $i < count($menus); $i++) { + $parentId = $menus[$i]['pid']; + if ($parentId == '0') { + $menus[$i]['parent_name'] = ""; + } else { + $parent = array_filter($menus, function ($item) use ($parentId) { + return $item['id'] == $parentId; + }); + + if ($parent) { + $parent = array_values($parent); + if ($parent[0]['name']) { + $menus[$i]['parent_name'] = $parent[0]['name']; + } else if ($parent[0]['title']) { + $menus[$i]['parent_name'] = $parent[0]['title']; + } + } + } + } + } + foreach ($menus as $key => $value) { + if ($value['pid'] == $pid) { + $children = $this->getTreeMenu($menus, $value['id']); + if (!empty($children)) { + $value['children'] = $children; + } + //pid=0为顶级菜单,前端不显示 + if ($pid == '0') { + unset($value['pid']); + } + $arr[] = $value; + } + } + + return $arr; + } + + function getSortTreeMenu($menus, $sort = 'order', $pid = 0) + { + $menuList = getTreeMenu($menus, $pid = 0); + foreach ($menuList as $key => $value) { + if (!empty($value['children'])) { + $sort = array_column($value['children'], $sort); + array_multisort($sort, SORT_DESC, $value['children']); + } + } + return $menuList; + } + + // 给 go 行情 发送 新增的股票 + public function sendNewStockToGo($country, $newStockCode, $oldStockCode, $stockName, $tape, $price = 0, $isReal = 1, $intro = '', $source = 0, $numericCode = 0) + { + try { + switch ($country) { + case 'India': + case 'Thailand': + case 'US': + case 'HongKong': + $price = bcadd($price, 0, 2); + break; + case 'Indonesia': + $price = bcadd($price, 0, 0); + break; + case 'Malaysia': + $price = bcadd($price, 0, 3); + break; + default: + $price = bcadd($price, 0, 2); + } + + $responseArr = [ + 'old_ticker' => $oldStockCode, //新的股票代码 + 'new_ticker' => $newStockCode, //旧的股票代码 (新增的话 ,两个字段都是一样的值) + 'token' => 'asdfsnl123jlknl3nksdf32345ln98sdfsfs8891232nsdfsdfsdfsdxcfvbhnfgh', + 'locale' => $country, //国家 + 'yesterday_close' => $price, //价格 + 'name' => $stockName, //股票name + 'primary_exchange' => $tape, //交易所 + 'is_real' => $isReal, //1正式股票 2测试股票 + 'intro' => $intro //股票简介 + ]; + + if ($source > 0) { + $responseArr['source'] = $source; + } + + if ($country == 'Malaysia') { + $responseArr['numeric_code'] = $numericCode . ''; + } + + $client = new Client(); + $url = env('QUOTE.BASE_URL') . '/spots/list/new/add'; + $response = $client->request("POST", $url, [ + 'json' => $responseArr + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + $responseArr['url'] = $url; + trace('---给行情推送数据---' . json_encode([$res, $responseArr]), 'error'); + + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + + trace('---给行情推送数据异常---' . json_encode([$res, $responseArr]), 'error'); + return false; + } catch (\Exception $exception) { + trace('---给行情推送数据异常1---' . $exception->getMessage(), 'error'); + + } catch (GuzzleException $e) { + trace('---给行情推送数据异常2---' . $e->getMessage(), 'error'); + } + + return false; + } + + // 给 go 行情 发送股票小数位数 + public function sendDecimalToGo($country, $stockCode, int $decimal) + { + try { + $client = new Client(); + $url = env('QUOTE.BASE_URL') . '/spots/update/keep'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'currency' => $country, + 'stockCode' => $stockCode, + 'keepDecimal' => $decimal, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + + Log::error('给行情推送数据异常 ' . json_encode([$res])); + return false; + } catch (\Exception $exception) { + Log::error('给行情推送数据异常1 ' . $exception->getMessage()); + } catch (GuzzleException $e) { + Log::error('给行情推送数据异常2 ' . $e->getMessage()); + } + + return false; + } + + // 给 go 交易 发送股票小数位数 // $preStockId $marketType $stockCode + public function sendStockToGo($preStockId, $stockCode, $marketType) + { + try { + $marketType = $marketType + 0; // 转成数字 + $preStockId = $preStockId . ''; + $client = new Client(); + $url = env('QUOTE.DEAL_BASE_URL') . '/order_sharepre/share_pre_trade'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'code' => $stockCode, + 'id' => $preStockId, + 'stock' => $marketType, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + trace('---给交易推送数据---' . json_encode([$res, [ + 'url' => $url, + 'code' => $stockCode, + 'id' => $preStockId, + 'stock' => $marketType,]]), 'error'); + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + return false; + } catch (\Exception $exception) { + trace('---通知交易异常1---' . $exception->getMessage(), 'error'); + } catch (GuzzleException $e) { + trace('---通知交易异常1---' . $e->getMessage(), 'error'); + } + return false; + } + + public function sendStockToTrade($order_no, $stockCode, $marketType) + { + try { + $marketType = $marketType + 0; // 转成数字 + $order_no = $order_no . ''; + $client = new Client(); + $url = env('QUOTE.DEAL_BASE_URL') . '/order_sharepre/share_pre_trade_by_order_no'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'code' => $stockCode, + 'id' => $order_no, + 'stock' => $marketType, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + trace('---单个订单给交易推送数据---' . json_encode([$res, [ + 'url' => $url, + 'code' => $stockCode, + 'id' => $order_no, + 'stock' => $marketType,]]), 'error'); + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + return false; + } catch (\Exception $exception) { + trace('---通知交易异常1---' . $exception->getMessage(), 'error'); + } catch (GuzzleException $e) { + trace('---通知交易异常1---' . $e->getMessage(), 'error'); + } + return false; + } + + public function sendUpdateCodeGo($newCode, $oldCode, $marketType) + { + try { + $marketType = $marketType + 0; // 转成数字 + $client = new Client(); + $url = env('QUOTE.DEAL_BASE_URL') . '/order_sharepre/update_stock_id'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'code' => $newCode, + 'codeOld' => $oldCode, + 'stock' => $marketType, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + Log::info('给交易推送数据 ' . json_encode([$res, [ + 'url' => $url, + 'code' => $newCode, + 'codeOld' => $oldCode, + 'stock' => $marketType,]])); + + + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + return false; + } catch (\Exception $exception) { + Log::error('给行情推送数据异常1 ' . $exception->getMessage()); + } catch (GuzzleException $e) { + Log::error('给行情推送数据异常2 ' . $e->getMessage()); + } + + return false; + } + + /** + * 给go推送股票指数代码 + * @param $code + * @param $country + * @param $sort + * @param $status + * @return bool + */ + public function sendStockIndexToGo($code, $country, $sort, $status) + { + try { + $client = new Client(); + $url = env('QUOTE.BASE_URL') . '/spots/index/list/new/add'; + $response = $client->request("POST", $url, [ + 'json' => [ + 'ticker' => $code, + 'locale' => $country, + 'state' => $status, + 'sort' => $sort, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + Log::info('给交易推送数据 ' . json_encode([$res, [ + 'url' => $url, + 'ticker' => $code, + 'locale' => $country, + 'state' => $status, + 'sort' => $sort, + ]])); + + + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + return false; + } catch (\Exception $exception) { + Log::error('给行情推送股票指数数据异常1 ' . $exception->getMessage()); + } catch (GuzzleException $e) { + Log::error('给行情推送股票指数数据异常2 ' . $e->getMessage()); + } + + return false; + } + + +} \ No newline at end of file diff --git a/app/admin/service/AdminService.php b/app/admin/service/AdminService.php new file mode 100644 index 0000000..59065ab --- /dev/null +++ b/app/admin/service/AdminService.php @@ -0,0 +1,362 @@ +scene('addUser')->check($param); + // 查找用户是否存在 + $username = $param['user_name']; + $user = AdminModel::getByUserName($username); + if (!empty($user)) { + return $this->toData('200100', '该用户已存在', []); + } + $param['password'] = (new UnqId())->encryptPassword($param['password'], env('ENCRYPT.ADMINSALT')); + $param['invite_code'] = (new BaseHomeService())->getUniqInviteCode(); + + AdminModel::create($param); + return $this->toData('0', '添加成功.', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', '系统繁忙.', [$exception->getMessage()]); + } + + } + + /** + * 获取用户列表 + * @return array + */ + public function getUserList($param) + { + try { + $adminModel = new AdminModel(); + //查询条件 + if (isset($param['user_name']) && !empty($param['user_name'])) { + $adminModel = $adminModel->where('user_name', $param['user_name']); + } + if (isset($param['nick_name']) && !empty($param['nick_name'])) { + $adminModel = $adminModel->where('nick_name', $param['nick_name']); + } + + // 总数 + $total = $adminModel->count(); + $list = $adminModel->withoutField('password,token')->order('id', 'asc')->page($param['page'], $param['limit'])->select()->toArray(); + $roleIds = array_column($list, "role_id"); + $roleList = AuthRoleModel::where('id', 'in', $roleIds)->field('id,name')->select()->toArray(); + $host = Request::host(); + $host = str_replace('api.', '', $host); + if (!empty($list)) { + for ($i = 0; $i < count($list); $i++) { + $index = array_search($list[$i]['role_id'], array_column($roleList, 'id')); + + if ($index !== false) { + $list[$i]['role_name'] = $roleList[$index]['name']; + } + + $list[$i]['url'] = $host . '/register/index?=agent_code='.$list[$i]['invite_code']; + } + } + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $list]); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * @desc 获取用户信息 + * @param $userId + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function getUserInfo($userId) + { + + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first', []); + } + $info = AdminModel::find($userId); + + if (empty($info)) { + return $this->toData('100400', 'The user does not exist.', []); + } + // 返回数据 + return $this->toData('0', 'Modification successful.', $info->toArray()); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + /** + * @desc 设置用户信息 + * @param $userId + * @param $param + * @return array + */ + public function updateInfo($userId, $param): array + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('200403', 'Please log in first.', []); + } + // 参数校验 + validate(AdminValidate::class)->scene('updateInfo')->check($param); + // 查找用户信息 + $user = AdminModel::find($userId); + if (empty($user)) { + return $this->toData('200403', 'Please log in first.', []); + } + + $user['nick_name'] = $param['nick_name']; + $user['email'] = $param['email']; + $user['mobile'] = isset($param['mobile']) ? $param['mobile'] : null; + $user['desc'] = isset($param['desc']) ? $param['mobile'] : null; + $user->save(); + // 返回 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('200400', $message); + } catch (\Exception $exception) { + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * 编辑账号信息 + * @param $accountId + * @param $param + * @return array + */ + public function updateAccount($accountId, $param): array + { + try { + // 主键 + if (empty($accountId) || $accountId <= 0) { + return $this->toData('200404', 'accountId lose.', []); + } + // 参数校验 + validate(AdminValidate::class)->scene('updateAccount')->check($param); + // 查找用户信息 + $user = AdminModel::find($accountId); + if (empty($user)) { + return $this->toData('200403', '不存在该用户.', []); + } + if (isset($param['password'])) { + $user['password'] = (new UnqId())->encryptPassword($param['password'], env('ENCRYPT.ADMINSALT')); + } + $user['role_id'] = $param['role_id']; + $user['user_name'] = $param['user_name']; + $user['nick_name'] = $param['nick_name']; + $user['email'] = isset($param['email']) ? $param['email'] : null; + $user['remark'] = isset($param['remark']) ? $param['remark'] : null; + $user->save(); + // 返回 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('200400', $message); + } catch (\Exception $exception) { + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + public function updateAccountStauts($accountId, $param): array + { + try { + // 主键 + if (empty($accountId) || $accountId <= 0) { + return $this->toData('200404', 'accountId lose.', []); + } + // 参数校验 + validate(AdminValidate::class)->scene('updateAccountStatus')->check($param); + // 查找用户信息 + $user = AdminModel::find($accountId); + if (empty($user)) { + return $this->toData('200403', 'Please log in first.', []); + } + $user['status'] = $param['status']; + $user->save(); + // 返回 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('200400', $message); + } catch (\Exception $exception) { + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + + public function updatePassword($userId, $param): array + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('200403', 'Please log in first.', []); + } + + // 参数校验 + validate(AdminValidate::class)->scene('updatePassword')->check($param); + // 查找用户信息 + $user = AdminModel::find($userId); + if (empty($user)) { + return $this->toData('200403', 'Please log in first.', []); + } + //检查原始密码 + $flag = (new UnqId())->checkPassword($param['old_password'], $user['password'], env('ENCRYPT.ADMINSALT')); + if (!$flag) { + return $this->toData('200401', '原始密码错误', []); + } + //设置新密码 + $newPassword = (new UnqId())->encryptPassword($param['new_password'], env('ENCRYPT.ADMINSALT')); + $user['password'] = $newPassword; + $user->save(); + // 返回 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('200400', $message); + } catch (\Exception $exception) { + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + public function del($id): array + { + try { + $adminModel = AdminModel::find($id); + $adminModel->delete(); + // 返回 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('200400', $message); + } catch (\Exception $exception) { + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * 查询用户权限代码 + * @param $id + * @return array + */ + public function getPermCode($id): array + { + try { + $adminModel = AdminModel::find($id); + //根据角色查询权限代码 + $roleModel = AuthRoleModel::find($adminModel->role_id); + $rules = $roleModel->rules; + if ($rules) { + $rules = explode(",", $rules); + //字符串转换为数字类型 +// $rules=array_map(function ($value){ +// return (int)$value; +// },$rules); + } + // 返回 + return $this->toData('0', 'Modification successful.', $rules); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('200400', $message); + } catch (\Exception $exception) { + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + } + + + /** + * @desc 退出登陆 + * @param $userId + * @return array + */ + public function logout($userId) + { + try { + // 获取用户 + $user = AdminModel::find($userId); + if (empty($user)) { + return $this->toData('200300', '用户不存在', []); + } + $user->token = ""; + $user->save(); + return $this->toData('0', 'Modification successful.'); + } catch (\Exception $exception) { + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + public function logList($param) + { + try { + $adminLogModel = new AdminLogModel(); + //查询条件 + if (!empty($param['create_date'])) { + $adminLogModel = $adminLogModel->where('create_date', $param['create_date']); + } + + // 总数 + $total = $adminLogModel->count(); + $list = $adminLogModel->order('id', 'desc')->page($param['page'], $param['limit'])->select()->toArray(); + $accountIds = array_column($list, "admin_id"); + $accountList = AdminModel::where('id', 'in', $accountIds)->column('user_name', 'id'); +// $menuList = AuthRuleModel::column('title', 'path'); + if (!empty($list)) { + foreach ($list as &$v) { + $v['admin_name'] = $accountList[$v['admin_id']] ?? '-'; + $v['path_text'] = '用户上分'; + } + } + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $list]); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function inviteCode() + { + try { + $user = AdminModel::select(); + foreach ($user as $v){ + $inviteCode = (new BaseHomeService())->getUniqInviteCode(); + AdminModel::where('id',$v->id)->update(['invite_code'=>$inviteCode]); + } + + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + +} diff --git a/app/admin/service/AgentService.php b/app/admin/service/AgentService.php new file mode 100644 index 0000000..b23de38 --- /dev/null +++ b/app/admin/service/AgentService.php @@ -0,0 +1,154 @@ +column('uid'); + $roleId = 10; + $agentAdminUser = AdminModel::where('role_id', 'in', $roleId)->field('id,user_name,nick_name,email,mobile,status,invite_code')->select(); + $rows = []; + if (!$agentAdminUser->isEmpty()) { + foreach ($agentAdminUser as $item) { + $rows[] = [ + 'id' => $item['id'], + 'username' => $item['user_name'], + 'nickname' => $item['nick_name'], + 'email' => $item['email'] ?? '-', + 'mobile' => $item['mobile'] ?? '-', + 'status' => $item['status'], + 'invite_code' => $item['invite_code'], + ]; + } + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 代理用户 + public function user($param) + { + try { + if (empty($param['agent_id'])) { + return $this->toData('0', 'SUCCESS', ['list' => []]); + } + + $userList = UserModel::where('agent_id', 'in', [0, $param['agent_id']])->where('parent_id', 0) + ->order('user_id', 'desc') + ->select(); + $rows = []; + if (!$userList->isEmpty()) { + foreach ($userList as $item) { + $rows[] = [ + 'id' => $item['user_id'], + 'email' => $item['email'], + 'user_no' => $item['user_no'], + 'status' => $item['agent_id'] == $param['agent_id'], + 'agent_id' => $param['agent_id'], + ]; + } + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function manager($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '参错错误', ['list' => []]); + } + + if (empty($param['agent_id']) || !is_numeric($param['agent_id'])) { + return $this->toData('1', '参错错误', ['list' => []]); + } + + $user = UserModel::where('user_id', $param['id'])->find(); + if (empty($user)) { + return $this->toData('1', '用户不存在', ['list' => []]); + } + + if ($user['parent_id'] != 0) { + return $this->toData('1', '只能绑定顶层用户', ['list' => []]); + } + + // 判断代理是否有效 + $admin = AdminModel::where('id', $param['agent_id'])->find(); + $roleId = 10; + if (empty($admin) || $admin['role_id'] != $roleId) { + return $this->toData('1', '代理不存在', ['list' => []]); + } + +// $agentUserId = env('AGENT.AGENT_GROUP_ID'); +// $agentAdminUserIds = AuthGroupAccessModel::where('group_id', $agentUserId)->column('uid'); +// if(!in_array($param['agent_id'], $agentAdminUserIds)){ +// return $this->toData('1', '代理不存在', ['list' => []]); +// } + + // 未绑定 直接绑定 + if ($user->agent_id == 0) { + UserModel::update(['agent_id' => $param['agent_id']], ['user_id' => $param['id']]); + return $this->toData('0', 'SUCCESS', []); + } + + // 取消绑定 + if ($user->agent_id == $param['agent_id']) { + UserModel::update(['agent_id' => 0], ['user_id' => $param['id']]); + return $this->toData('0', 'SUCCESS', []); + } + + return $this->toData('1', '该用户已被其他代理绑定, 请先取消绑定', []); + + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function addUser($param) + { + try { + if (empty($param['agent_id']) || !is_numeric($param['agent_id'])) { + return $this->toData('1', '参错错误'); + } + + if (empty($param['user_id']) || !is_numeric($param['user_id'])) { + return $this->toData('1', '参错错误'); + } + + $user = UserModel::where('user_id', $param['user_id'])->find(); + if (empty($user)) { + return $this->toData('1', '用户不存在'); + } + + if ($user['parent_id'] != 0) { + return $this->toData('1', '只能绑定顶层用户'); + } + + // 判断代理是否有效 + $admin = AdminModel::where('id', $param['agent_id'])->find(); + $roleId = 10; + if (empty($admin) || $admin['role_id'] != $roleId) { + return $this->toData('1', '代理不存在'); + } + + UserModel::update(['agent_id' => $param['agent_id']], ['user_id' => $param['user_id']]); + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/FlowService.php b/app/admin/service/FlowService.php new file mode 100644 index 0000000..28cbc0d --- /dev/null +++ b/app/admin/service/FlowService.php @@ -0,0 +1,951 @@ +scene('digital')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserDigitalLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + // 交易对 + if (!empty($param['digital_id'])) { + $where['digital_id'] = $param['digital_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserDigitalLogModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserDigitalLogModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr)]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', []); + } + } + + public function stock($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserStockLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['stock_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserStockLogModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserStockLogModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr)]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function contract($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('contract')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserContractLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserContractLogModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserContractLogModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr)]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function forex($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('forex')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserForexLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserForexLogModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserForexLogModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr)]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function transfer($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('transfer')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + if (!empty($param['change_type'])) $where['change_type'] = $param['change_type']; + + + // 转出 转入账户 + if (!empty($param['from_account'])) { + $where['from_account'] = $param['from_account']; + } + + if (!empty($param['to_account'])) { + $where['to_account'] = $param['to_account']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserTransferModel::where($where)->where($whereU)->order('tran_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserTransferModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function fee($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('fee')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + if (!empty($param['change_type'])) $where['change_type'] = $param['change_type']; + + + // 账户类型 + if (!empty($param['account_type'])) { + $where['account_type'] = $param['account_type']; + } + + // 交易类型 + if (!empty($param['trade_type'])) { + $where['trade_type'] = $param['trade_type']; + } + + // 交易单号 + if (!empty($param['trade_no'])) { + $where['trade_no'] = $param['trade_no']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = TradeFeeModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = TradeFeeModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function brokerage($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('brokerage')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + if (!empty($param['change_type'])) $where['change_type'] = $param['change_type']; + + + // 返佣级别 + if (!empty($param['level_type'])) { + $where['level_type'] = $param['level_type']; + } + + // 返佣类型 + if (!empty($param['back_type'])) { + $where['back_type'] = $param['back_type']; + } + + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserBrokerageModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserBrokerageModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + ######################################## 美股资产流水 ################################ + + + // 基金流水 + public function fundStock($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('fund_stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserStockFundLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['stock_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserStockFundLogModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserStockFundLogModel::where($where)->where($whereU)->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'change_type_list' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr) + ]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage()]); + } + } + + + // 香港股票 + public function StockLogs($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('us_stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserStockHkdLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + $market_type=intval($param['market_type']); + $table_obj=(new IPOService())->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['stock_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = Db::table($table_obj['log_table'])->where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = Db::table($table_obj['log_table'])->where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'change_type_list' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr) + ]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(),$exception->getTrace()]); + } + } + + // 印度期权 + public function inOptionStock($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('hk_stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserStockOptionInrLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['stock_id']; + } + + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserStockOptionInrLogModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserStockOptionInrLogModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'change_type_list' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr) + ]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage()]); + } + } + + // 香股 + public function blockStock($param, $adminId) + { + try { + // 参数校验 + validate(FlowValidate::class)->scene('block_stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserStockBlockLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['stock_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserStockBlockLogModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserStockBlockLogModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'change_type_list' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr) + ]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage()]); + } + } + + public function forexList($param, $adminId){ + try { + // 参数校验 + validate(FlowValidate::class)->scene('block_stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserForexLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['stock_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserForexLogModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserForexLogModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'change_type_list' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr) + ]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage()]); + } + } + + public function allList($param, $adminId){ + try { + // 参数校验 + validate(FlowValidate::class)->scene('block_stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $changeTypeArr = UserMoneyLogModel::group('change_type')->column('change_type'); + + if (!empty($param['change_type']) && in_array($param['change_type'], $changeTypeArr)) $where['change_type'] = $param['change_type']; + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['stock_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserMoneyLogModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserMoneyLogModel::where($where)->where($whereU) + ->count(); + + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'change_type_list' => (new BaseHomeService())->getCapitalTypeList($changeTypeArr) + ]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/LoginService.php b/app/admin/service/LoginService.php new file mode 100644 index 0000000..1369186 --- /dev/null +++ b/app/admin/service/LoginService.php @@ -0,0 +1,100 @@ +scene('login')->check($param); + + // 获取用户 + $info = AdminModel::getByUserName($param['user_name']); + if(empty($info)){ + return $this->toData('200300', 'Incorrect account or password.1', []); + } + if($info->status!==1){ + return $this->toData('200300', '该账户已被禁用', []); + } + //查看角色状态 + $role=AuthRoleModel::find($info->role_id); + if(!$role||$role->status!==1){ + return $this->toData('200300', '该账户所在的群组已被禁用', []); + } + // 校验密码 + $checkPasswordBool = (new UnqId())->checkPassword($param['password'], $info->password,env('ENCRYPT.ADMINSALT')); + + if(!$checkPasswordBool){ + return $this->toData('200300', 'Incorrect account or password.3', []); + } + $token = (new Jwt())->generateToken($info->id); + + if(empty($token)){ + return $this->toData('200400', 'The system is busy. Please try again later.1', []); + } + + //保存token + $info->token=$token; + $info->save(); + +// $key = 'TOKEN:USER:'.$token; +// $expired = 3600*24; +// Cache::store('redis')->set($key, 9999999999, $expired); + + $info=$info->toArray(); + $this->setUserTokenCache($token, $info['id']); + + // 返回结果以及用户信息 + return $this->toData('0', 'Request successful.', [ + 'id' => $info['id'], + 'nickname' => $info['nick_name'], + 'email' => $info['email'], + 'token' => $token, + ]); + }catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + }catch (\Exception $exception){ + + return $this->toData('200500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function setUserTokenCache($token, $userId) + { + // 清除之前的token 设置新的token + $userTokenKey = 'USER:TOKEN:'.$userId; // 根据用户id 查找token + $oldToken = Cache::store('redis')->get($userTokenKey); + if($oldToken){ + $oldTokenKey = 'TOKEN:USER:'.$oldToken; + Cache::store('redis')->delete($oldTokenKey); + } + + //trace('---设置用户登陆凭证--'.$userId.'----'.$token, 'error'); + + $tokenKey = 'TOKEN:USER:'.$token; // 根据token查找用户id + $expired = 30 * 24 * 60 * 60; + // 由中间件自动续期 + Cache::store('redis')->set($tokenKey, $userId, $expired); + Cache::store('redis')->set($userTokenKey, $token, $expired); + + } + +} \ No newline at end of file diff --git a/app/admin/service/OrderService.php b/app/admin/service/OrderService.php new file mode 100644 index 0000000..69f1ebc --- /dev/null +++ b/app/admin/service/OrderService.php @@ -0,0 +1,2898 @@ +scene('digitalPlace')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($where)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + if (!empty($where['user_id']) && is_numeric($where['user_id']) && $where['user_id'] == 0) { + return $this->toData('1', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0, + ]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['digital_id'])) { + $where['digital_id'] = $param['digital_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = DigitalTradeModel::where('status', DigitalTradeModel::STATUS_PLACE)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = DigitalTradeModel::where('status', DigitalTradeModel::STATUS_PLACE) + ->where($where) + ->count(); + // 持仓总金额 + $totalModel = DigitalTradeModel::where('status', DigitalTradeModel::STATUS_PLACE) + ->field('SUM(order_money) as total') + ->where($where)->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'trade_id' => $item['trade_id'], // + 'trade_type' => $item['trade_type'], // + 'trade_type_name' => $item['trade_type'] == DigitalTradeModel::TRADE_TYPE_BUY ? '买入' : '卖出', //交易类型 + 'create_time' => $item['create_time'], // 挂单时间 + 'order_money' => $item['order_money'], // 订单金额 + 'digital_id' => $item['digital_id'], // 股票代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'deal_price' => $item['deal_price'], // 开仓价 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + // 现货撤单 + public function digitalBack($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('digitalBack')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['digital_id'])) { + $where['digital_id'] = $param['digital_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = DigitalTradeModel::where('status', DigitalTradeModel::STATUS_BACk) + ->where($where)->where($whereU) + ->order('trade_id', 'desc') + ->page($param['page'], $param['limit'])->select(); + // 总数 + $total = DigitalTradeModel::where('status', DigitalTradeModel::STATUS_BACk) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = DigitalTradeModel::where('status', DigitalTradeModel::STATUS_BACk) + ->field('SUM(order_money) as total') + ->where($where)->where($whereU)->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'order_id' => $item['order_id'], // 用户号 + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'trade_type' => $item['trade_type'], // + 'trade_type_name' => $item['trade_type'] == DigitalTradeModel::TRADE_TYPE_BUY ? '买入' : '卖出', //交易类型 + 'create_time' => $item['create_time'], // 挂单时间 + 'update_time' => $item['update_time'], // 撤单时间 + 'order_money' => $item['order_money'], // 订单金额 + 'digital_id' => $item['digital_id'], // 股票代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'deal_price' => $item['deal_price'], // 开仓价 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + // 现货订单 + public function digitalDeal($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('digitalDeal')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['digital_id'])) { + $where['digital_id'] = $param['digital_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = DigitalTradeModel::where('status', DigitalTradeModel::STATUS_SUCCESS) + ->where($where)->where($whereU) + ->order('trade_id', 'desc') + ->page($param['page'], $param['limit'])->select(); + // 总数 + $total = DigitalTradeModel::where('status', DigitalTradeModel::STATUS_SUCCESS) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = DigitalTradeModel::where('status', DigitalTradeModel::STATUS_SUCCESS) + ->field('SUM(order_money) as total') + ->where($where)->where($whereU)->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'order_id' => $item['order_id'], // 用户号 + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'trade_type' => $item['trade_type'], // + 'trade_type_name' => $item['trade_type'] == DigitalTradeModel::TRADE_TYPE_BUY ? '买入' : '卖出', //交易类型 + 'create_time' => $item['create_time'], // 挂单时间 + 'closing_time' => $item['closing_time'], // 完成时间 + 'order_money' => $item['order_money'], // 订单金额 + 'digital_id' => $item['digital_id'], // 股票代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['closing_cost'], // 服务费 + 'deal_price' => $item['closing_price'], // 平仓价 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + + ######################################## 外汇交易 ####################################### + + // 合约持仓 + public function forexHold($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('forexHold')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_HOLD)->where($where)->where($whereU)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_HOLD) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_HOLD) + ->field('SUM(order_money) as total') + ->where($where)->where($whereU)->find(); + + // 持仓总手续费 + $totalServiceCost = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_HOLD) + ->where($where)->where($whereU) + ->sum('service_cost'); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'open_time' => $item['open_time'], // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $item['order_money'], // 订单金额 + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'float' => '-', // 浮动盈亏 + 'face_value' => $item['face_value'], // 浮动盈亏 + 'deal_price' => $item['deal_price'], // 开仓价 + 'now_price' => '-', // 当前价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), 'totalServiceCost' => $totalServiceCost, + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 合约持仓 + public function forexPlace($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('forexPlace')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_PLACE)->where($where)->where($whereU)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = MoneyTradeModel::where('status', ForexTradeModel::STATUS_PLACE) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_PLACE) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'order_id' => $item['order_id'], // 订单号 + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'order_money' => $item['order_money'], // 订单金额 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'deal_price' => $item['deal_price'], // 开仓价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'face_value' => $item['face_value'], // 面值 + 'pry_num' => $item['pry_num'], // 杠杆 + 'limit_price' => $item['limit_price'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 合约撤单 + public function forexBack($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('forexBack')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['update_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_BACK)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_BACK) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_BACK) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'update_time' => $item['update_time'], // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $item['order_money'], // 订单金额 + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'face_value' => $item['face_value'], // 浮动盈亏 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'price' => $item['deal_type'] == 1 ? $item['limit_price'] : $item['market_price'], // 价格 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 合约持仓 + public function forexClear($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('forexClear')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_CLEAR)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_CLEAR)->where($whereU) + ->where($where) + ->count(); + + // 持仓总手续费 + $totalClosingCost = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_CLEAR) + ->where($whereU) + ->where($where) + ->sum('closing_cost'); + + $totalFloat = MoneyTradeModel::where('status', MoneyTradeModel::STATUS_CLEAR) + ->where($whereU) + ->where($where) + ->field("SUM( CASE WHEN trade_type = 1 THEN ( closing_price - deal_price )* order_number ELSE ( deal_price - closing_price )* order_number END ) AS total")->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + // 计算浮动盈亏 + if ($item['trade_type'] == 1) { + $float = $item['closing_price'] - $item['deal_price']; + } else { + $float = $item['deal_price'] - $item['closing_price']; + } + + // * 仓位 + $float = @bcmul($float, $item['order_number'], 10); + // * 面值 + $float = @bcmul($float, $item['face_value'], 6); + + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'closing_time' => $item['closing_time'], // 平仓时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $item['order_money'], // 订单金额 + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'closing_cost' => $item['closing_cost'], // 平仓服务费 + 'face_value' => $item['face_value'], // + 'deal_price' => $item['deal_price'], // 开仓价 + 'closing_price' => $item['closing_price'], // 平仓价格 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'float' => $float, // 平仓盈亏 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => [ + 'totalClosingCost' => $totalClosingCost, + 'totalFloat' => $totalFloat['total'], + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + ######################################## 合约交易 ####################################### + + // 合约持仓 + public function contractHold($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('contractHold')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = ContractTradeModel::where('status', ContractTradeModel::STATUS_HOLD)->where($where)->where($whereU)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = ContractTradeModel::where('status', ContractTradeModel::STATUS_HOLD) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = ContractTradeModel::where('status', ContractTradeModel::STATUS_HOLD) + ->field('SUM(order_money) as total') + ->where($where)->where($whereU)->find(); + + // 持仓总手续费 + $totalServiceCost = ContractTradeModel::where('status', ContractTradeModel::STATUS_HOLD) + ->where($where)->where($whereU) + ->sum('service_cost'); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'open_time' => $item['open_time'], // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $item['order_money'], // 订单金额 + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'float' => '-', // 浮动盈亏 + 'face_value' => $item['face_value'], // 浮动盈亏 + 'deal_price' => $item['deal_price'], // 开仓价 + 'now_price' => '-', // 当前价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), 'totalServiceCost' => $totalServiceCost, + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 合约持仓 + public function contractPlace($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('contractPlace')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = ContractTradeModel::where('status', ContractTradeModel::STATUS_PLACE)->where($where)->where($whereU)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = ContractTradeModel::where('status', ContractTradeModel::STATUS_PLACE) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = ContractTradeModel::where('status', ContractTradeModel::STATUS_PLACE) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'order_id' => $item['order_id'], // 订单号 + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'order_money' => $item['order_money'], // 订单金额 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'deal_price' => $item['deal_price'], // 开仓价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'face_value' => $item['face_value'], // 面值 + 'pry_num' => $item['pry_num'], // 杠杆 + 'limit_price' => $item['limit_price'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 合约撤单 + public function contractBack($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('contractBack')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['update_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = ContractTradeModel::where('status', ContractTradeModel::STATUS_BACK)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = ContractTradeModel::where('status', ContractTradeModel::STATUS_BACK) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = ContractTradeModel::where('status', ContractTradeModel::STATUS_BACK) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'update_time' => $item['update_time'], // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $item['order_money'], // 订单金额 + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'face_value' => $item['face_value'], // 浮动盈亏 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'price' => $item['deal_type'] == 1 ? $item['limit_price'] : $item['market_price'], // 价格 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 合约持仓 + public function contractClear($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('contractClear')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = ContractTradeModel::where('status', ContractTradeModel::STATUS_CLEAR)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = ContractTradeModel::where('status', ContractTradeModel::STATUS_CLEAR)->where($whereU) + ->where($where) + ->count(); + + // 持仓总手续费 + $totalClosingCost = ContractTradeModel::where('status', ContractTradeModel::STATUS_CLEAR) + ->where($whereU) + ->where($where) + ->sum('closing_cost'); + + $totalFloat = ContractTradeModel::where('status', ContractTradeModel::STATUS_CLEAR) + ->where($whereU) + ->where($where) + ->field("SUM( CASE WHEN trade_type = 1 THEN ( closing_price - deal_price )* order_number ELSE ( deal_price - closing_price )* order_number END ) AS total")->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + // 计算浮动盈亏 + if ($item['trade_type'] == 1) { + $float = $item['closing_price'] - $item['deal_price']; + } else { + $float = $item['deal_price'] - $item['closing_price']; + } + + // * 仓位 + $float = @bcmul($float, $item['order_number'], 10); + // * 面值 + $float = @bcmul($float, $item['face_value'], 6); + + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'closing_time' => $item['closing_time'], // 平仓时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $item['order_money'], // 订单金额 + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'closing_cost' => $item['closing_cost'], // 平仓服务费 + 'face_value' => $item['face_value'], // + 'deal_price' => $item['deal_price'], // 开仓价 + 'closing_price' => $item['closing_price'], // 平仓价格 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'float' => $float, // 平仓盈亏 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => [ + 'totalClosingCost' => $totalClosingCost, + 'totalFloat' => $totalFloat['total'], + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + ######################################## 秒合约交易 ####################################### + + // 合约持仓 + public function contractSecHold($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('contractHold')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_HOLD)->where($where)->where($whereU)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_HOLD) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_HOLD) + ->field('SUM(order_money) as total') + ->where($where)->where($whereU)->find(); + + // 持仓总手续费 + $totalServiceCost = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_HOLD) + ->where($where)->where($whereU) + ->sum('service_cost'); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'open_time' => $item['open_time'], // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $item['order_money'], // 订单金额 + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'float' => '-', // 浮动盈亏 + 'face_value' => $item['face_value'], // 浮动盈亏 + 'deal_price' => $item['deal_price'], // 开仓价 + 'now_price' => '-', // 当前价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), 'totalServiceCost' => $totalServiceCost, + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 合约持仓 + public function contractSecPlace($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('contractPlace')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_PLACE)->where($where)->where($whereU)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_PLACE) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_PLACE) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'order_id' => $item['order_id'], // 订单号 + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'order_money' => $item['order_money'], // 订单金额 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'deal_price' => $item['deal_price'], // 开仓价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'face_value' => $item['face_value'], // 面值 + 'pry_num' => $item['pry_num'], // 杠杆 + 'limit_price' => $item['limit_price'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 合约撤单 + public function contractSecBack($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('contractBack')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['update_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_BACK)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_BACK) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_BACK) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'update_time' => $item['update_time'], // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $item['order_money'], // 订单金额 + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'face_value' => $item['face_value'], // 浮动盈亏 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'price' => $item['deal_type'] == 1 ? $item['limit_price'] : $item['market_price'], // 价格 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 合约持仓 + public function contractSecClear($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('contractClear')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_CLEAR)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_CLEAR)->where($whereU) + ->where($where) + ->count(); + + // 持仓总手续费 + $totalClosingCost = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_CLEAR) + ->where($whereU) + ->where($where) + ->sum('closing_cost'); + + $totalFloat = ContractSecTradeModel::where('status', ContractSecTradeModel::STATUS_CLEAR) + ->where($whereU) + ->where($where) + ->field("SUM( CASE WHEN trade_type = 1 THEN ( closing_price - deal_price )* order_number ELSE ( deal_price - closing_price )* order_number END ) AS total")->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + // 计算浮动盈亏 + if ($item['trade_type'] == 1) { + $float = $item['closing_price'] - $item['deal_price']; + } else { + $float = $item['deal_price'] - $item['closing_price']; + } + + // * 仓位 + $float = @bcmul($float, $item['order_number'], 10); + // * 面值 + $float = @bcmul($float, $item['face_value'], 6); + + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'closing_time' => $item['closing_time'], // 平仓时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $item['order_money'], // 订单金额 + 'contract_id' => $item['contract_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'closing_cost' => $item['closing_cost'], // 平仓服务费 + 'face_value' => $item['face_value'], // + 'deal_price' => $item['deal_price'], // 开仓价 + 'closing_price' => $item['closing_price'], // 平仓价格 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'float' => $float, // 平仓盈亏 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => [ + 'totalClosingCost' => $totalClosingCost, + 'totalFloat' => $totalFloat['total'], + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + ########################################## 股票交易 ########################################### + // 股票持仓 + public function StockHold($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('stockHold')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $market_type = intval($param['market_type']); + $table_obj = (new IPOService())->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = Db::table($table_obj['trade_table'])->where('status', 1)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = Db::table($table_obj['trade_table'])->where('status', 1) + ->where($whereU) + ->where($where) + ->count(); + // 持仓总金额 + $totalModel = Db::table($table_obj['trade_table'])->where('status', 1) + ->field('SUM(order_money) as total') + ->where($whereU) + ->where($where)->find(); + + // 持仓总手续费 + $totalServiceCost = Db::table($table_obj['trade_table'])->where('status', 1) + ->where($whereU) + ->where($where) + ->sum('service_cost'); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $orderNumber = number_format($item['order_number'], '18', '.', ''); + $orderPrice = number_format($item['deal_price'], '18', '.', ''); + $orderAmount = bcmul($orderNumber, $orderPrice, 18); + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'open_time' => $item['open_time'] ?? '-', // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $orderAmount, // 订单金额 + 'stock_id' => $item['stock_id'], // 股票代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'float' => '-', // 浮动盈亏 + 'deal_price' => $item['deal_price'], // 开仓价 + 'now_price' => '-', // 当前价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), 'totalServiceCost' => $totalServiceCost, + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 股票挂单 + public function StockPlace($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('stockPlace')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + $market_type = intval($param['market_type']); + $table_obj = (new IPOService())->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + + // 列表 + $list = Db::table($table_obj['trade_table'])->where('status', 0)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = Db::table($table_obj['trade_table'])->where('status', 0) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = Db::table($table_obj['trade_table'])->where('status', 0) + ->field('SUM(order_money) as total') + ->where($where)->where($whereU)->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + // 挂单价 + $price = $item['limit_price']; + if ($item['deal_type'] == 2) { + $price = $item['market_price']; + } + + $orderNumber = number_format($item['order_number'], '18', '.', ''); + $orderPrice = number_format($price, '18', '.', ''); + $orderAmount = bcmul($orderNumber, $orderPrice, 18); + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'order_id' => $item['order_id'], // 订单号 + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'order_money' => $orderAmount, // 订单金额 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'stock_id' => $item['stock_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'deal_price' => $price, // 委托价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'limit_price' => $item['limit_price'], // 限价 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 股票撤单 + public function StockBack($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('stockBack')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $market_type = intval($param['market_type']); + $table_obj = (new IPOService())->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['update_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = Db::table($table_obj['trade_table'])->where('status', 2)->where($where)->where($whereU)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = Db::table($table_obj['trade_table'])->where('status', 2) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = Db::table($table_obj['trade_table'])->where('status', 2) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + // 挂单价 + $price = $item['limit_price']; + if ($item['deal_type'] == 2) { + $price = $item['market_price']; + } + $orderNumber = number_format($item['order_number'], '18', '.', ''); + $orderPrice = number_format($price, '18', '.', ''); + $orderAmount = bcmul($orderNumber, $orderPrice, 18); + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'update_time' => $item['update_time'], // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $orderAmount, // 订单金额 + 'stock_id' => $item['stock_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'deal_price' => $price, // 委托价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 股票平仓 + public function StockClear($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('us_stockClear')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + $market_type = intval($param['market_type']); + $table_obj = (new IPOService())->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + + // 列表 + $list = Db::table($table_obj['trade_table'])->where('status', 3)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = Db::table($table_obj['trade_table'])->where('status', 3) + ->where($where)->where($whereU) + ->count(); + + // 持仓总手续费 + $totalClosingCost = Db::table($table_obj['trade_table'])->where('status', 3) + ->where($whereU) + ->where($where) + ->sum('closing_cost'); + + $totalFloat = Db::table($table_obj['trade_table'])->where('status', 3) + ->where($whereU) + ->where($where) + ->field("SUM( CASE WHEN trade_type = 1 THEN ( closing_price - deal_price )* order_number ELSE ( deal_price - closing_price )* order_number END ) AS total")->find(); + + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + // 计算浮动盈亏 + if ($item['trade_type'] == 1) { + $float = $item['closing_price'] - $item['deal_price']; + } else { + $float = $item['deal_price'] - $item['closing_price']; + } + + $orderNumber = number_format($item['order_number'], '18', '.', ''); + $orderPrice = number_format($item['deal_price'], '18', '.', ''); + $float = number_format($float, '18', '.', ''); + + $float = bcmul($float, $item['order_number'], 18); + $orderAmount = bcmul($orderNumber, $orderPrice, 18); + + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'closing_time' => $item['closing_time'], // 平仓时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $orderAmount, // 订单金额 + 'stock_id' => $item['stock_id'], // 股票代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'closing_cost' => $item['closing_cost'], // 平仓服务费 + 'deal_price' => $item['deal_price'], // 开仓价 + 'closing_price' => $item['closing_price'], // 平仓价格 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'float' => $float, // 平仓盈亏 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => [ + 'totalClosingCost' => $totalClosingCost, + 'totalFloat' => $totalFloat['total'], + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + ################################################# 申购订单 + + // 申购订单 + public function preStock($marketType, $param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('pre_stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_no'])) { + $where['order_no'] = $param['order_no']; + } + + $tableObj = (new IPOService)->getStockModel($marketType); + + if (!empty($param['stock_code'])) { + $stockArr = Db::table($tableObj['stock_table'])->where('stock_code', 'like', '%' . $param['stock_code'])->column('id'); + if (!empty($stockArr)) { + $where[] = ['pre_stock_id', 'in', $stockArr]; + } + } + $list = Db::table($tableObj['order_table'])->where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + $total = Db::table($tableObj['order_table'])->where($where)->where($whereU)->count(); + + + $stockTape=(new IPOService)->getStockTape($marketType); + $tapeList = $stockTape['tape']; + $stockTypeList = $stockTape['type']; + $statusList = UserUsPreStockOrderModel::$statusList; + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + // stock + $preStockId = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + $preStockId[] = $idItem['pre_stock_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + $stockArr = Db::table($tableObj['stock_table'])->where('id', 'in', $preStockId)->column('*', 'id'); + + $rows = $list->toArray(); + foreach ($rows as $key => $item) { + $stock = $stockArr[$item['pre_stock_id']] ?? []; + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + $rows[$key]['stock_code'] = $stock['stock_code'] ?? '-'; + $rows[$key]['stock_name'] = $stock['stock_name'] ?? '-'; + $rows[$key]['stock_type'] = $stock['stock_type'] ?? '-'; + $rows[$key]['tape'] = $stock['stock_type'] ?? '-'; + $rows[$key]['rate'] = $stock['rate'] ?? '-'; + $rows[$key]['open_time'] = $stock['open_time'] ?? '-'; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'tape_list' => $tapeList, + 'stock_type_list' => $stockTypeList, + 'status_list' => $statusList + ]]); + + } catch + (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 申购订单 - 修改中签数 + public function updateGetNum($marketType, $param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', 'id参数错误'); + } + + if (!is_numeric($param['get_num'])) { + return $this->toData('1', 'get_num参数错误'); + } + + $tableObj = (new IPOService)->getStockModel($marketType); + $order = Db::table($tableObj['order_table'])->where('id', $param['id'])->find(); + if (empty($order)) return $this->toData('1', 'id参数错误'); + + if (in_array($order['status'], [7, 8])) return $this->toData('1', '订单已退款,不可操作'); + + if ($param['get_num'] > $order['num']) { + return $this->toData('1', '修改中签数不能大于订单申购数'); + } + + $getTime = Db::table($tableObj['stock_table'])->where('id', $order['pre_stock_id'])->value('get_time'); + if (env('USER_ARREARS.HAS_USER_ARREARS') == 1 && $order['pay_type'] == 2 && in_array($order['status'], [5, 6])) { + } else { + if (strtotime($getTime) < time()) return $this->toData('1', 'IPO已中签,无法修改'); + } + + $bool = Db::table($tableObj['order_table'])->where('id', $param['id'])->update([ + 'get_num' => $param['get_num'], + 'get_amount' => $param['get_num'] * $order['price'], + 'get_fee' => $order['get_amount'] * $order['fee_rate'], + 'update_time' => date('Y-m-d H:i:s') + ]); + if (!$bool) return $this->toData('1', '修改失败'); + + return $this->toData('0', 'SUCCESS', []); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 申购订单退款 + public function preRefund($marketType, $param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', 'id参数错误'); + } + $tableObj = (new IPOService)->getStockModel($marketType); + + $order = Db::table($tableObj['order_table'])->where('id', $param['id'])->whereIn('status',[1,2,5,6])->find(); + if (empty($order)) return $this->toData('1', 'id参数错误'); + + + $preStock = Db::table($tableObj['stock_table'])->where('id', $param['id'])->where('is_delete', 1) + ->where('status', 1) + ->where('id', $param['pre_id']) + // 签名状态 + ->where('sign_status', 1) + ->where('open_status', 1) ->find(); + if(empty($preStock)){ + return $this->toData('1', 'IPO未签名或已上市不可退款'); + } + + $now = date('Y-m-d H:i:s'); + $total_num=$order['amount']+$order['fee']; + //查询订单有没有欠款 + $user_arrears=UserArrearsModel::where('order_no', $order['order_no'])->where('status',0)->where('user_id', $order['user_id'])->find(); + + Db::startTrans(); + if($user_arrears){ + $user_arrears=$user_arrears->toArray(); + if($user_arrears['is_add']==1){ + //扣除冻结,不加可用 + $updateNum = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $order['user_id']) + ->where('frozen_num', '>=', $total_num) + ->dec('frozen_num',$total_num) + ->update(['update_time' => $now]); + if(!$updateNum){ + Db::rollback(); + trace('IPO订单退款01-给用户ID:' . $order['user_id'] . "解冻资金异常" . $order['order_no'], 'error'); + return $this->toData('1', '解冻资金异常'); + } + } + $update_bool=UserArrearsModel::where('order_no', $order['order_no'])->where('user_id', $order['user_id']) + ->update([ + 'update_time'=>$now, + 'status'=>1 + ]); + if(!$update_bool){ + Db::rollback(); + trace('IPO订单退款02-给用户ID:' . $order['user_id'] . "更新贷款订单异常" . $order['order_no'], 'error'); + return $this->toData('1', '更新贷款订单异常'); + } + + $status=8; + }else{ + //扣除冻结 加可用 + $updateNum = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $order['user_id']) + ->where('frozen_num', '>=', $total_num) + ->inc('usable_num', $total_num) + ->dec('frozen_num',$total_num) + ->update(['update_time' => $now]); + if(!$updateNum){ + Db::rollback(); + trace('IPO订单退款03-给用户ID:' . $order['user_id'] . "解冻资金异常" . $order['order_no'], 'error'); + return $this->toData('1', '解冻资金异常'); + } + $status=7; + } + + //更新状态 + $bool_status = Db::table($tableObj['order_table'])->where('id', $order['id'])->update([ + 'status' => $status, + 'update_time' => $now + ]); + if (!$bool_status) { + Db::rollback(); + trace('IPO订单退款04-更新订单状态异常' . $order['order_no'], 'error'); + return $this->toData('1', '更新订单状态异常'); + } + //删除缓存订单 + $redis = $this->getRedis(); + $key = "USER:ARREAR:ORDER:" . $order['order_no']; + $redis->del($key); + Db::commit(); + + return $this->toData('0', 'SUCCESS', []); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + ################################################# 基金订单 + //基金订单 + public function fundStock($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('fund_stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_no'])) $where[] = ['order_no', '=', $param['order_no']]; + + // 状态 + if (!empty($param['open_status']) && in_array($param['open_status'], array_keys(PreFundStockModel::$stockTypeList))) $where[] = ['status', '=', $param['status']]; + + if (!empty($param['stock_code'])) { + $stockId = PreFundStockModel::where('stock_code', $param['stock_code'])->value('id'); + $stockId = $stockId ?? 0; + $where[] = ['pre_stock_id', '=', $stockId]; + } + + $list = UserFundPreStockOrderModel::where($whereU)->where($where)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + $total = UserFundPreStockOrderModel::where($whereU)->where($where)->count(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + // stock + $preStockId = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + $preStockId[] = $idItem['pre_stock_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + $stockArr = PreFundStockModel::where('id', 'in', $preStockId)->column('*', 'id'); + + $rows = $list->toArray(); + foreach ($rows as $key => $item) { + $stock = $stockArr[$item['pre_stock_id']] ?? []; + if (empty($stock)) continue; + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + $rows[$key]['stock_code'] = $stock['stock_code'] ?? '-'; + $rows[$key]['stock_name'] = $stock['stock_name'] ?? '-'; + $rows[$key]['stock_type'] = PreFundStockModel::$stockTypeList[$stock['stock_type']] ?? '-'; + $rows[$key]['rate'] = $item['stock_rate'] . "%" ?? '-'; + $rows[$key]['cycle'] = $item['stock_cycle'] . PreFundStockModel::$cycleTypeList[$item['stock_cycle_type']] ?? '-'; + $rows[$key]['open_time'] = $stock['open_time'] ?? '-'; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'tape_list' => [], + 'stock_type_list' => PreFundStockModel::$stockTypeList, + 'cycle_type_list' => PreFundStockModel::$cycleTypeList + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + //基金订单info + public function fundStockInfo($param) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('fund_stock_info')->check($param); + $list = UserStockFundInterestReceiptModel::where('order_id', $param['id'])->append(['status_text'])->select(); + return $this->toData('0', 'SUCCESS', ['list' => $list]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + //基金返息单列表 + public function fundInterestList($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('fund_interest_list')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 状态 + if (!empty($param['status']) && in_array($param['status'], ['1', '2'])) $where[] = ['status', '=', $param['status']]; + + if (!empty($param['stock_code'])) { + $stockId = PreFundStockModel::where('stock_code', $param['stock_code'])->value('id'); + $stockId = $stockId ?? 0; + $where[] = ['pre_stock_id', '=', $stockId]; + } + + $list = UserStockFundInterestReceiptModel::where($whereU)->where($where)->append(['status_text'])->order('status', 'asc')->order('return_date', 'asc')->page($param['page'], $param['limit'])->select(); + $total = UserStockFundInterestReceiptModel::where($whereU)->where($where)->count(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + // stock + $preStockId = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + $orderIdArr[] = $idItem['order_id']; + $preStockId[] = $idItem['pre_stock_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + $orderArr = UserFundPreStockOrderModel::where('id', 'in', $orderIdArr)->column('*', 'id'); + $stockArr = PreFundStockModel::where('id', 'in', $preStockId)->column('*', 'id'); + + $rows = $list->toArray(); + foreach ($rows as $key => $item) { + $order = $orderArr[$item['order_id']] ?? []; + $stock = $stockArr[$item['pre_stock_id']] ?? []; + if (empty($stock) || empty($order)) continue; + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + $rows[$key]['stock_code'] = $stock['stock_code'] ?? '-'; + $rows[$key]['stock_name'] = $stock['stock_name'] ?? '-'; + $rows[$key]['stock_type'] = PreFundStockModel::$stockTypeList[$order['interest_type']] ?? '-'; + $rows[$key]['order_no'] = $order['order_no'] ?? '-'; + $rows[$key]['rate'] = $order['stock_rate'] . "%" ?? '-'; + $rows[$key]['cycle'] = $order['stock_cycle'] . PreFundStockModel::$cycleTypeList[$order['stock_cycle_type']] ?? '-'; + $rows[$key]['open_time'] = $stock['open_time'] ?? '-'; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'tape_list' => [], + 'stock_type_list' => PreFundStockModel::$stockTypeList, + 'cycle_type_list' => PreFundStockModel::$cycleTypeList + ]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + + ########################################## 印度期权交易 ########################################### + // 印度期权持仓 + public function inOptionHold($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('hk_stockHold')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_HOLD)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_HOLD) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_HOLD) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + // 持仓总手续费 + $totalServiceCost = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_HOLD) + ->where($whereU) + ->where($where) + ->sum('service_cost'); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + $orderNumber = number_format($item['order_number'], '18', '.', ''); + $orderPrice = number_format($item['deal_price'], '18', '.', ''); + $orderAmount = bcmul($orderNumber, $orderPrice, 18); + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'open_time' => $item['open_time'] ?? '-', // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $orderAmount, // 订单金额 + 'stock_id' => $item['stock_id'], // 股票代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'float' => '-', // 浮动盈亏 + 'deal_price' => $item['deal_price'], // 开仓价 + 'now_price' => '-', // 当前价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), 'totalServiceCost' => $totalServiceCost, + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 印度期权挂单 + public function inOptionPlace($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('hk_stockPlace')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_PLACE)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_PLACE) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_PLACE) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + // 挂单价 + $price = $item['limit_price']; + if ($item['deal_type'] == 2) { + $price = $item['market_price']; + } + + $orderNumber = number_format($item['order_number'], '18', '.', ''); + $orderPrice = number_format($price, '18', '.', ''); + $orderAmount = bcmul($orderNumber, $orderPrice, 18); + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'order_id' => $item['order_id'], // 订单号 + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'order_money' => $orderAmount, // 订单金额 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'stock_id' => $item['stock_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'deal_price' => $price, // 委托价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'limit_price' => $item['limit_price'], // 限价 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 印度期权撤单 + public function inOptionBack($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('hk_stockBack')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['stock_id'])) { + $where['stock_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['update_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_BACK)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_BACK) + ->where($where)->where($whereU) + ->count(); + // 持仓总金额 + $totalModel = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_BACK) + ->field('SUM(order_money) as total')->where($whereU) + ->where($where)->find(); + + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + // 挂单价 + $price = $item['limit_price']; + if ($item['deal_type'] == 2) { + $price = $item['market_price']; + } + + $orderNumber = number_format($item['order_number'], '18', '.', ''); + $orderPrice = number_format($price, '18', '.', ''); + $orderAmount = bcmul($orderNumber, $orderPrice, 18); + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'create_time' => $item['create_time'], // 挂单时间 + 'update_time' => $item['update_time'], // 挂单时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $orderAmount, // 订单金额 + 'stock_id' => $item['stock_id'], // 合约代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'deal_price' => $price, // 委托价 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => ['totalMoney' => round($totalModel['total'], 4), + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 印度期权平仓 + public function inOptionClear($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('hk_stockClear')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + // 订单号 + if (!empty($param['order_id'])) { + $where['order_id'] = $param['order_id']; + } + + // 交易对 + if (!empty($param['contract_id'])) { + $where['contract_id'] = $param['contract_id']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['open_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_CLEAR)->where($whereU)->where($where)->order('trade_id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_CLEAR) + ->where($where)->where($whereU) + ->count(); + + // 持仓总手续费 + $totalClosingCost = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_CLEAR) + ->where($whereU) + ->where($where) + ->sum('closing_cost'); + + $totalFloat = StockOptionInrTradeModel::where('status', StockOptionInrTradeModel::STATUS_CLEAR) + ->where($whereU) + ->where($where) + ->field("SUM( CASE WHEN trade_type = 1 THEN ( closing_price - deal_price )* order_number ELSE ( deal_price - closing_price )* order_number END ) AS total")->find(); + + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + foreach ($list as $item) { + // 计算浮动盈亏 + if ($item['trade_type'] == 1) { + $float = $item['closing_price'] - $item['deal_price']; + } else { + $float = $item['deal_price'] - $item['closing_price']; + } + $float = bcmul($float, $item['order_number'], 18); + + $orderNumber = number_format($item['order_number'], '18', '.', ''); + $orderPrice = number_format($item['deal_price'], '18', '.', ''); + $orderAmount = bcmul($orderNumber, $orderPrice, 18); + + $rows[] = [ + 'trade_id' => $item['trade_id'], // + 'user_no' => $userNoArr[$item['user_id']] ?? '-', // 用户号 + 'order_id' => $item['order_id'], // 用户号 + 'closing_time' => $item['closing_time'], // 平仓时间 + 'trade_type' => $item['trade_type'] == 1 ? '买涨' : '买跌', + 'order_money' => $orderAmount, // 订单金额 + 'stock_id' => $item['stock_id'], // 股票代码 + 'order_number' => $item['order_number'], // 数量 + 'service_cost' => $item['service_cost'], // 服务费 + 'closing_cost' => $item['closing_cost'], // 平仓服务费 + 'deal_price' => $item['deal_price'], // 开仓价 + 'closing_price' => $item['closing_price'], // 平仓价格 + 'stop_loss_price' => $item['stop_loss_price'], // 止损价 + 'stop_win_price' => $item['stop_win_price'], // 止盈价 + 'float' => $float, // 平仓盈亏 + 'pry_num' => $item['pry_num'], // 杠杆 + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, + 'extent' => [ + 'totalClosingCost' => $totalClosingCost, + 'totalFloat' => $totalFloat['total'], + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + ################################################# 大宗交易 + //大宗交易订单 + public function blockStock($param, $adminId) + { + try { + // 参数校验 + validate(OrderValidate::class)->scene('fund_stock')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + + if (!empty($param['type']) && is_numeric($param['type'])) { + $where['type'] = $param['type']; + } + + $list = UserStockBlockOrderModel::where($whereU)->where($where)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + $total = UserStockBlockOrderModel::where($whereU)->where($where)->count(); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + // stock + $preStockId = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; +// $preStockId[] = $idItem['pre_stock_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); +// $stockArr = PreFundStockModel::where('id', 'in', $preStockId)->column('*', 'id'); + + $rows = $list->toArray(); + foreach ($rows as $key => $item) { +// $stock = $stockArr[$item['pre_stock_id']] ?? []; +// if (empty($stock)) continue; + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + $rows[$key]['stock_name'] = $item['stock_name'] ?? '-'; + $rows[$key]['market_price'] = $item['market_price'] ?? '-'; + $rows[$key]['deal_price'] = $item['deal_price'] ?? '-'; + $rows[$key]['order_number'] = $item['order_number'] ?? '-'; + $rows[$key]['market_money'] = $item['market_money'] ?? '-'; + $rows[$key]['order_money'] = $item['order_money'] ?? '-'; + $rows[$key]['status'] = UserStockBlockOrderModel::$statusList[$item['status']]; + $rows[$key]['type'] = UserStockBlockOrderModel::$typeList[$item['type']]; + $rows[$key]['create_time'] = $item['create_time'] ?? '-'; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extend' => [ + 'status_list' => UserStockBlockOrderModel::$statusList, + 'type_list' => UserStockBlockOrderModel::$typeList + ]]); + + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/RechargeService.php b/app/admin/service/RechargeService.php new file mode 100644 index 0000000..5187272 --- /dev/null +++ b/app/admin/service/RechargeService.php @@ -0,0 +1,182 @@ +scene('index')->check($param); + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], ]); + } + $userId = $user['user_id']; + } + $statusList = RechargeApplyModel::$statusList; + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extend' => $statusList]); + } + // 订单号 + if (!empty($param['order_id'])) { + $where['order_no'] = $param['order_id']; + } + if (isset($param['is_online'])) { + $where['is_online'] = $param['is_online']; + if ($param['is_online'] == 1) $statusList[0] = '用户取消'; + } + + if (isset($param['status'])) { + $where['status'] = $param['status']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['update_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + Cache::store('redis')->set('Recharge_Read_Time'.$adminId,time()); + // 列表 + $list = RechargeApplyModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = RechargeApplyModel::where($where)->where($whereU)->count(); + // 统计 充值成功 + $sum = RechargeApplyModel::where($where)->where($whereU)->where('status', 1)->sum('recharge_num'); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + $rows = $list->toArray(); + foreach ($rows as $key => $item) { + $rows[$key]['status_text'] = $statusList[$item['status']]; + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号 + $rows[$key]['order_id'] = $item['order_no']; + $rows[$key]['recharge_channel'] = PaymentListModel::where('id', $item['recharge_channel'])->value('channel'); + } + } + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'sum' => $sum . 'USD', 'extend' => $statusList]); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function info($param, $adminId) + { + try { + // 参数校验 + validate(RechargeValidate::class)->scene('info')->check($param); + $where = [ + 'id' => $param['id'] + ]; + + $userId = 0; + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($where)) { + return $this->toData('0', 'SUCCESS', []); + } + + $info = RechargeApplyModel::getOrderInfo($where); + if ($info['file_id']) { + $info['file_url'] = FileModel::getFilePath($info['file_id']); + } + $payment_info = PaymentListModel::getPaymentInfo([ + 'id' => $info['recharge_channel'] + ]); + if ($payment_info) { + $info['recharge_channel'] = !isset($payment_info['channel']) ? $payment_info['channel'] : $info['recharge_channel']; + $info['bank_name'] = !isset($payment_info['bank_name']) ? $payment_info['bank_name'] : ''; + $info['bank_branch'] = !isset($payment_info['bank_branch']) ? $payment_info['bank_branch'] : ''; + $info['bank_user'] = !isset($payment_info['bank_user']) ? $payment_info['bank_user'] : ''; + $info['bank_account'] = !isset($payment_info['bank_account']) ? $payment_info['bank_account'] : ''; + $info['wallet_address'] = !isset($payment_info['wallet_address']) ? $payment_info['wallet_address'] : ''; + } + return $this->toData('0', 'SUCCESS', $info); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + public function check($param, $adminId) + { + try { + // 参数校验 + validate(RechargeValidate::class)->scene('info')->check($param); + $isAgent = AdminModel::checkUserIsAgent($adminId); + if ($isAgent) { + return $this->toData('10040', '代理无权限操作'); + } + $where = [ + 'id' => $param['id'] + ]; + $userId = 0; + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($where)) { + return $this->toData('0', 'SUCCESS', []); + } + $info = RechargeApplyModel::getOrderInfo($where); + if ($info) { + if ($info['is_online'] == 1){ + return $this->toData('10040', '在线充值 不可操作'); + } + + if ($info['is_check'] == 0) { + if ($param['check_status'] == 1) { + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $result = $this->updateUserAssetNew($info['user_id'], 1, $info['market_amount'], 0, $info['order_no']); + }else{ + $result = $this->updateUserAsset($info['user_id'], $info['account_type'], 1, $info['market_amount'], 0, $info['order_no']); + } + if ($result['status'] == 200) { + RechargeApplyModel::where('id', $info['id'])->update([ + 'is_check' => 1, + 'status' => 1, + 'deal_time' => date('Y-m-d H:i:s') + ]); + } else { + return $this->toData('1015', $result['msg'],$result['data']); + } + } else { + RechargeApplyModel::where('id', $info['id'])->update([ + 'is_check' => 2, + 'status' => 2 + ]); + } + } + if ($info['file_id']) { + $info['file_url'] = FileModel::getFilePath($info['file_id']); + $file = dirname(dirname(dirname(__DIR__))) . "/public" . $info['file_url']; + @unlink($file); + } + + return $this->toData('0', 'SUCCESS', []); + } else { + return $this->toData('1', '参数错误', []); + } + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + + } +} \ No newline at end of file diff --git a/app/admin/service/UserService.php b/app/admin/service/UserService.php new file mode 100644 index 0000000..f5492a2 --- /dev/null +++ b/app/admin/service/UserService.php @@ -0,0 +1,1303 @@ +scene('index')->check($param); + Cache::store('redis')->set('User_Read_Time'.$adminId,time()); + $where = []; + // 邮箱搜索 + if (!empty($param['email']) && trim($param['email'])) { + $where['email'] = $param['email']; + } + + // 用户审核状态筛选 + if (!empty($param['real_status']) && is_numeric($param['real_status'])) { + $where['real_status'] = $param['real_status']; + } + + // 用户号 + if (!empty($param['user_no']) && trim($param['user_no'])) { + $where['user_no'] = $param['user_no']; + } + + // 手机号搜索 + if (!empty($param['phone']) && trim($param['phone'])) { + $where['phone_number'] = $param['phone']; + } + + // 用户审核状态筛选 + if (!empty($param['agent_id']) && is_numeric($param['agent_id'])) { + $where['agent_id'] = $param['agent_id']; + } + + //邀请码 + if (!empty($param['invite_code']) && trim($param['invite_code'])) { + $where['invite_code'] = $param['invite_code']; + } + + // 杠杆申请状态 + if (!empty($param['leve_status']) && is_numeric($param['leve_status'])) { + $where['leve_status'] = $param['leve_status']; + } + + // 测试用户 + if (!empty($param['is_test_user']) && is_numeric($param['is_test_user'])) { + $where['is_test_user'] = $param['is_test_user']; + } + + // 注册时间 + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + $IsAgent = AdminModel::checkUserIsAgent($adminId); + $agentNameArr = AdminModel::where('role_id', 10)->column('user_name', 'id'); + + $marketRate = StockMarketModel::column('rate', 'stock_market_type'); + $tapeList = (new StockMarketModel)->getAllTape(); + // 父级用户号 + if (!empty($param['parent_user_no']) && trim($param['parent_user_no'])) { + $parentUser = UserModel::where('user_no', $param['parent_user_no'])->find(); + if (empty($parentUser)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, 'is_agent' => $IsAgent, 'agent_list' => $agentNameArr, 'market_rate' => $marketRate, 'market_tape_list' => $tapeList]]); + } + $where['parent_id'] = $parentUser->user_id; + } + + if (!empty($where['user_id']) && is_numeric($where['user_id']) && $where['user_id'] == 0) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, 'is_agent' => $IsAgent, 'agent_list' => $agentNameArr, 'market_rate' => $marketRate, 'market_tape_list' => $tapeList]]); + } + + $whereU = $this->getWhereByIsAgentAndUserId($adminId, [], 0); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, 'is_agent' => $IsAgent, 'agent_list' => $agentNameArr, 'market_rate' => $marketRate, 'market_tape_list' => $tapeList]]); + } + + $userList = UserModel::where($where)->where($whereU)->page($param['page'], $param['limit'])->order('user_id', 'desc')->select(); + $total = UserModel::where($where)->where($whereU)->count(); + + $rows = []; + if (!empty($userList)) { + $userIdArr = []; + $parentIdArr = []; + foreach ($userList as $value) { + $userIdArr[] = $value['user_id']; + if ($value['parent_id'] > 0) { + $parentIdArr[] = $value['parent_id']; + } + } + + // 查询父级 + $parentNos = UserModel::where('user_id', 'in', $parentIdArr)->column('user_no', 'user_id'); + + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $userMoneyList=UserMoneyModel::where('user_id', 'in', $userIdArr) ->where('stock_id', 'USD') + ->column('usable_num,frozen_num', 'user_id'); + }else{ + // 查询用户余额 + $userContractList = UserContractModel::where('user_id', 'in', $userIdArr) + ->where('contract_id', 'USDT') + ->column('usable_num,frozen_num', 'user_id'); + // 查询用户余额 + $userContractSecList = UserContractSecModel::where('user_id', 'in', $userIdArr) + ->where('contract_id', 'USDT') + ->column('usable_num,frozen_num', 'user_id'); + $userStockList = UserStockModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'USD') + ->column('usable_num,frozen_num', 'user_id'); + $userDigitalList = UserDigitalModel::where('user_id', 'in', $userIdArr) + ->where('digital_id', 'USDT') + ->column('usable_num,frozen_num', 'user_id'); + + // 印尼资产 + $userStockIdrList = UserStockIdnModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'IDR') + ->column('usable_num,frozen_num', 'user_id'); + + // 泰股资产 + $userStockThaList = UserStockThaModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'THB') + ->column('usable_num,frozen_num', 'user_id'); + + // 马股资产 + $userStockMysList = UserStockMysModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'MYR') + ->column('usable_num,frozen_num', 'user_id'); + + // 印度股票资产 + $userStockInList = UserStockInModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'INR') + ->column('usable_num,frozen_num', 'user_id'); + //新加坡股票资产 + $userStockSGDList = UserStockSgdModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'SGD') + ->column('usable_num,frozen_num', 'user_id'); + //基金资产 + $userStockFundList = UserStockFundModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'USD') + ->column('usable_num,frozen_num', 'user_id'); + //印度期权 + $userStockOptionInrList = UserStockOptionInrModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'INR') + ->column('usable_num,frozen_num', 'user_id'); + //港股 + $userStockHkList = UserStockHkdModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'HKD') + ->column('usable_num,frozen_num', 'user_id'); + //英股 + $userStockUkList = UserStockGBXModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'GBX') + ->column('usable_num,frozen_num', 'user_id'); + //法股 + $userStockFurList = UserStockFurModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'EUR') + ->column('usable_num,frozen_num', 'user_id'); + //德股 + $userStockEurList = UserStockEurModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'EUR') + ->column('usable_num,frozen_num', 'user_id'); + //巴西 + $userStockBrlList = UserStockBrlModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'BRL') + ->column('usable_num,frozen_num', 'user_id'); + + $userStockJpList = UserStockJpModel::where('user_id', 'in', $userIdArr) + ->where('stock_id', 'JPY') + ->column('usable_num,frozen_num', 'user_id'); + //外汇 + $userForexList = UserForexModel::where('user_id', 'in', $userIdArr) + ->where('contract_id', 'USD') + ->column('usable_num,frozen_num', 'user_id'); + } + + // 查询用户冻结状态 + $accountFrozenList = []; + if ($userIdArr) { + $accountFrozenList = AccountFrozenModel::where('user_id', 'in', $userIdArr) + ->column('frozen_recharge,frozen_withdraw', 'user_id'); + } + + + //最近登录IP、最近登录国家 + $subQuery = UserLoginLog::field('user_id,MAX(login_date) AS last_login_date') + ->where('user_id', 'in', $userIdArr)->group('user_id')->buildSql(); + $lastLoginLog = UserLoginLog::alias('a')->field('a.id') + ->join([$subQuery => 'w'], 'a.user_id=w.user_id AND a.login_date=w.last_login_date')->column(['id', 'ip', 'country', 'city'], 'a.user_id'); + + foreach ($userList as $item) { + $frozenRecharge = isset($accountFrozenList[$item['user_id']]['frozen_recharge']) ? $accountFrozenList[$item['user_id']]['frozen_recharge'] : 0; + $frozenWithdraw = isset($accountFrozenList[$item['user_id']]['frozen_withdraw']) ? $accountFrozenList[$item['user_id']]['frozen_withdraw'] : 0; + $key = 'LEVERAGE:' . $item['user_id']; + $leverage_num=empty(Cache::store('redis')->get($key))? 1: Cache::store('redis')->get($key); + $userRow= [ + 'id' => $item['user_id'], + 'frozen_recharge' => $frozenRecharge, + 'frozen_withdraw' => $frozenWithdraw, + 'user_no' => $item['user_no'], + 'nickname' => $item['nick_name'], + 'regTime' => $item['create_time'], + 'parentNo' => $parentNos[$item['parent_id']] ?? '-', + 'parent_id' => $item['parent_id'], + 'invite_code' => $item['invite_code'], + 'email' => $item['email'], + 'mobile' => $item['country_code'] . '-' . $item['phone_number'], + 'rechargeAmount' => 0, + 'withdrawalAmount' => 0, + 'regIp' => $item['reg_ip'], + 'status' => $item['status'], + 'statusName' => UserModel::$statusMap[$item['status']] ?? '-', + 'loginTime' => $item['last_login_time'], + 'is_real' => $item['is_real'], + 'real_status' => $item['real_status'], + 'lever_status' => $item['lever_status'], + 'is_test_user' => $item['is_test_user'], + 'is_test_user_text' => UserModel::$isTestUserMap[$item['is_test_user']] ?? '-', + 'last_ip' => $lastLoginLog[$item['user_id']]['ip'] ?? '-', + 'last_country' => empty($lastLoginLog[$item['user_id']]['country']) ? '-' : json_decode($lastLoginLog[$item['user_id']]['country'], true)['en'], + 'agent_id' => $item['agent_id'], + 'agent_name' => $item['agent_id'] > 0 ? $agentNameArr[$item['agent_id']] ?? '-' : '-', + 'leverage_num'=>$leverage_num + ]; + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $userRow['money'] = $userMoneyList[$item['user_id']]['usable_num'] ?? '0'; + $userRow['money_frozen']=$userMoneyList[$item['user_id']]['frozen_num'] ?? '0'; + }else{ + //余额 + $userRow['digital'] = $userDigitalList[$item['user_id']]['usable_num'] ?? '0'; + $userRow['stock'] = $userStockList[$item['user_id']]['usable_num'] ?? '0'; + $userRow['contract'] = $userContractList[$item['user_id']]['usable_num'] ?? '0'; + $userRow['contract_sec'] = $userContractSecList[$item['user_id']]['usable_num'] ?? '0'; + $userRow['forex'] = $userForexList[$item['user_id']]['usable_num'] ?? '0';//外汇 + $userRow['stock_idn']=$userStockIdrList[$item['user_id']]['usable_num'] ?? '0'; // 印尼股票余额 + $userRow['stock_tha']=$userStockThaList[$item['user_id']]['usable_num'] ?? '0'; // 泰股资产 + $userRow['stock_mys']=$userStockMysList[$item['user_id']]['usable_num'] ?? '0'; // 马股资产 + $userRow['stock_in']=$userStockInList[$item['user_id']]['usable_num'] ?? '0';// 印度股资产 + $userRow['stock_sgd']=$userStockSGDList[$item['user_id']]['usable_num'] ?? '0'; // 新加坡股资产 + $userRow['stock_fund']=$userStockFundList[$item['user_id']]['usable_num'] ?? '0'; // 基金资产 + $userRow['stock_option_in']=$userStockOptionInrList[$item['user_id']]['usable_num'] ?? '0'; // 印度期权资产 + $userRow['stock_hk']=$userStockHkList[$item['user_id']]['usable_num'] ?? '0';// 香港股资产 + $userRow['stock_uk']=$userStockUkList[$item['user_id']]['usable_num'] ?? '0'; // 英股资产 + $userRow['stock_fur']=$userStockFurList[$item['user_id']]['usable_num'] ?? '0'; // 法股资产 + $userRow['stock_eur']=$userStockEurList[$item['user_id']]['usable_num'] ?? '0'; // 德股资产 + $userRow['stock_brl']=$userStockBrlList[$item['user_id']]['usable_num'] ?? '0'; // 巴西股资产 + $userRow['stock_jp']=$userStockJpList[$item['user_id']]['usable_num'] ?? '0';// 巴西股资产 + //冻结资金 + $userRow['digital_frozen']=$userDigitalList[$item['user_id']]['frozen_num'] ?? '0'; + $userRow['stock_frozen']=$userStockList[$item['user_id']]['frozen_num'] ?? '0'; + $userRow['contract_frozen']=$userContractList[$item['user_id']]['frozen_num'] ?? '0'; + $userRow['forex_frozen']=$userForexList[$item['user_id']]['frozen_num'] ?? '0'; + $userRow['contract_sec_frozen']=$userContractSecList[$item['user_id']]['frozen_num'] ?? '0'; + $userRow['stock_idn_frozen']=$userStockIdrList[$item['user_id']]['frozen_num'] ?? '0'; // 印尼股票余额 + $userRow['stock_tha_frozen']=$userStockThaList[$item['user_id']]['frozen_num'] ?? '0'; // 泰股资产 + $userRow['stock_mys_frozen']=$userStockMysList[$item['user_id']]['frozen_num'] ?? '0'; // 马股资产 + $userRow['stock_in_frozen']=$userStockInList[$item['user_id']]['frozen_num'] ?? '0';// 印度股资产 + $userRow['stock_sgd_frozen']=$userStockSGDList[$item['user_id']]['frozen_num'] ?? '0'; // 新加坡股资产 + $userRow['stock_fund_frozen']=$userStockFundList[$item['user_id']]['frozen_num'] ?? '0'; // 基金资产 + $userRow['stock_option_in_frozen']=$userStockOptionInrList[$item['user_id']]['frozen_num'] ?? '0';// 印度期权资产 + $userRow['stock_hk_frozen']=$userStockHkList[$item['user_id']]['frozen_num'] ?? '0'; // 香港股资产 + $userRow['stock_uk_frozen']=$userStockUkList[$item['user_id']]['frozen_num'] ?? '0'; // 英港股资产 + $userRow['stock_fur_frozen']=$userStockFurList[$item['user_id']]['frozen_num'] ?? '0'; // 法股资产 + $userRow['stock_eur_frozen']=$userStockEurList[$item['user_id']]['frozen_num'] ?? '0'; // 德股资产 + $userRow['stock_brl_frozen']=$userStockBrlList[$item['user_id']]['frozen_num'] ?? '0'; // 德股资产 + $userRow['stock_jp_frozen']=$userStockJpList[$item['user_id']]['frozen_num'] ?? '0'; // 德股资产 + } + $rows[] =$userRow; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extent' => ['market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, 'is_agent' => $IsAgent, 'agent_list' => $agentNameArr, 'market_rate' => $marketRate, 'market_tape_list' => $tapeList]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + public function RealList($param, $adminId) + { + try { + Cache::store('redis')->set('User_Read_Time'.$adminId,time()); + // 参数校验 + validate(UserValidate::class)->scene('index')->check($param); + + $where = []; + // 邮箱搜索 + if (!empty($param['email']) && trim($param['email'])) { + $where['email'] = $param['email']; + } + + // 用户审核状态筛选 + if (!empty($param['real_status']) && is_numeric($param['real_status'])) { + $where['real_status'] = $param['real_status']; + } + + // 用户号 + if (!empty($param['user_no']) && trim($param['user_no'])) { + $where['user_no'] = $param['user_no']; + } + + // 手机号搜索 + if (!empty($param['phone']) && trim($param['phone'])) { + $where['phone_number'] = $param['phone']; + } + + // 用户审核状态筛选 + if (!empty($param['agent_id']) && is_numeric($param['agent_id'])) { + $where['agent_id'] = $param['agent_id']; + } + + //邀请码 + if (!empty($param['invite_code']) && trim($param['invite_code'])) { + $where['invite_code'] = $param['invite_code']; + } + + // 杠杆申请状态 + if (!empty($param['leve_status']) && is_numeric($param['leve_status'])) { + $where['leve_status'] = $param['leve_status']; + } + + // 测试用户 + if (!empty($param['is_test_user']) && is_numeric($param['is_test_user'])) { + $where['is_test_user'] = $param['is_test_user']; + } + + // 注册时间 + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['create_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + $IsAgent = AdminModel::checkUserIsAgent($adminId); + $agentNameArr = AdminModel::where('role_id', 10)->column('user_name', 'id'); + + $marketRate = StockMarketModel::column('rate', 'stock_market_type'); + $tapeList = (new StockMarketModel)->getAllTape(); + // 父级用户号 + if (!empty($param['parent_user_no']) && trim($param['parent_user_no'])) { + $parentUser = UserModel::where('user_no', $param['parent_user_no'])->find(); + if (empty($parentUser)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, 'is_agent' => $IsAgent, 'agent_list' => $agentNameArr, 'market_rate' => $marketRate, 'market_tape_list' => $tapeList]]); + } + $where['parent_id'] = $parentUser->user_id; + } + + if (!empty($where['user_id']) && is_numeric($where['user_id']) && $where['user_id'] == 0) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, 'is_agent' => $IsAgent, 'agent_list' => $agentNameArr, 'market_rate' => $marketRate, 'market_tape_list' => $tapeList]]); + } + + $whereU = $this->getWhereByIsAgentAndUserId($adminId, [], 0); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, 'is_agent' => $IsAgent, 'agent_list' => $agentNameArr, 'market_rate' => $marketRate, 'market_tape_list' => $tapeList]]); + } + + $userList = UserModel::where($where)->where($whereU) + ->where('real_status',2)->page($param['page'], $param['limit'])->order('user_id', 'desc')->select(); + $total = UserModel::where($where)->where($whereU) ->where('real_status',2)->count(); + + $rows = []; + if (!empty($userList)) { + $userIdArr = []; + $parentIdArr = []; + foreach ($userList as $value) { + $userIdArr[] = $value['user_id']; + if ($value['parent_id'] > 0) { + $parentIdArr[] = $value['parent_id']; + } + } + + // 查询父级 + $parentNos = UserModel::where('user_id', 'in', $parentIdArr)->column('user_no', 'user_id'); + + //最近登录IP、最近登录国家 + $subQuery = UserLoginLog::field('user_id,MAX(login_date) AS last_login_date') + ->where('user_id', 'in', $userIdArr)->group('user_id')->buildSql(); + $lastLoginLog = UserLoginLog::alias('a')->field('a.id') + ->join([$subQuery => 'w'], 'a.user_id=w.user_id AND a.login_date=w.last_login_date')->column(['id', 'ip', 'country', 'city'], 'a.user_id'); + + foreach ($userList as $item) { + $key = 'LEVERAGE:' . $item['user_id']; + $leverage_num=empty(Cache::store('redis')->get($key))? 1: Cache::store('redis')->get($key); + $userRow= [ + 'id' => $item['user_id'], + 'user_no' => $item['user_no'], + 'nickname' => $item['nick_name'], + 'regTime' => $item['create_time'], + 'parentNo' => $parentNos[$item['parent_id']] ?? '-', + 'parent_id' => $item['parent_id'], + 'invite_code' => $item['invite_code'], + 'email' => $item['email'], + 'mobile' => $item['country_code'] . '-' . $item['phone_number'], + 'rechargeAmount' => 0, + 'withdrawalAmount' => 0, + 'regIp' => $item['reg_ip'], + 'status' => $item['status'], + 'statusName' => UserModel::$statusMap[$item['status']] ?? '-', + 'loginTime' => $item['last_login_time'], + 'is_real' => $item['is_real'], + 'real_status' => $item['real_status'], + 'lever_status' => $item['lever_status'], + 'is_test_user' => $item['is_test_user'], + 'is_test_user_text' => UserModel::$isTestUserMap[$item['is_test_user']] ?? '-', + 'last_ip' => $lastLoginLog[$item['user_id']]['ip'] ?? '-', + 'last_country' => empty($lastLoginLog[$item['user_id']]['country']) ? '-' : json_decode($lastLoginLog[$item['user_id']]['country'], true)['en'], + 'agent_id' => $item['agent_id'], + 'agent_name' => $item['agent_id'] > 0 ? $agentNameArr[$item['agent_id']] ?? '-' : '-', + 'leverage_num'=>$leverage_num + ]; + $rows[] =$userRow; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'extent' => ['market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, 'is_agent' => $IsAgent, 'agent_list' => $agentNameArr, 'market_rate' => $marketRate, 'market_tape_list' => $tapeList]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 修改用户状态 + public function status($param, $adminId) + { + try { + // 参数校验 + validate(UserValidate::class)->scene('status')->check($param); + $userId = $param['id']; + $status = $param['status']; + $user = UserModel::where('user_id', $userId)->find(); + if (empty($user)) { + return $this->toData('1', '用户不存在'); + } + + $bool = $this->checkUserIdInAgent($adminId, $userId); + if (!$bool) { + return $this->toData('1', '无权操作'); + } + + UserModel::update(['status' => $status], ['user_id' => $userId]); + // 强制推出登录 + if ($status != UserModel::STATUS_ON) { + (new BaseHomeService())->delUserTokenCache($userId); + } + + return $this->toData('0', 'SUCCESS'); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 账号冻结与解冻 + public function frozen($param, $adminId) + { + try { + // 参数校验 + validate(UserValidate::class)->scene('frozen_state')->check($param); + $userId = $param['id']; + $user = UserModel::where('user_id', $userId)->find(); + if (empty($user)) { + return $this->toData('1', '用户不存在'); + } + $bool = $this->checkUserIdInAgent($adminId, $userId); + if (!$bool) { + return $this->toData('1', '无权操作'); + } + // 查询冻结记录表 + $accountFrozen = AccountFrozenModel::where('user_id', $userId)->find(); + if (empty($accountFrozen)) { + if (isset($param['frozen_recharge'])) { + AccountFrozenModel::create(['user_id'=>$userId, 'frozen_recharge' => $param['frozen_recharge']]); + } + if (isset($param['frozen_withdraw'])) { + AccountFrozenModel::create(['user_id'=>$userId, 'frozen_withdraw' => $param['frozen_withdraw']]); + } + } else { + if (isset($param['frozen_recharge'])) { + AccountFrozenModel::update(['frozen_recharge' => $param['frozen_recharge']], ['user_id' => $userId]); + } + if (isset($param['frozen_withdraw'])) { + AccountFrozenModel::update(['frozen_withdraw' => $param['frozen_withdraw']], ['user_id' => $userId]); + } + } + return $this->toData('0', 'SUCCESS'); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 资产修改 + public function change($param, $adminId) + { + try { + // 参数校验 + validate(UserValidate::class)->scene('change')->check($param); + + // 手动判断额度是否有效 + if (empty($param['amount']) || !preg_match('/^[0-9]+(.[0-9]{0,18})?$/', $param['amount'])) { + return $this->toData('1', '调整额度格式错误'); + } + + $userId = $param['id']; + $type = $param['type']; // 1 现货 2 合约 3 股票 + $amount = $param['amount']; // 调整为 + $user = UserModel::where('user_id', $userId)->find(); + if (empty($user)) { + return $this->toData('1', '用户不存在'); + } + $bool = AdminModel::checkUserIsAgent($adminId); + if ($bool) { + return $this->toData('1', '无权操作'); + } + + $rate = 0; + $marketArr = StockMarketModel::column('rate', 'unit'); + + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $user_money=UserMoneyModel::getUserUSDByUserId(['user_id'=>$param['id']]); + $originMoney=$user_money['usable_num']; +// $originMoney = UserMoneyModel::where('user_id', $param['id']) +// ->where('stock_id', 'USD') +// ->value('usable_num'); + $rate = 1; + }else{ + // 查询账户余额 + switch ($param['type']) { + case '1': //现货 + $originMoney = UserDigitalModel::where('user_id', $param['id'])->value('usable_num'); + + $rate = 1; + break; + case '2': //合约 + $originMoney = UserContractModel::where('user_id', $param['id'])->value('usable_num'); + + $rate = 1; + break; + case '3': //美股 + $originMoney = UserStockModel::where('user_id', $param['id']) + ->where('stock_id', 'USD') + ->value('usable_num'); + + $rate = $marketArr['USD'] ?? 0; + break; + case '4': + $originMoney = UserStockIdnModel::where('user_id', $param['id']) + ->where('stock_id', 'IDR') + ->value('usable_num'); + + $rate = $marketArr['IDR'] ?? 0; + break; + case '5': + $originMoney = UserStockMysModel::where('user_id', $param['id']) + ->where('stock_id', 'MYR') + ->value('usable_num'); + + $rate = $marketArr['MYR'] ?? 0; + break; + case '6': + $originMoney = UserStockThaModel::where('user_id', $param['id']) + ->where('stock_id', 'THB') + ->value('usable_num'); + + $rate = $marketArr['THB'] ?? 0; + break; + case '7': + $originMoney = UserStockInModel::where('user_id', $param['id']) + ->where('stock_id', 'INR') + ->value('usable_num'); + + $rate = $marketArr['INR'] ?? 0; + break; + case '8': //秒合约 + $originMoney = UserContractSecModel::where('user_id', $param['id'])->value('usable_num'); + + $rate = 1; + break; + case '9': + $originMoney = UserStockSgdModel::where('user_id', $param['id']) + ->where('stock_id', 'SGD') + ->value('usable_num'); + + $rate = $marketArr['SGD'] ?? 0; + break; + + case '10': + $originMoney = UserStockFundModel::where('user_id', $param['id']) + ->where('stock_id', 'USD') + ->value('usable_num'); + + $rate = $marketArr['USD'] ?? 0; + break; + case '11': + $originMoney = UserStockOptionInrModel::where('user_id', $param['id']) + ->where('stock_id', 'INR') + ->value('usable_num'); + + $rate = $marketArr['INR'] ?? 0; + break; + case '12': + $originMoney = UserStockHkdModel::where('user_id', $param['id']) + ->where('stock_id', 'HKD') + ->value('usable_num'); + + $rate = $marketArr['HKD'] ?? 0; + break; + case '14': + $originMoney = UserStockGBXModel::where('user_id', $param['id']) + ->where('stock_id', 'GBX') + ->value('usable_num'); + + $rate = $marketArr['GBX'] ?? 0; + break; + case '15': + $originMoney = UserStockFurModel::where('user_id', $param['id']) + ->where('stock_id', 'EUR') + ->value('usable_num'); + + $rate = $marketArr['EUR'] ?? 0; + break; + case '16': + $originMoney = UserStockEurModel::where('user_id', $param['id']) + ->where('stock_id', 'EUR') + ->value('usable_num'); + + $rate = $marketArr['EUR'] ?? 0; + break; + case '17': + $originMoney = UserStockBrlModel::where('user_id', $param['id']) + ->where('stock_id', 'BRL') + ->value('usable_num'); + + $rate = $marketArr['BRL'] ?? 0; + break; + case '18': + $originMoney = UserStockJpModel::where('user_id', $param['id']) + ->where('stock_id', 'JPY') + ->value('usable_num'); + + $rate = $marketArr['JPY'] ?? 0; + break; + case '19': + $originMoney = UserForexModel::where('user_id', $param['id']) + ->where('contract_id', 'USD') + ->value('usable_num'); + + $rate = $marketArr['USD'] ?? 0; + break; + default: + return $this->toData('1', '无权操作'); + break; + } + } + + + + $diff = bcsub($amount, $originMoney, 18); + // 未进行修改 + if ($diff == 0) { + return $this->toData('0', 'SUCCESS'); + } + + if ($rate == 0) { + return $this->toData('1', '兑换汇率错误'); + } + + $operateType = '13'; + if ($diff > 0) { + $operateType = '12'; + } + + //正式用户 && 给用户加钱 -> 需要写入变更日志 + $changeLogAdminId = ($user->is_test_user == 1 && abs($diff) > 0) ? $adminId : 0; + // 执行修改账户额度 + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $res = $this->updateUserAssetNew($userId, $operateType, $diff); + }else{ + $res = $this->updateUserAsset($userId, $type, $operateType, $diff, 0, "", $changeLogAdminId, $rate); + } + + if (isset($res['status']) && $res['status'] == 200) { + return $this->toData('0', 'SUCCESS'); + } + return $this->toData('1', '操作失败', [$res]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + // 用户关系 + public function relation($param, $adminId) + { + try { + // 参数校验 + validate(UserValidate::class)->scene('relation')->check($param); + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [],]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + +// // 查询列表数据 +// $userList = UserModel::where('FIND_IN_SET(:id,parent_ids)', ['id' => $userId]) +// ->order('user_id', 'desc') +// ->page($param['page'], $param['limit']) +// ->select(); +// // 查询总数 +// $total = UserModel::where('FIND_IN_SET(:id,parent_ids)', ['id' => $userId]) +// ->count(); + + // 查询列表数据 + $userList = UserModel::where($whereU) + ->order('user_id', 'desc') + ->page($param['page'], $param['limit']) + ->select(); + // 查询总数 + $total = UserModel::where($whereU)->count(); + + + $rows = []; + if (!empty($userList)) { + $userIdArr = []; + $parentIdArr = []; + foreach ($userList as $value) { + $userIdArr[] = $value['user_id']; + if ($value['parent_id'] > 0) { + $parentIdArr[] = $value['parent_id']; + } + } + + // 查询父级 + $parentNos = UserModel::where('user_id', 'in', $parentIdArr)->column('user_no', 'user_id'); + + // 查询用户余额 + $userContractList = UserContractModel::where('user_id', 'in', $userIdArr)->column('usable_num', 'user_id'); + $userStockList = UserStockModel::where('user_id', 'in', $userIdArr)->column('usable_num', 'user_id'); + $userDigitalList = UserDigitalModel::where('user_id', 'in', $userIdArr)->column('usable_num', 'user_id'); + + foreach ($userList as $item) { + // 展示层级关系 + $parentIdsArr = array_reverse(explode(',', $item['parent_ids'])); + $level = '-'; + for ($i = 1; $i <= count($parentIdsArr); $i++) { + if ($parentIdsArr[$i - 1] == $userId) { + $level = '下 ' . $i . ' 级'; + } + } + + $rows[] = [ + 'id' => $item['user_id'], + 'user_no' => $item['user_no'], + 'regTime' => $item['create_time'], + 'nickname' => $item['nick_name'], + 'parentId' => $parentNos[$item['parent_id']] ?? '-', + 'parent_id' => $item['parent_id'], + 'email' => $item['email'], + 'mobile' => $item['country_code'] . '-' . $item['phone_number'], + 'digital' => $userDigitalList[$item['user_id']] ?? '0', + 'stock' => $userStockList[$item['user_id']] ?? '0', + 'contract' => $userContractList[$item['user_id']] ?? '0', + 'rechargeAmount' => 0, + 'withdrawalAmount' => 0, + 'regIp' => $item['reg_ip'], + 'status' => UserModel::$statusMap[$item['status']] ?? '-', + 'loginTime' => $item['last_login_time'], + 'level' => $level, + ]; + } + } + + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function reg_phone($param, $adminId) + { + try { + // 参数校验 + validate(UserValidate::class)->scene('add_phone')->check($param); + $phoneExists = UserModel::checkPhoneExists($param['phone']); + if ($phoneExists) { + return $this->toData('100400', 'The phone number has already been registered.', []); + } + // 入库 + $userNo = (new BaseHomeService())->getUniqUserNo(); + $salt = env('ENCRYPT.SALT'); + $password = (new UnqId())->encryptPassword($param['password'], $salt); + $userInviteCode = (new BaseHomeService())->getUniqInviteCode(); + $parentUserId = 0; + $ip = (new BaseHomeService())->getClientRealIp(); + $userId = UserModel::phoneRegister($param['nation'], $param['phone'], $userNo, $userInviteCode, $parentUserId, $password, $ip, $salt, $param['is_test_user'] ?? 1, 0); + (new \app\home\service\UserService())->doRegInitUserInfo($userId, $parentUserId); + // 判断是否是代理 + $isAgent = AdminModel::checkUserIsAgent($adminId); + if ($isAgent) { + UserModel::where('user_id', $userId)->update([ + 'agent_id' => $adminId + ]); + } + + return $this->toData('0', 'SUCCESS'); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + public function reg_email($param, $adminId) + { + try { + // 参数校验 + validate(UserValidate::class)->scene('add_email')->check($param); + if ((new BaseHomeService())->checkForbidEmail($param['email'])) { + return $this->toData('100500', 'You are not allowed to register with Chinese email addresses.', []); + } + // 邮箱是否已经存在 + $emailExists = UserModel::checkEmailExists($param['email']); + if ($emailExists) { + return $this->toData('100300', 'The email has already been registered.', []); + } + + // 入库 + $userNo = (new BaseHomeService())->getUniqUserNo(); + $salt = env('ENCRYPT.SALT'); + $password = (new UnqId())->encryptPassword($param['password'], $salt); + $userInviteCode = (new BaseHomeService())->getUniqInviteCode(); + $parentUserId = 0; + $ip = (new BaseHomeService())->getClientRealIp(); + $userId = UserModel::emailRegister($param['email'], $userNo, $userInviteCode, $parentUserId, $password, $ip, $salt, $param['is_test_user'] ?? 1, 0); + // 判断是否是代理 + $isAgent = AdminModel::checkUserIsAgent($adminId); + if ($isAgent) { + UserModel::where('user_id', $userId)->update([ + 'agent_id' => $adminId + ]); + } + (new \app\home\service\UserService())->doRegInitUserInfo($userId, $parentUserId); + return $this->toData('0', 'SUCCESS'); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + // 实名认证操作 + public function verifyDetail($param) + { + try { + $userId = $param['user_id'] ?? ''; + if (!is_numeric($userId)) { + return $this->toData('100400', 'Param error', []); + } + + $log = UserVerifyLogModel::where('user_id', $userId)->order('id', 'desc')->find(); + if (empty($log)) { + return $this->toData('0', 'success', []); + } + + $front = FileModel::where('id', $log->front_img)->value('path'); + $back = FileModel::where('id', $log->back_img)->value('path'); + $country = CountryModel::where('id', $log->country)->find(); + + $data = [ + 'id' => $log->id, + 'name' => $log->name, + 'code' => $log->code, + 'country' => $country, + 'front_img' => $front, + 'back_img' => $back, + 'lock_password' => $log->lock_password + ]; + + return $this->toData('0', 'success', $data); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function verifyDo($param, $adminId) + { + try { + $id = $param['id'] ?? ''; + $status = $param['status'] ?? '3'; + if (!is_numeric($id)) { + return $this->toData('100400', 'Param error', []); + } + + if (!is_numeric($status) || !in_array($status, [UserVerifyLogModel::STATUS_SUCCESS, UserVerifyLogModel::STATUS_FAIL])) { + return $this->toData('100400', 'Status param error', []); + } + + $log = UserVerifyLogModel::where('id', $id)->find(); + if (empty($log)) { + return $this->toData('100400', 'ID param error', []); + } + + $agentAuth = env('AGENT_AUTH.AGENT_AUTH_VERIFY'); // 0代理不可审核 1代理可审核 + if (empty($agentAuth)){ + $isAgent = AdminModel::checkUserIsAgent($adminId); + if ($isAgent) { + return $this->toData('10040', '代理无权限操作'); + } + } + + $isReal = 0; + $realStatus = 4; + // 如果是成功 修改用户表 + if ($status == UserVerifyLogModel::STATUS_SUCCESS) { + $isReal = 1; + $realStatus = 3; + } + + // 更新用户 + UserModel::where('user_id', $log->user_id)->update(['is_real' => $isReal, 'real_status' => $realStatus, 'update_time' => date('Y-m-d H:i:s')]); + // 更新记录 + $log->status = $status; + $log->update_time = date('Y-m-d H:i:s'); + $log->save(); + return $this->toData('0', 'success'); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + // 杠杆状态审核 + public function leverReview($param) + { + try { + $userId = $param['user_id'] ?? ''; + if (!is_numeric($userId)) { + return $this->toData('100400', 'Param error', []); + } + + $lever_status = $param['lever_status'] ?? 4; + if (!is_numeric($lever_status)) { + return $this->toData('100400', 'Param error', []); + } + + if (!in_array($lever_status, [UserModel::LEVER_STATUS_PASSED, UserModel::LEVER_STATUS_FAIL])) { + return $this->toData('100400', 'Param error', []); + } + + $key = 'USER:LEVER_STATUS:' . $userId; + $lever_status = $lever_status + 0; + $this->getRedis()->set($key, $lever_status); + UserModel::update(['lever_status' => $lever_status, 'update_time' => date('Y-m-d H:i:s')], ['user_id' => $userId]); + return $this->toData('0', 'success'); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + // 获取用户验证码 + public function getUserCode($param) + { + try { + $extend = [ + 'business' => ['1' => '已登录操作', '3' => '未登录操作'], + 'code_type' => ['6' => '邮箱', '9' => '短信'], + ]; + if (empty($param['search']) || empty($param['business']) || empty($param['code_type'])) { + return $this->toData('0', 'success', ['extend' => $extend, 'get_code' => 0, 'code' => '']); + } + + if (!is_numeric($param['business']) || !is_numeric($param['code_type']) || !is_string($param['search'])) { + return $this->toData('0', 'success', ['extend' => $extend, 'get_code' => 0, 'code' => '']); + } + + + $key_12 = "DB:USER:UNLOGIN:SMS_CODE:" . $param['search']; + $key_9 = "DB:USER:UNLOGIN:EMAIL_CODE:" . $param['search']; + $key_7 = "USER:sendEmailLoginNoTrade:" . $param['search']; + $key_10 = "USER:sendSmsLoginNoTrade:" . $param['search']; + + $key = "key_" . ($param['business'] + $param['code_type']); + if (!isset($$key)) { + return $this->toData('0', 'success', ['extend' => $extend, 'get_code' => 0, 'code' => '']); + } + + $redis = $this->getRedis(); + $code = $redis->get($$key); + if ($code) { + return $this->toData('0', 'success', ['extend' => $extend, 'get_code' => 1, 'code' => $code]); + } + return $this->toData('0', 'success', ['extend' => $extend, 'get_code' => 0, 'code' => '']); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + public function getRegCode($param) + { + $key = "USER:REG:CODE"; + $redis = $this->getRedis(); + $code = $redis->get($key); + if (empty($code)) { + $code = random_int(1000, 9999); + $time = 300; + $redis->setex($key, $time, $code); + } else { + $time = $redis->pttl($key); + } + return $this->toData('0', 'success', ['code' => $code, 'expiration_time' => $time]); + } + + // 用户银行卡 + public function bankDetail($param) + { + try { + $userId = $param['user_id'] ?? ''; + if (!is_numeric($userId)) { + return $this->toData('100400', 'Param error', []); + } + + $bank = UserBankModel::getUserBankInfoById(['user_id' => $userId]); + if (empty($bank)) { + return $this->toData('0', 'success', []); + } + + return $this->toData('0', 'success', $bank); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function editBank($param) + { + try { + if (empty($param['id'])) { + return $this->toData('100400', 'Param error', []); + } + + $bank = UserBankModel::getUserBankInfoById(['id' => $param['id']]); + if (empty($bank)) { + return $this->toData('100400', 'Param error', []); + } + + $updateArr = [ + 'true_name' => $param['true_name'] ?? $bank['true_name'], + 'bank_name' => $param['bank_name'] ?? $bank['bank_name'], + 'bank_code' => $param['bank_code'] ?? $bank['bank_code'], + 'bank_card' => $param['bank_card'] ?? $bank['bank_card'], + 'bank_phone' => $param['bank_phone'] ?? $bank['bank_phone'], + 'bank_email' => $param['bank_email'] ?? $bank['bank_email'], + 'ifsc' => $param['ifsc'] ?? $bank['ifsc'], + 'update_time' => date('Y-m-d H:i:s') + ]; + UserBankModel::where('id', $param['id'])->update($updateArr); + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function editPassword($param) + { + try { + if (empty($param['id'])) { + return $this->toData('100400', 'Param error', []); + } + + $user = UserModel::where('user_id', $param['id'])->find(); + if (empty($user)) { + return $this->toData('100400', 'Param error', []); + } + + $updateArr = []; +// $bool = 0; + if (!empty($param['login_password'])) $updateArr['login_password'] = (new UnqId())->encryptPassword($param['login_password'], $user->salt); + if (!empty($param['trade_password'])) $updateArr['trade_password'] = (new UnqId())->encryptPassword($param['trade_password'], $user->salt); + if (!empty($updateArr)) UserModel::where('user_id', $param['id'])->update($updateArr); +// if (empty($bool)) return $this->toData('1', '系统异常 请稍后重试', []); + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function setAutoLogin($param) + { + try { + if (empty($param['id'])) { + return $this->toData('100400', 'Param error', []); + } + $userId = $param['id']; + $user = UserModel::where('user_id', $userId)->find(); + if (empty($user)) { + return $this->toData('1', '用户不存在'); + } + $token = md5($param['id'] . time() . date('Y-m-d H:i:s')); + $tokenKey = 'AUTO:TOKEN:' . $token; // 根据token查找用户id + + $expired = 5 * 60; + // 由中间件自动续期 + Cache::store('redis')->set($tokenKey, $userId, $expired); + return $this->toData('0', 'SUCCESS', [ + 'login_token' => $token + ]); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function getLeverageNum($param) + { + try { + if (!is_numeric($param['id'])) { + return $this->toData('100400', 'Param error', []); + } + + $key = 'LEVERAGE:' . $param['id']; + $value = Cache::store('redis')->get($key); + if (empty($value)) { + $key = 'LEVERAGE:0'; + $value = Cache::store('redis')->get($key); + } + return $this->toData('0', 'SUCCESS', ['leverage_num' => $value]); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function editLeverageNum($param) + { + try { + if (empty($param['leverage_num'])) { + return $this->toData('100400', 'Param error', []); + } + if (!empty($param['id'])) { + $userId = $param['id']; + } else { + $userId = 0; + } + + $key = 'LEVERAGE:' . $userId; + Cache::store('redis')->del($key); + Cache::store('redis')->set($key, $param['leverage_num']); + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + public function getUserLoan($param,$adminId) + { + try { + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + + if(isset($param['status'])){ + $where['status']=intval($param['status']); + } + + $data['where']=$where; + + $data['page']=isset($param['page']) ? intval($param['page']) : 1; + $data['size']=isset($param['size']) ? intval($param['size']) : 10; + + $list = UserLoanModel::getUserLoanList($data); + if(!empty($list['list'])){ + foreach ($list['list'] as $key=>$item){ + $user= UserModel::where('user_id', $item['user_id'])->find(); + $list['list'][$key]['nick_name']=$user->nick_name; + } + } + + + return $this->toData('0', 'SUCCESS', $list); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage(),$exception->getTrace()]); + } + } + public function dealUserLoan($param,$adminId) + { + try { + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => ['totalMoney' => 0]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + + $where['id']=intval($param['id']); + + $info=UserLoanModel::where($where)->find(); + if(empty($info)){ + return $this->toData('1', '数据不存在'); + } + if($info['status']!=0){ + return $this->toData('1', '数据已审核'); + } + + UserLoanModel::where($where)->update([ + 'status'=>intval($param['status']), + 'update_time'=>date('Y-m-d H:i:s') + ]); + + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } +} + + diff --git a/app/admin/service/VoteService.php b/app/admin/service/VoteService.php new file mode 100644 index 0000000..61b7455 --- /dev/null +++ b/app/admin/service/VoteService.php @@ -0,0 +1,139 @@ +order('id', 'desc'); + $total = $vote->count(); + $list = $vote->page($param['page'], $param['limit'])->select(); + + return $this->toData('0', 'SUCCESS', ['list' => $list, 'total' => $total]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function add($param) + { + try { + + if (empty($param['code'])) { + return $this->toData('1', 'code无效'); + } + + if (empty($param['title'])) { + return $this->toData('1', '标题无效'); + } + + if (empty($param['icon'])) { + return $this->toData('1', '图标无效'); + } + + if (empty($param['content'])) { + return $this->toData('1', '内容无效'); + } + + $vote = new VoteModel(); + $vote->code = $param['code']; + $vote->title = $param['title']; + $vote->icon = $param['icon']; + $vote->content = $param['content']; + $vote->score_num = $param['score_num'] ?? 0; + $vote->sort = $param['sort'] ?? 0; + $vote->oneday_times = $param['oneday_times'] ?? 1; + $vote->create_time = date('Y-m-d H:i:s'); + $vote->update_time = date('Y-m-d H:i:s'); + $vote->save(); + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + public function edit($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '目标不存在'); + } + + $vote = VoteModel::where('id', $param['id']) + ->where('is_delete', VoteModel::IS_DELETE_NO) + ->find(); + if (empty($doc)) { + return $this->toData('1', '目标不存在'); + } + + if (empty($param['code'])) { + return $this->toData('1', 'code无效'); + } + + if (empty($param['title'])) { + return $this->toData('1', '标题无效'); + } + + if (empty($param['icon'])) { + return $this->toData('1', '图标无效'); + } + + if (empty($param['content'])) { + return $this->toData('1', '内容无效'); + } + + $isHas = VoteModel::where('is_delete', VoteModel::IS_DELETE_NO) + ->where('id', '<>', $param['id']) + ->where('title', $param['title'])->find(); + if (!empty($isHas)) { + return $this->toData('1', '标题在相同内容'); + } + + $vote->code = $param['code']; + $vote->title = $param['title']; + $vote->icon = $param['icon']; + $vote->content = $param['content']; + $vote->score_num = $param['score_num'] ?? 0; + $vote->sort = $param['sort'] ?? 0; + $vote->oneday_times = $param['oneday_times'] ?? 1; + $vote->update_time = date('Y-m-d H:i:s'); + $vote->save(); + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function del($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '目标不存在'); + } + + $vote = VoteModel::where('id', $param['id']) + ->where('is_delete', VoteModel::IS_DELETE_NO) + ->find(); + if (empty($vote)) { + return $this->toData('1', '目标不存在'); + } + + $vote->is_delete = VoteModel::IS_DELETE_YES; + $vote->save(); + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/WithdrawService-pro.php b/app/admin/service/WithdrawService-pro.php new file mode 100644 index 0000000..5e9a6ff --- /dev/null +++ b/app/admin/service/WithdrawService-pro.php @@ -0,0 +1,346 @@ +scene('index')->check($param); + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extend' => UserWithdrawalModel::$statusList]); + } + $userId = $user['user_id']; + } + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extend' => UserWithdrawalModel::$statusList]); + } + // 订单号 + if (!empty($param['order_id'])) { + $where['order_no'] = $param['order_id']; + } + if (isset($param['status'])) { + $where['status'] = $param['status']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['update_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserWithdrawalModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserWithdrawalModel::where($where)->where($whereU)->count(); + // 统计 提现成功 + $sum = UserWithdrawalModel::where($where)->where($whereU)->where('status', 4)->sum('apply_num'); + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + $ifscArr = UserBankModel::where('user_id', 'in', $userIdArr)->column('ifsc', 'user_id'); + + $rows = $list->toArray(); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号. + $rows[$key]['ifsc'] = $ifscArr[$item['user_id']] ?? '-'; // ifsc + $rows[$key]['order_id'] = $item['order_no']; + $rows[$key]['status_text'] = UserWithdrawalModel::$statusList[$item['status']]; + //$rows[$key]['pay_info'] = json_decode($item['pay_info'],true); + } + } + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'sum' => $sum . 'USD', 'extend' => UserWithdrawalModel::$statusList]); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function info($param, $adminId) + { + try { + // 参数校验 + validate(WithdrawValidate::class)->scene('info')->check($param); + $where = [ + 'id' => $param['id'] + ]; + + $userId = 0; + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($where)) { + return $this->toData('0', 'SUCCESS', []); + } + + $order_info = []; + $info = UserWithdrawalModel::where($where)->find(); + $ifsc = UserBankModel::where('user_id', $info->user_id)->value('ifsc'); + + if (!$info->isEmpty()) { + $order_info = $info->toArray(); + $order_info['pay_info'] = json_decode($order_info['pay_info'], true); + $channel = PaymentListModel::getPaymentInfo([ + 'id' => intval($order_info['channel_id']) + ]); + $order_info['channel_name'] = isset($channel['channel']) ? $channel['channel'] : ''; + $order_info['ifsc'] = $ifsc ?? '-'; + } + return $this->toData('0', 'SUCCESS', $order_info); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + public function change_status($param, $adminId) + { + try { + // 参数校验 + validate(WithdrawValidate::class)->scene('status')->check($param); + $isAgent = AdminModel::checkUserIsAgent($adminId); + if ($isAgent) { + return $this->toData('10040', '代理无权限操作'); + } + $where = [ + 'id' => $param['id'] + ]; + $userId = 0; + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($where)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $order_info = []; + $info = UserWithdrawalModel::where($where)->find(); + if (empty($info)) { + return $this->toData('1004', '订单不存在'); + } + $order_info = $info->toArray(); + $change_flag = false; + if ($order_info['status'] == 0 && $param['status'] < 3) { + $change_flag = true; + } + if ($order_info['status'] = 1 && ($param['status'] == 3 || $param['status'] == 2)) { + $change_flag = true; + } + if ($order_info['status'] = 3 && $param['status'] == 4) { + $change_flag = true; + } + $pay_flag = false; + $msg = ""; + $content = ""; + if ($change_flag) { + $update_data['status'] = $param['status']; + $update_data['update_time'] = date('Y-m-d H:i:s'); + //拒绝 + if ($param['status'] == 2) { + $updateStatus = $this->updateUserAsset($order_info['user_id'], $order_info['account_type'], 6, $order_info['market_amount'], -$order_info['market_amount'], $order_info['order_no']); + } + + //代付 + if ($param['status'] == 3) { + //解冻资金 ,扣除提现 + $updateOne = $this->updateUserAsset($order_info['user_id'], $order_info['account_type'], 6, $order_info['market_amount'], -$order_info['market_amount'], $order_info['order_no']); + if (!empty($updateOne) && $updateOne['status'] == 200) { + $updateStatus = $this->updateUserAsset($order_info['user_id'], $order_info['account_type'], 2, -$order_info['market_amount'], 0, $order_info['order_no']); + } else { + //提现事务回滚... +// $updateOne = $this->updateUserAsset($order_info['user_id'], $order_info['account_type'], 5, -$order_info['market_amount'], +$order_info['market_amount'], $order_info['order_no']); + trace("提现失败1 - change_status - order_no=" . $order_info['order_no'] . "---user_id= " . $order_info['user_id'] . "---account_type= " . $order_info['account_type'] . "---market_amount= " . $order_info['market_amount']); + return $this->toData($updateOne['status'] ?? '3251', $updateOne['msg'] ?? $msg, [$content]); + } + + if (!empty($updateStatus) && $updateStatus['status'] == 200) { + $channel = PaymentListModel::getPaymentInfo([ + 'id' => $param['channel'] + ]); + if ($channel) { + $result = $this->payToUser($order_info, $channel); + if ($result['code'] == 200) { + $update_data['order_idx'] = $result['order_idx']; + $update_data['channel_id'] = $param['channel']; + } else { + $update_data['status'] = 1; //代付失败 + $pay_flag = true; + $content = $result['content']; + $msg = $result['msg']; + } + } + //手动支付完成 + if ($param['channel'] == 0) { + $update_data['status'] = 4; + $update_data['channel_id'] = $param['channel']; + } + } + } + + $update_data['beizhu'] = $param['beizhu'] ?? ""; + + if ($param['status'] == 1 || (!empty($updateStatus) && $updateStatus['status'] == 200)) { + UserWithdrawalModel::where($where)->update($update_data); + } else { + trace("提现失败2 - change_status - order_no=" . $order_info['order_no'] . "---user_id= " . $order_info['user_id'] . "---account_type= " . $order_info['account_type'] . "---market_amount= " . $order_info['market_amount']); + return $this->toData($updateStatus['status'] ?? '3251', $updateStatus['msg'] ?? $msg, [$content]); + } + + if ($pay_flag) { + return $this->toData('3250', $msg, [$content]); + } else { + return $this->toData('0', 'SUCCESS'); + } + + } else { + return $this->toData('10040', '操作流程不合法'); + } + + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + private function payToUser($order, $channel) + { + //货币单位换算 + $order['total_amount'] = $order['apply_num'] * $channel['exchange_rate']; + $address_info = json_decode($order['pay_info'], true); + + switch ($channel['type']) { + //印尼支付 + case 2: + return (new IndPayService())->singleIndOrder($order); + break; + //TRC + case 3: + return (new MoPayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['bank_code'], $address_info['bank_card'], $address_info['true_name'], $address_info['bank_phone'], $address_info['ifsc']); + break; + //合泰 + case 4: + return (new HTPayService())->arPay($order['order_no'], $order['total_amount'], $address_info['bank_code'], $address_info['bank_card'], $address_info['true_name']); + break; + //合泰 + case 5: + return (new XdPayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['ifsc'], $address_info['bank_card'], $address_info['true_name']); + break; + //QEAE + case 6: + return (new QeaePayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['bank_card'], $address_info['true_name'], $address_info['ifsc'], $address_info['bank_code']); + break; + //合泰 + case 7: + return (new NicePayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['bank_card'], $address_info['true_name'], $address_info['ifsc']); + break; + //ClickPay + case 8: + return (new ClickPayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['bank_card'], $address_info['true_name'], $address_info['ifsc'], $address_info['bank_code']); + break; + default: + + break; + } + } + + public function get_balance($param, $adminId) + { + $channel = PaymentListModel::getPaymentInfo([ + 'id' => intval($param['id']) + ]); + if ($channel) { + switch ($channel['type']) { + case 1: + //$result=(new IndPayService())->getIndBalance(); + $result = [ + 'amount' => 0 + ]; + break; + case 2: + $result = (new TrcPayService())->getTrcBalance(); + break; + case 4: + $result = (new HTPayService())->getHtBalance(); + break; + case 5: + $result = (new XdPayService())->getBalance(); + break; + case 6: + $result = (new QeaePayService())->getBalance(); + break; + case 8: + $result = (new ClickPayService())->getBalance(); + break; + default: + $result = [ + 'amount' => 0 + ]; + break; + } + + return $this->toData('0', '请求成功', $result); + + } else { + return $this->toData('1', '参数错误,通道不存在', []); + } + } + + public function channel_list($param, $adminId) + { + try { + // 参数校验 + validate(WithdrawValidate::class)->scene('info')->check($param); + $where = [ + 'id' => $param['id'] + ]; + + $userId = 0; + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($where)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $order_info = UserWithdrawalModel::getUserDrawalInfo($where); + if ($order_info) { + $channel_list = PaymentListModel::getPaymentList([ + 'is_withdrawal' => 1, + 'status' => 1, + 'channel_type' => $order_info['apply_type'] + ]); + } else { + $channel_list = []; + } + return $this->toData('0', '请求成功', $channel_list); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + +} \ No newline at end of file diff --git a/app/admin/service/WithdrawService.php b/app/admin/service/WithdrawService.php new file mode 100644 index 0000000..f4a98f7 --- /dev/null +++ b/app/admin/service/WithdrawService.php @@ -0,0 +1,365 @@ +scene('index')->check($param); + Cache::store('redis')->set('Withdraw_Read_Time'.$adminId,time()); + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extend' => UserWithdrawalModel::$statusList]); + } + $userId = $user['user_id']; + } + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extend' => UserWithdrawalModel::$statusList]); + } + // 订单号 + if (!empty($param['order_id'])) { + $where['order_no'] = $param['order_id']; + } + if (isset($param['status'])) { + $where['status'] = $param['status']; + } + + if (!empty($param['start_time']) && !empty($param['end_time'])) { + $where['update_time'] = ['between time', [$param['start_time'], $param['end_time']]]; + } + + // 列表 + $list = UserWithdrawalModel::where($where)->where($whereU)->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + // 总数 + $total = UserWithdrawalModel::where($where)->where($whereU)->count(); + // 统计 提现成功 + $sum = UserWithdrawalModel::where($where)->where($whereU)->where('status', 4)->sum('apply_num'); + + + + $rows = []; + if (!$list->isEmpty()) { + // 获取用户号 + $userIdArr = []; + foreach ($list as $idItem) { + $userIdArr[] = $idItem['user_id']; + } + + $userNoArr = UserModel::where('user_id', 'in', $userIdArr)->column('user_no', 'user_id'); + $ifscArr = UserBankModel::where('user_id', 'in', $userIdArr)->column('ifsc', 'user_id'); + + $rows = $list->toArray(); + foreach ($rows as $key => $item) { + $rows[$key]['user_no'] = $userNoArr[$item['user_id']] ?? '-'; // 用户号. + $rows[$key]['ifsc'] = $ifscArr[$item['user_id']] ?? '-'; // ifsc + $rows[$key]['order_id'] = $item['order_no']; + $rows[$key]['status_text'] = UserWithdrawalModel::$statusList[$item['status']]; + //$rows[$key]['pay_info'] = json_decode($item['pay_info'],true); + } + } + return $this->toData('0', 'SUCCESS', ['total' => $total, 'list' => $rows, 'sum' => $sum . 'USD', 'extend' => UserWithdrawalModel::$statusList]); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function info($param, $adminId) + { + try { + // 参数校验 + validate(WithdrawValidate::class)->scene('info')->check($param); + $where = [ + 'id' => $param['id'] + ]; + + $userId = 0; + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($where)) { + return $this->toData('0', 'SUCCESS', []); + } + + $order_info = []; + $info = UserWithdrawalModel::where($where)->find(); + $ifsc = UserBankModel::where('user_id', $info->user_id)->value('ifsc'); + + if (!$info->isEmpty()) { + $order_info = $info->toArray(); + $order_info['pay_info'] = json_decode($order_info['pay_info'], true); + $channel = PaymentListModel::getPaymentInfo([ + 'id' => intval($order_info['channel_id']) + ]); + $order_info['channel_name'] = isset($channel['channel']) ? $channel['channel'] : ''; + $order_info['ifsc'] = $ifsc ?? '-'; + } + return $this->toData('0', 'SUCCESS', $order_info); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + public function change_status($param, $adminId) + { + try { + // 参数校验 + validate(WithdrawValidate::class)->scene('status')->check($param); + $isAgent = AdminModel::checkUserIsAgent($adminId); + if ($isAgent) { + return $this->toData('10040', '代理无权限操作'); + } + $where = [ + 'id' => $param['id'] + ]; + $userId = 0; + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($where)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $order_info = []; + $info = UserWithdrawalModel::where($where)->find(); + if (empty($info)) { + return $this->toData('1004', '订单不存在'); + } + $order_info = $info->toArray(); + $change_flag = false; + if ($order_info['status'] == 0 && $param['status'] < 3) { + $change_flag = true; + } + if ($order_info['status'] = 1 && ($param['status'] == 3 || $param['status'] == 2)) { + $change_flag = true; + } + if ($order_info['status'] = 3 && $param['status'] == 4) { + $change_flag = true; + } + $pay_flag = false; + $msg = ""; + $content = ""; + if ($change_flag) { + $update_data['status'] = $param['status']; + $update_data['update_time'] = date('Y-m-d H:i:s'); + //拒绝 + if ($param['status'] == 2) { + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $updateStatus = $this->updateUserAssetNew($order_info['user_id'], 6, $order_info['market_amount'], -$order_info['market_amount'], $order_info['order_no']); + }else{ + $updateStatus = $this->updateUserAsset($order_info['user_id'], $order_info['account_type'], 6, $order_info['market_amount'], -$order_info['market_amount'], $order_info['order_no']); + } + + } + + //代付 + if ($param['status'] == 3) { + //解冻资金 ,扣除提现 + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $updateOne = $this->updateUserAssetNew($order_info['user_id'], 6, $order_info['market_amount'], -$order_info['market_amount'], $order_info['order_no']); + }else{ + $updateOne = $this->updateUserAsset($order_info['user_id'], $order_info['account_type'], 6, $order_info['market_amount'], -$order_info['market_amount'], $order_info['order_no']); + } + + if (!empty($updateOne) && $updateOne['status'] == 200) { + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $updateStatus = $this->updateUserAssetNew($order_info['user_id'], 2, -$order_info['market_amount'], 0, $order_info['order_no']); + }else{ + $updateStatus = $this->updateUserAsset($order_info['user_id'], $order_info['account_type'], 2, -$order_info['market_amount'], 0, $order_info['order_no']); + } + + } else { + //提现事务回滚... + trace("提现失败1 - change_status - order_no=" . $order_info['order_no'] . "---user_id= " . $order_info['user_id'] . "---account_type= " . $order_info['account_type'] . "---market_amount= " . $order_info['market_amount']); + return $this->toData($updateOne['status'] ?? '3251', $updateOne['msg'] ?? $msg, [$content]); + } + + if (!empty($updateStatus) && $updateStatus['status'] == 200) { + $channel = PaymentListModel::getPaymentInfo([ + 'id' => $param['channel'] + ]); + if ($channel) { + $result = $this->payToUser($order_info, $channel); + if ($result['code'] == 200) { + $update_data['order_idx'] = $result['order_idx']; + $update_data['channel_id'] = $param['channel']; + } else { + $update_data['status'] = 1; //代付失败 + $pay_flag = true; + $content = $result['content']; + $msg = $result['msg']; + } + } + //手动支付完成 + if ($param['channel'] == 0) { + $update_data['status'] = 4; + $update_data['channel_id'] = $param['channel']; + } + } + } + + $update_data['beizhu'] = $param['beizhu'] ?? ""; + + if ($param['status'] == 1 || (!empty($updateStatus) && $updateStatus['status'] == 200)) { + UserWithdrawalModel::where($where)->update($update_data); + } else { + trace("提现失败2 - change_status - order_no=" . $order_info['order_no'] . "---user_id= " . $order_info['user_id'] . "---account_type= " . $order_info['account_type'] . "---market_amount= " . $order_info['market_amount']); + return $this->toData($updateStatus['status'] ?? '3251', $updateStatus['msg'] ?? $msg, [$content]); + } + + if ($pay_flag) { + return $this->toData('3250', $msg, [$content]); + } else { + return $this->toData('0', 'SUCCESS'); + } + + } else { + return $this->toData('10040', '操作流程不合法'); + } + + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + private function payToUser($order, $channel) + { + //货币单位换算 + $order['total_amount'] = $order['apply_num'] * $channel['exchange_rate']; + $address_info = json_decode($order['pay_info'], true); + + switch ($channel['type']) { + //印尼支付 + case 2: + return (new IndPayService())->singleIndOrder($order); + break; + //TRC + case 3: + return (new MoPayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['bank_code'], $address_info['bank_card'], $address_info['true_name'], $address_info['bank_phone'], $address_info['ifsc']); + break; + //合泰 + case 4: + return (new HTPayService())->arPay($order['order_no'], $order['total_amount'], $address_info['bank_code'], $address_info['bank_card'], $address_info['true_name']); + break; + //合泰 + case 5: + return (new XdPayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['ifsc'], $address_info['bank_card'], $address_info['true_name']); + break; + //QEAE + case 6: + return (new QeaePayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['bank_card'], $address_info['true_name'], $address_info['ifsc'], $address_info['bank_code']); + break; + //合泰 + case 7: + return (new NicePayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['bank_card'], $address_info['true_name'], $address_info['ifsc']); + break; + //ClickPay + case 8: + return (new ClickPayService())->apply_pay($order['order_no'], $order['total_amount'], $address_info['bank_card'], $address_info['true_name'], $address_info['ifsc'], $address_info['bank_code']); + break; + default: + + break; + } + } + + public function get_balance($param, $adminId) + { + $channel = PaymentListModel::getPaymentInfo([ + 'id' => intval($param['id']) + ]); + if ($channel) { + switch ($channel['type']) { + case 1: + //$result=(new IndPayService())->getIndBalance(); + $result = [ + 'amount' => 0 + ]; + break; + case 2: + $result = (new TrcPayService())->getTrcBalance(); + break; + case 4: + $result = (new HTPayService())->getHtBalance(); + break; + case 5: + $result = (new XdPayService())->getBalance(); + break; + case 6: + $result = (new QeaePayService())->getBalance(); + break; + case 8: + $result = (new ClickPayService())->getBalance(); + break; + default: + $result = [ + 'amount' => 0 + ]; + break; + } + + return $this->toData('0', '请求成功', $result); + + } else { + return $this->toData('1', '参数错误,通道不存在', []); + } + } + + public function channel_list($param, $adminId) + { + try { + // 参数校验 + validate(WithdrawValidate::class)->scene('info')->check($param); + $where = [ + 'id' => $param['id'] + ]; + + $userId = 0; + $where = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($where)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => []]); + } + + $order_info = UserWithdrawalModel::getUserDrawalInfo($where); + if ($order_info) { + $channel_list = PaymentListModel::getPaymentList([ + 'is_withdrawal' => 1, + 'status' => 1, + 'channel_type' => $order_info['apply_type'] + ]); + } else { + $channel_list = []; + } + return $this->toData('0', '请求成功', $channel_list); + } catch (\Exception $exception) { + return $this->toData('1', '系统异常 请稍后重试', [$exception->getMessage(), $exception->getTrace()]); + } + } + + +} \ No newline at end of file diff --git a/app/admin/service/auth/AuthRoleService.php b/app/admin/service/auth/AuthRoleService.php new file mode 100644 index 0000000..b74f47c --- /dev/null +++ b/app/admin/service/auth/AuthRoleService.php @@ -0,0 +1,148 @@ +scene('add')->check($param); + // 查找角色是否存在 + $authRole=new AuthRoleModel(); + $rule = $authRole->where('name',$param['name'])->find(); + if(!empty($rule)){ + return $this->toData('200100', '名称已存在', []); + } + $authRole->save($param); + return $this->toData('0', '添加成功.', []); + }catch (ValidateException $validateException){ + $message = $validateException->getError(); + return $this->toData('100400', $message); + }catch (\Exception $exception){ + return $this->toData('100500', '系统繁忙.', [$exception->getMessage()]); + } + + } + + + public function list($param){ + try { + $authRole=new AuthRoleModel(); + //查询条件 + if(isset($param['name'])&&!empty($param['name'])){ + $authRole=$authRole->where('name',$param['name']); + } + if(isset($param['satus'])&&!empty($param['status'])){ + $authRole=$authRole->where('status',$param['status']); + } + // 总数 + $total = $authRole->count(); + $list=$authRole->order('sort', 'asc')->page($param['page'], $param['limit'])->select(); + for($i=0;$itoData('0', 'SUCCESS', ['total' => $total, 'list' => $list]); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + public function updateStatus($id, $param): array + { + try { + // 主键 + if(empty($id) || $id <= 0){ + return $this->toData('200403', 'id字段丢失', []); + } + // 参数校验 + validate(AuthRoleValidate::class)->scene('updateStatus')->check($param); + // 查找用户信息 + $authRole = AuthRoleModel::find($id); + if(empty($authRole)){ + return $this->toData('200403', '该角色不存在.', []); + } + $authRole->status=$param['status']; + $authRole->save(); + // 返回 + return $this->toData('0', 'Modification successful.', []); + }catch (ValidateException $validateException){ + $message = $validateException->getError(); + return $this->toData('200400', $message); + }catch (\Exception $exception){ + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + public function allList($param){ + try { + $authRole=new AuthRoleModel(); + //查询条件 + if(isset($param['name'])&&!empty($param['name'])){ + $authRole=$authRole->where('name',$param['name']); + } + if(isset($param['satus'])&&!empty($param['status'])){ + $authRole=$authRole->where('status',$param['status']); + } + $list=$authRole->order('sort', 'asc')->column('name,id'); + return $this->toData('0', 'SUCCESS', $list); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function edit($id, $param): array + { + try { + // 主键 + if(empty($id) || $id <= 0){ + return $this->toData('200403', 'id字段丢失', []); + } + // 参数校验 + validate(AuthRoleValidate::class)->scene('edit')->check($param); + // 查找用户信息 + $authRole = AuthRoleModel::find($id); + if(empty($authRole)){ + return $this->toData('200403', '该规则不存在.', []); + } + $authRole->withoutField('id')->save($param); + // 返回 + return $this->toData('0', 'Modification successful.', []); + }catch (ValidateException $validateException){ + $message = $validateException->getError(); + return $this->toData('200400', $message); + }catch (\Exception $exception){ + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + public function del($id): array + { + try { + $authRole = AuthRoleModel::find($id); + $authRole->delete(); + // 返回 + return $this->toData('0', 'Modification successful.', []); + }catch (ValidateException $validateException){ + $message = $validateException->getError(); + return $this->toData('200400', $message); + }catch (\Exception $exception){ + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } +} diff --git a/app/admin/service/auth/AuthRuleService.php b/app/admin/service/auth/AuthRuleService.php new file mode 100644 index 0000000..0e91c9e --- /dev/null +++ b/app/admin/service/auth/AuthRuleService.php @@ -0,0 +1,216 @@ +scene('add')->check($param); + $this->verifyRepeat($param); + $authRule=new AuthRuleModel(); + $authRule->create($param); + return $this->toData('0', '添加成功.', []); + }catch (ValidateException $validateException){ + $message = $validateException->getError(); + return $this->toData('100400', $message); + }catch (\Exception $exception){ + return $this->toData('100500', '系统繁忙.', [$exception->getMessage()]); + } + + } + + /** + * 查重验证 + * @param $param + * @return void + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function verifyRepeat($param){ + $authRule=new AuthRuleModel(); + if(isset($param['id'])){ //编辑 + $authRule=$authRule->whereNotIn('id',[$param['id']]); + } + $rule = (clone $authRule)->where('name',$param['name'])->find(); + if(!empty($rule)){ + throw new ValidateException('权限标识已存在'); + } + + if($param['type']=='menu'){ + $rule = (clone $authRule)->where('path', $param['path'])->find(); + if(!empty($rule)){ + throw new ValidateException('路由地址已存在'); + } + $rule = (clone $authRule)->where('component',$param['component'])->find(); + if(!empty($rule)){ + throw new ValidateException('组件已存在'); + } + } + if($param['type']=='catelog'){ + $rule = (clone $authRule)->where('path',$param['path'])->find(); + if(!empty($rule)){ + throw new ValidateException('路由地址已存在'); + } + } + + } + + public function list($user_id,$param){ + try { + $authRule=new AuthRuleModel(); + //查询条件 + if(isset($param['name'])&&!empty($param['name'])){ + $authRule=$authRule->where('name',$param['name']); + } + if(isset($param['satus'])&&!empty($param['status'])){ + $authRule=$authRule->where('status',$param['status']); + } + + //获取用户权限id + $user=AdminModel::find($user_id); + //查询拥有权限 + if($user->role_id=='7'){ + //超级管理员拥有全部权限 + $list=$authRule::order('sort', 'asc')->select()->toArray(); + }else{ + $role=AuthRoleModel::find($user->role_id); + $list=$authRule::whereIn('id',$role->rules)->order('sort', 'asc')->select()->toArray(); + } + + // 总数 +// $total = $authRule->count(); +// $list=$authRule->order('sort', 'asc')->select()->toArray(); + $list=$this->getTreeMenu($list,0,true); + + + return $this->toData('0', 'SUCCESS', $list); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + public function allList($user_id){ + try { + //获取用户权限id + $user=AdminModel::find($user_id); + + //查询拥有权限 + if($user->role_id=='7'){ + //超级管理员拥有全部权限 + $list=AuthRuleModel::order('sort', 'asc')->select()->toArray(); + }else{ + $role=AuthRoleModel::find($user->role_id); + $list=AuthRuleModel::whereIn('id',$role->rules)->order('sort', 'asc')->select()->toArray(); + } +// $list=$authRule->order('sort', 'asc')->select()->toArray(); + $list=$this->getTreeMenu($list,0,true); + return $this->toData('0', 'SUCCESS',$list); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + public function edit($id, $param): array + { + try { + // 主键 + if(empty($id) || $id <= 0){ + return $this->toData('200403', 'id字段丢失', []); + } + // 参数校验 + validate(AuthRuleValidate::class)->scene('edit')->check($param); + // 查找用户信息 + $authRule = AuthRuleModel::find($id); + if(empty($authRule)){ + return $this->toData('200403', 'Please log in first.', []); + } + $this->verifyRepeat($param); + $authRule->save($param); + // 返回 + return $this->toData('0', 'Modification successful.', []); + }catch (ValidateException $validateException){ + $message = $validateException->getError(); + return $this->toData('200400', $message); + }catch (\Exception $exception){ + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + public function getSideMenu($user_id){ + try { + //获取用户权限id + $user=AdminModel::find($user_id); + $role=AuthRoleModel::find($user->role_id); + //查询拥有权限 + if($user->role_id=='7'){ + //超级管理员拥有全部权限 + $authRule=AuthRuleModel::order('sort', 'asc')->select()->toArray(); + }else{ + $role=AuthRoleModel::find($user->role_id); + $authRule=AuthRuleModel::whereIn('id',$role->rules)->order('sort', 'asc')->select()->toArray(); + } +// $authRule=AuthRuleModel::whereIn('id',$role->rules)->order('sort', 'asc')->select()->toArray(); +// $authRule=AuthRuleModel::order('sort', 'asc')->select()->toArray();//显示全部 + $menus=[]; + for($i=0;$i$authRule[$i]['id'], + 'pid'=>$authRule[$i]['pid'], + 'path'=>$authRule[$i]['path'], + 'name'=>$authRule[$i]['name'], + 'component'=>$authRule[$i]['component'], + 'redirect'=>$authRule[$i]['redirect'], + 'meta'=>[ + 'title'=>$authRule[$i]['title'], + 'hideMenu'=>$authRule[$i]['show']===1?false:true, + 'icon'=>$authRule[$i]['icon'], + 'ignoreKeepAlive'=>true, + 'isLink'=>false, +// 'currentActiveMenu'=>"", + ] + ]; + array_push($menus,$menuItem); + } + + $list=$this->getTreeMenu($menus,0,true); + + return $this->toData('0', 'SUCCESS',$list); + + }catch (ValidateException $validateException){ + $message = $validateException->getError(); + return $this->toData('200400', $message); + }catch (\Exception $exception){ + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + } + + /** + * @param $id + * @return array + */ + public function del($id): array + { + try { + $authRule = AuthRuleModel::find($id); + $authRule->delete(); + // 返回 + return $this->toData('0', 'Modification successful.', []); + }catch (ValidateException $validateException){ + $message = $validateException->getError(); + return $this->toData('200400', $message); + }catch (\Exception $exception){ + return $this->toData('200500', 'The system is busy.', [$exception->getMessage()]); + } + + } + +} diff --git a/app/admin/service/document/AnnouncementService.php b/app/admin/service/document/AnnouncementService.php new file mode 100644 index 0000000..df31bb1 --- /dev/null +++ b/app/admin/service/document/AnnouncementService.php @@ -0,0 +1,200 @@ +field('id,lang,name,title,status,weight') + ->order('name', 'asc') + ->order('weight', 'desc')->select(); + if(!$list->isEmpty()){ + $rows = $list->toArray(); + $lang = LanguageSettingModel::where('id', '>', 0)->column('china_name', 'id'); + foreach ($rows as $key=>$item){ + $rows[$key]['lang'] = $lang[$item['lang']] ?? '-'; + $rows[$key]['status'] = AnnouncementModel::STATUS_MAP[$item['status']] ?? '-'; + } + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function add($param) + { + try { + $langIds = LanguageSettingModel::column('id'); + if(empty($param['lang']) || !in_array($param['lang'], $langIds)){ + return $this->toData('1', '语言类型无效'); + } + + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + if(empty($param['title']) || !is_string($param['title'])){ + return $this->toData('1', '标题无效'); + } + + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + if(!isset($param['weight']) || !is_numeric($param['weight']) || ceil($param['weight']) != $param['weight'] || $param['weight'] < 0){ + return $this->toData('1', '权重无效'); + } + + if(!isset($param['status']) || !in_array($param['status'], [1,2])){ + return $this->toData('1', '状态无效'); + } +// +// if(!isset($param['is_pop_ups']) || !in_array($param['is_pop_ups'], [1,2])){ +// return $this->toData('1', 'h5弹窗状态无效'); +// } + + $docExists = AnnouncementModel::where('is_delete', AnnouncementModel::IS_DELETE_NO) + ->where('name', $param['name']) + ->where('lang', $param['lang'])->find(); + if(!empty($docExists)){ + return $this->toData('1', '已存在相同内容'); + } + + $doc = new AnnouncementModel; + $doc->lang = $param['lang']; + $doc->title = $param['title']; + $doc->content = $param['content']; + $doc->status = $param['status']; + $doc->weight = $param['weight']; + if (!empty($param['is_pop_ups'])) $doc->is_pop_ups = $param['is_pop_ups']; + $doc->create_time = date('Y-m-d H:i:s'); + $doc->update_time = date('Y-m-d H:i:s'); + $doc->name = $param['name']; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function detail($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = AnnouncementModel::where('id', $param['id']) + ->where('is_delete', AnnouncementModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $docArr = $doc->toArray(); + + return $this->toData('0', 'SUCCESS', ['row' => $docArr,]); + + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = AnnouncementModel::where('id', $param['id']) + ->where('is_delete', AnnouncementModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + + $langIds = LanguageSettingModel::column('id'); + if(empty($param['lang']) || !in_array($param['lang'], $langIds)){ + return $this->toData('1', '语言类型无效'); + } + + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + if(empty($param['title']) || !is_string($param['title'])){ + return $this->toData('1', '标题无效'); + } + + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + if(!isset($param['weight']) || !is_numeric($param['weight']) || ceil($param['weight']) != $param['weight'] || $param['weight'] < 0){ + return $this->toData('1', '权重无效'); + } + + if(!isset($param['status']) || !in_array($param['status'], [1,2])){ + return $this->toData('1', '状态无效'); + } + +// $docExists = AnnouncementModel::where('is_delete', AnnouncementModel::IS_DELETE_NO) +// ->where('id', '<>', $param['id']) +// ->where('name', $param['name']) +// ->where('lang', $param['lang'])->find(); +// if(!empty($docExists)){ +// return $this->toData('1', '已存在相同内容'); +// } + + $doc->lang = $param['lang']; + $doc->title = $param['title']; + $doc->content = $param['content']; + $doc->status = $param['status']; + $doc->weight = $param['weight']; + if (!empty($param['is_pop_ups'])) $doc->is_pop_ups = $param['is_pop_ups']; + $doc->update_time = date('Y-m-d H:i:s'); + $doc->name = $param['name']; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function del($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = AnnouncementModel::where('id', $param['id']) + ->where('is_delete', AnnouncementModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $doc->is_delete = AnnouncementModel::IS_DELETE_YES; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/document/BannerService.php b/app/admin/service/document/BannerService.php new file mode 100644 index 0000000..df36d2f --- /dev/null +++ b/app/admin/service/document/BannerService.php @@ -0,0 +1,196 @@ +field('id,lang,path,name,title,status') + ->order('name', 'asc') + ->select(); + if(!$list->isEmpty()){ + $rows = $list->toArray(); + $lang = LanguageSettingModel::where('id', '>', 0)->column('china_name', 'id'); + foreach ($rows as $key=>$item){ + $rows[$key]['lang'] = $lang[$item['lang']] ?? '-'; + $rows[$key]['status'] = BannerModel::STATUS_MAP[$item['status']] ?? '-'; + } + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function add($param) + { + try { + + $langIds = LanguageSettingModel::column('id'); + if(empty($param['lang']) || !in_array($param['lang'], $langIds)){ + return $this->toData('1', '语言类型无效'); + } + + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + if(empty($param['title']) || !is_string($param['title'])){ + return $this->toData('1', '标题无效'); + } + + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + if(empty($param['path']) || !is_string($param['path'])){ + return $this->toData('1', '图片路径无效'); + } + + + if(!isset($param['status']) || !in_array($param['status'], [1,2])){ + return $this->toData('1', '状态无效'); + } + + $docExists = BannerModel::where('is_delete', BannerModel::IS_DELETE_NO) + ->where('name', $param['name']) + ->where('lang', $param['lang'])->find(); + if(!empty($docExists)){ + return $this->toData('1', '已存在相同内容'); + } + + $doc = new BannerModel(); + $doc->lang = $param['lang']; + $doc->path = $param['path']; + $doc->title = $param['title']; + $doc->content = $param['content']; + $doc->status = $param['status']; + $doc->create_time = date('Y-m-d H:i:s'); + $doc->update_time = date('Y-m-d H:i:s'); + $doc->name = $param['name']; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function detail($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = BannerModel::where('id', $param['id']) + ->where('is_delete', BannerModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $docArr = $doc->toArray(); + + return $this->toData('0', 'SUCCESS', ['row' => $docArr]); + + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = BannerModel::where('id', $param['id']) + ->where('is_delete', BannerModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $langIds = LanguageSettingModel::column('id'); + if(empty($param['lang']) || !in_array($param['lang'], $langIds)){ + return $this->toData('1', '语言类型无效'); + } + + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + if(empty($param['title']) || !is_string($param['title'])){ + return $this->toData('1', '标题无效'); + } + + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + if(empty($param['path']) || !is_string($param['path'])){ + return $this->toData('1', '图片路径无效'); + } + + if(!isset($param['status']) || !in_array($param['status'], [1,2])){ + return $this->toData('1', '状态无效'); + } + + $docExists = BannerModel::where('is_delete', BannerModel::IS_DELETE_NO) + ->where('id', '<>', $param['id']) + ->where('name', $param['name']) + ->where('lang', $param['lang'])->find(); + if(!empty($docExists)){ + return $this->toData('1', '已存在相同内容'); + } + + $doc->lang = $param['lang']; + $doc->title = $param['title']; + $doc->content = $param['content']; + $doc->status = $param['status']; + $doc->path = $param['path']; + $doc->update_time = date('Y-m-d H:i:s'); + $doc->name = $param['name']; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function del($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = BannerModel::where('id', $param['id']) + ->where('is_delete', BannerModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $doc->is_delete = BannerModel::IS_DELETE_YES; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/document/FaqService.php b/app/admin/service/document/FaqService.php new file mode 100644 index 0000000..2c300ed --- /dev/null +++ b/app/admin/service/document/FaqService.php @@ -0,0 +1,195 @@ +field('id,lang,name,title,status,weight') + ->order('name', 'asc') + ->order('weight', 'desc')->select(); + if(!$list->isEmpty()){ + $rows = $list->toArray(); + $lang = LanguageSettingModel::where('id', '>', 0)->column('china_name', 'id'); + foreach ($rows as $key=>$item){ + $rows[$key]['lang'] = $lang[$item['lang']] ?? '-'; + $rows[$key]['status'] = FaqModel::STATUS_MAP[$item['status']] ?? '-'; + } + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function add($param) + { + try { + $langIds = LanguageSettingModel::column('id'); + if(empty($param['lang']) || !in_array($param['lang'], $langIds)){ + return $this->toData('1', '语言类型无效'); + } + + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + if(empty($param['title']) || !is_string($param['title'])){ + return $this->toData('1', '标题无效'); + } + + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + if(!isset($param['weight']) || !is_numeric($param['weight']) || ceil($param['weight']) != $param['weight'] || $param['weight'] < 0){ + return $this->toData('1', '权重无效'); + } + + if(!isset($param['status']) || !in_array($param['status'], [1,2])){ + return $this->toData('1', '状态无效'); + } + + $docExists = FaqModel::where('is_delete', FaqModel::IS_DELETE_NO) + ->where('name', $param['name']) + ->where('lang', $param['lang'])->find(); + if(!empty($docExists)){ + return $this->toData('1', '已存在相同内容'); + } + + $doc = new FaqModel; + $doc->lang = $param['lang']; + $doc->title = $param['title']; + $doc->content = $param['content']; + $doc->status = $param['status']; + $doc->weight = $param['weight']; + $doc->create_time = date('Y-m-d H:i:s'); + $doc->update_time = date('Y-m-d H:i:s'); + $doc->name = $param['name']; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function detail($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = FaqModel::where('id', $param['id']) + ->where('is_delete', FaqModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $docArr = $doc->toArray(); + + return $this->toData('0', 'SUCCESS', ['row' => $docArr,]); + + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = FaqModel::where('id', $param['id']) + ->where('is_delete', FaqModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + + $langIds = LanguageSettingModel::column('id'); + if(empty($param['lang']) || !in_array($param['lang'], $langIds)){ + return $this->toData('1', '语言类型无效'); + } + + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + if(empty($param['title']) || !is_string($param['title'])){ + return $this->toData('1', '标题无效'); + } + + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + if(!isset($param['weight']) || !is_numeric($param['weight']) || ceil($param['weight']) != $param['weight'] || $param['weight'] < 0){ + return $this->toData('1', '权重无效'); + } + + if(!isset($param['status']) || !in_array($param['status'], [1,2])){ + return $this->toData('1', '状态无效'); + } + + $docExists = FaqModel::where('is_delete', FaqModel::IS_DELETE_NO) + ->where('id', '<>', $param['id']) + ->where('name', $param['name']) + ->where('lang', $param['lang'])->find(); + if(!empty($docExists)){ + return $this->toData('1', '已存在相同内容'); + } + + $doc->lang = $param['lang']; + $doc->title = $param['title']; + $doc->content = $param['content']; + $doc->status = $param['status']; + $doc->weight = $param['weight']; + $doc->update_time = date('Y-m-d H:i:s'); + $doc->name = $param['name']; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function del($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = FaqModel::where('id', $param['id']) + ->where('is_delete', FaqModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $doc->is_delete = FaqModel::IS_DELETE_YES; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/document/IndexService.php b/app/admin/service/document/IndexService.php new file mode 100644 index 0000000..6046804 --- /dev/null +++ b/app/admin/service/document/IndexService.php @@ -0,0 +1,211 @@ +field('id,lang,type,name,title,status,weight') + ->order('type', 'asc') + ->order('name', 'asc') + ->order('weight', 'desc')->select(); + if(!$list->isEmpty()){ + $rows = $list->toArray(); + $lang = LanguageSettingModel::where('id', '>', 0)->column('china_name', 'id'); + foreach ($rows as $key=>$item){ + $rows[$key]['type'] = DocumentModel::TYPE_MAP[$item['type']] ?? '-'; + $rows[$key]['lang'] = $lang[$item['lang']] ?? '-'; + $rows[$key]['status'] = DocumentModel::STATUS_MAP[$item['status']] ?? '-'; + } + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows),'extend' => ['typeMap' => DocumentModel::TYPE_MAP]]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function add($param) + { + try { + $typeMapKeys = array_keys(DocumentModel::TYPE_MAP); + if(empty($param['type']) || !in_array($param['type'],$typeMapKeys)){ + return $this->toData('1', '文章类型无效'); + } + + $langIds = LanguageSettingModel::column('id'); + if(empty($param['lang']) || !in_array($param['lang'], $langIds)){ + return $this->toData('1', '语言类型无效'); + } + + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + if(empty($param['title']) || !is_string($param['title'])){ + return $this->toData('1', '标题无效'); + } + + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + if(!isset($param['weight']) || !is_numeric($param['weight']) || ceil($param['weight']) != $param['weight'] || $param['weight'] < 0){ + return $this->toData('1', '权重无效'); + } + + if(!isset($param['status']) || !in_array($param['status'], [1,2])){ + return $this->toData('1', '状态无效'); + } + + $docExists = DocumentModel::where('type', $param['type']) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->where('name', $param['name']) + ->where('lang', $param['lang'])->find(); + if(!empty($docExists)){ + return $this->toData('1', '已存在相同内容'); + } + + $doc = new DocumentModel; + $doc->lang = $param['lang']; + $doc->type = $param['type']; + $doc->title = $param['title']; + $doc->content = $param['content']; + $doc->status = $param['status']; + $doc->weight = $param['weight']; + $doc->create_time = date('Y-m-d H:i:s'); + $doc->update_time = date('Y-m-d H:i:s'); + $doc->name = $param['name']; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function detail($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = DocumentModel::where('id', $param['id']) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $docArr = $doc->toArray(); + + return $this->toData('0', 'SUCCESS', ['row' => $docArr, + 'extend' => ['typeMap' => DocumentModel::TYPE_MAP]]); + + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = DocumentModel::where('id', $param['id']) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $typeMapKeys = array_keys(DocumentModel::TYPE_MAP); + if(empty($param['type']) || !in_array($param['type'],$typeMapKeys)){ + return $this->toData('1', '文章类型无效'); + } + + $langIds = LanguageSettingModel::column('id'); + if(empty($param['lang']) || !in_array($param['lang'], $langIds)){ + return $this->toData('1', '语言类型无效'); + } + + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + if(empty($param['title']) || !is_string($param['title'])){ + return $this->toData('1', '标题无效'); + } + + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + if(!isset($param['weight']) || !is_numeric($param['weight']) || ceil($param['weight']) != $param['weight'] || $param['weight'] < 0){ + return $this->toData('1', '权重无效'); + } + + if(!isset($param['status']) || !in_array($param['status'], [1,2])){ + return $this->toData('1', '状态无效'); + } + + $docExists = DocumentModel::where('type', $param['type']) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->where('id', '<>', $param['id']) + ->where('name', $param['name']) + ->where('lang', $param['lang'])->find(); + if(!empty($docExists)){ + return $this->toData('1', '已存在相同内容'); + } + + $doc->lang = $param['lang']; + $doc->type = $param['type']; + $doc->title = $param['title']; + $doc->content = $param['content']; + $doc->status = $param['status']; + $doc->weight = $param['weight']; + $doc->update_time = date('Y-m-d H:i:s'); + $doc->name = $param['name']; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function del($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = DocumentModel::where('id', $param['id']) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $doc->is_delete = DocumentModel::IS_DELETE_YES; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/document/LandingPageService.php b/app/admin/service/document/LandingPageService.php new file mode 100644 index 0000000..c9f6ece --- /dev/null +++ b/app/admin/service/document/LandingPageService.php @@ -0,0 +1,148 @@ +order('id', 'desc')->select(); + if(!$list->isEmpty()){ + $rows = $list->toArray(); + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function add($param): array + { + try { + + // 名称 + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + // 内容 + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + // 跳转地址 + if(empty($param['link_url']) || !is_string($param['link_url'])){ + $param['link_url'] = ''; + } + + if(!isset($param['status']) || !in_array($param['status'], [LandingPageModel::STATUS_ON, LandingPageModel::STATUS_OFF])){ + return $this->toData('1', '状态无效'); + } + + $docExists = LandingPageModel::where('is_delete', LandingPageModel::IS_DELETE_NO) + ->where('name', $param['name']) + ->find(); + if(!empty($docExists)){ + return $this->toData('1', '已存在相同内容'); + } + + $doc = new LandingPageModel; + $doc->name = $param['name']; + $doc->content = $param['content']; + $doc->click_num = 0; + $doc->link_url = 0; + $doc->is_delete = 0; + $doc->status = 0; + $doc->create_time = date('Y-m-d H:i:s'); + $doc->update_time = date('Y-m-d H:i:s'); + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function edit($param): array + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = LandingPageModel::where('id', $param['id']) + ->where('is_delete', LandingPageModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + // 名称 + if(empty($param['name']) || !is_string($param['name'])){ + return $this->toData('1', '名称无效'); + } + + // 内容 + if(empty($param['content']) || !is_string($param['content'])){ + return $this->toData('1', '内容无效'); + } + + // 跳转地址 + if(empty($param['link_url']) || !is_string($param['link_url'])){ + $param['link_url'] = ''; + } + + if(!isset($param['status']) || !in_array($param['status'], [LandingPageModel::STATUS_ON, LandingPageModel::STATUS_OFF])){ + return $this->toData('1', '状态无效'); + } + + $docExists = LandingPageModel::where('is_delete', LandingPageModel::IS_DELETE_NO) + ->where('id', '<>', $param['id']) + ->where('name', $param['name'])->find(); + if(!empty($docExists)){ + return $this->toData('1', '已存在相同内容'); + } + + $doc->name = $param['name']; + $doc->content = $param['content']; + $doc->status = $param['status']; + $doc->link_url = $param['link_url']; + $doc->update_time = date('Y-m-d H:i:s'); + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function del($param): array + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在'); + } + + $doc = LandingPageModel::where('id', $param['id']) + ->where('is_delete', LandingPageModel::IS_DELETE_NO) + ->find(); + if(empty($doc)){ + return $this->toData('1', '目标不存在'); + } + + $doc->is_delete = LandingPageModel::IS_DELETE_YES; + $doc->save(); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/BlockStockService.php b/app/admin/service/setting/BlockStockService.php new file mode 100644 index 0000000..84162e4 --- /dev/null +++ b/app/admin/service/setting/BlockStockService.php @@ -0,0 +1,422 @@ +toData('1', '分页参数错误'); + } + + $where = []; + // 未删除 + $where[] = [ + 'is_delete', '=', StockBlockListModel::IS_DELETE_NO + ]; + // 股票号 + if (!empty($param['stock_code']) && is_string($param['stock_code'])) { + $where[] = [ + 'stock_code', '=', $param['stock_code'] + ]; + } + + // 状态 + if (!empty($param['status']) && in_array($param['status'], [StockBlockListModel::STATUS_ON, StockBlockListModel::STATUS_OFF])) { + $where[] = [ + 'status', '=', $param['status'] + ]; + } + + $query = StockBlockListModel::where($where); + $totalQuery = StockBlockListModel::where($where); + $list = $query->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + $total = $totalQuery->order('id', 'desc')->count(); + + + return $this->toData('0', 'SUCCESS', ['list' => $list, 'total' => $total, 'extend' => [ +// 'tape_list' => StockBlockListModel::$tapeList, + 'stock_type_list' => StockBlockListModel::$typeList, + ]]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 新增 + public function add($param) + { + try { + // 股票代码 + if (empty($param['stock_code']) || !is_string($param['stock_code'])) { + return $this->toData('1', '股票代码 无效'); + } + + + // 股票类型 + if (empty($param['type']) || !in_array($param['type'], array_keys(StockBlockListModel::$typeList))) { + return $this->toData('1', '股票市场 无效'); + } + + // 交易所类型 +// if(empty($param['tape']) || !in_array($param['tape'], array_keys(StockBlockListModel::$tapeList))){ +// return $this->toData('1', '交易所类型 无效'); +// } + + switch ($param['type']) { + case '3': + $stock = StockListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '4': + $stock = StockIdnListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '5': + $stock = StockMysListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '6': + $stock = StockThaListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '7': + $stock = StockInListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '9': + $stock = StockSgdListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '12': + $stock = StockHkdListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '14': + $stock = StockGBXListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '15': + $stock = StockFurListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '16': + $stock = StockEurListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '17': + $stock = StockBrlListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '18': + $stock = StockJpListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + default: + return $this->toData('1', '股票市场或股票代码 无效'); + } + + + // 发布状态 + if (empty($param['status']) || !in_array($param['status'], [StockBlockListModel::STATUS_ON, StockBlockListModel::STATUS_OFF])) { + return $this->toData('1', '发布状态 无效'); + } + + // 单股价格 + if (empty($param['price']) || !is_numeric($param['price']) || $param['price'] <= 0) { + return $this->toData('1', '单股价格 无效'); + } + + // 最小申购数量 + if (empty($param['min']) || !is_numeric($param['min']) || $param['min'] <= 0 || ceil($param['min']) != $param['min']) { + return $this->toData('1', '最小购买股数无效'); + } + + // 开始认购时间 + if (empty($param['start_time']) || !is_string($param['start_time'])) { + return $this->toData('1', '开始认购时间 无效'); + } + + // 认购结束时间 + if (empty($param['end_time']) || !is_string($param['end_time']) || strtotime($param['end_time']) <= strtotime($param['start_time'])) { + return $this->toData('1', '认购结束时间 无效'); + } + + // 可出售时间时间 + if (empty($param['today_add']) || !is_numeric($param['today_add'])) { + return $this->toData('1', 'T+n 无效'); + } + + // 新增数据 + $blockStock = new StockBlockListModel(); + $blockStock->stock_code = $param['stock_code']; + $blockStock->stock_name = $param['stock_name']; + $blockStock->type = $param['type']; + $blockStock->tape = $stock->tape; + $blockStock->status = $param['status']; + $blockStock->price = $param['price']; + $blockStock->min = $param['min']; + $blockStock->start_time = $param['start_time']; + $blockStock->end_time = $param['end_time']; + $blockStock->today_add = $param['today_add']; + $blockStock->keep_decimal = $stock->keep_decimal; + $blockStock->info = $param['info'] ?? ''; + $blockStock->forced_closure = $stock->forced_closure; + $blockStock->up_limit = $stock->up_limit;; + $blockStock->down_limit = $stock->down_limit; + $blockStock->buy_pwd = isset($param['buy_pwd']) ? trim($param['buy_pwd']) : '' ; + + $blockStock->create_time = date('Y-m-d H:i:s'); + $blockStock->update_time = date('Y-m-d H:i:s'); + $blockStock->save(); + + // 加入缓存 + $list_key = StockBlockListModel::$typeListEn[$param['type']] . ":BLOCK:LIST:" . $param['stock_code']; + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'stock_name' => $blockStock->stock_name, + 'stock_code' => $blockStock->stock_code, + 'status' => $blockStock->status, + 'keep_decimal' => $blockStock->keep_decimal, + 'forced_closure' => $blockStock->forced_closure, + 'up_limit' => $blockStock->up_limit, + 'down_limit' => $blockStock->down_limit, + 'info' => $blockStock->info, + 'tape' => $blockStock->tape, + 'price' => $blockStock->price, + 'min' => $blockStock->min, + 'start_time' => $blockStock->start_time, + 'end_time' => $blockStock->end_time, + 'today_add' => $blockStock->today_add, + 'buy_pwd'=>$blockStock->buy_pwd + ]); + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('0', '系统繁忙', [$exception->getMessage()]); + } + } + + // 编辑 + public function edit($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '主键 无效'); + } + + $blockStock = StockBlockListModel::where('id', $param['id'])->where('is_delete', StockBlockListModel::IS_DELETE_NO)->find(); + if (empty($blockStock)) { + return $this->toData('1', '主键 无效'); + } + +// // 已中签或者已上市不支持修改 +// if($blockStock->open_status == PreMysStockModel::OPEN_STATUS_HAD || strtotime($blockStock->get_time)<=time()){ +// return $this->toData('1', '已中签或已上市 不支持修改'); +// } + + // 股票代码 + if (empty($param['stock_code']) || !is_string($param['stock_code'])) { + return $this->toData('1', '股票代码 无效'); + } + + // 股票名称 + if (empty($param['stock_name']) || !is_string($param['stock_name'])) { + return $this->toData('1', '股票代码 无效'); + } + + // 股票类型 + if (empty($param['type']) || !in_array($param['type'], array_keys(StockBlockListModel::$typeList))) { + return $this->toData('1', '股票市场 无效'); + } + + switch ($param['type']) { + case '3': + $stock = StockListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '4': + $stock = StockIdnListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '5': + $stock = StockMysListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '6': + $stock = StockThaListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '7': + $stock = StockInListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '9': + $stock = StockSgdListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '12': + $stock = StockHkdListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '14': + $stock = StockGBXListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '15': + $stock = StockFurListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '16': + $stock = StockEurListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '17': + $stock = StockBrlListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + case '18': + $stock = StockJpListModel::where('stock_code', $param['stock_code'])->find(); + if (empty($stock)) return $this->toData('1', 'stock_code 无效'); + break; + default: + return $this->toData('1', '股票市场或股票代码 无效'); + } + + // 交易所类型 +// if(empty($param['tape']) || !in_array($param['tape'], array_keys(StockBlockListModel::$tapeList))){ +// return $this->toData('1', '交易所类型 无效'); +// } + + // 发布状态 + if (empty($param['status']) || !in_array($param['status'], [StockBlockListModel::STATUS_ON, StockBlockListModel::STATUS_OFF])) { + return $this->toData('1', '发布状态 无效'); + } + + // 单股价格 + if (empty($param['price']) || !is_numeric($param['price']) || $param['price'] <= 0) { + return $this->toData('1', '单股价格 无效'); + } + + // 最小申购数量 + if (empty($param['min']) || !is_numeric($param['min']) || $param['min'] <= 0 || ceil($param['min']) != $param['min']) { + return $this->toData('1', '最小购买股数无效'); + } + + // 开始认购时间 + if (empty($param['start_time']) || !is_string($param['start_time'])) { + return $this->toData('1', '开始认购时间 无效'); + } + + // 认购结束时间 + if (empty($param['end_time']) || !is_string($param['end_time']) || strtotime($param['end_time']) <= strtotime($param['start_time'])) { + return $this->toData('1', '认购结束时间 无效'); + } + + // 可出售时间时间 + if (empty($param['today_add']) || !is_numeric($param['today_add'])) { + return $this->toData('1', 'T+n 无效'); + } + + // 新增数据 + $blockStock->stock_code = $param['stock_code']; + $blockStock->stock_name = $param['stock_name']; + $blockStock->type = $param['type']; + $blockStock->tape = $stock->tape; + $blockStock->status = $param['status']; + $blockStock->price = $param['price']; + $blockStock->min = $param['min']; + $blockStock->start_time = $param['start_time']; + $blockStock->end_time = $param['end_time']; + $blockStock->today_add = $param['today_add']; + $blockStock->keep_decimal = $stock->keep_decimal; + $blockStock->info = $param['info'] ?? ''; + $blockStock->forced_closure = $stock->forced_closure; + $blockStock->up_limit = $stock->up_limit;; + $blockStock->down_limit = $stock->down_limit; + $blockStock->update_time = date('Y-m-d H:i:s'); + $blockStock->buy_pwd = trim($param['buy_pwd']); + $blockStock->save(); + + // 加入缓存 + $list_key = StockBlockListModel::$typeListEn[$param['type']] . ":BLOCK:LIST:" . $param['stock_code']; + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'stock_name' => $blockStock->stock_name, + 'stock_code' => $blockStock->stock_code, + 'status' => $blockStock->status, + 'keep_decimal' => $blockStock->keep_decimal, + 'forced_closure' => $blockStock->forced_closure, + 'up_limit' => $blockStock->up_limit, + 'down_limit' => $blockStock->down_limit, + 'info' => $blockStock->info, + 'tape' => $blockStock->tape, + 'price' => $blockStock->price, + 'min' => $blockStock->min, + 'start_time' => $blockStock->start_time, + 'end_time' => $blockStock->end_time, + 'today_add' => $blockStock->today_add, + 'buy_pwd'=>$blockStock->buy_pwd, + ]); + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('0', '系统繁忙', [$exception->getMessage()]); + } + } + +// //删除 +// public function del($param) +// { +// try { +// if (empty($param['id']) || !is_numeric($param['id'])) { +// return $this->toData('1', '主键 无效'); +// } +// +// $preInStock = StockBlockListModel::where('id', $param['id'])->where('is_delete', StockBlockListModel::IS_DELETE_NO)->find(); +// if (empty($preInStock)) { +// return $this->toData('1', '主键 无效'); +// } +// +// $orderList = UserMysPreStockOrderModel::where('pre_stock_id', $preInStock->id)->select(); +// if (!$orderList->isEmpty()) { +// return $this->toData('1', '已有申购订单不可删除'); +// } +// +// // 删除 +// $list_key = "MYS:STOCK:LIST:" . $preInStock->stock_code; +// $redis = $this->getRedis(); +// $redis->del($list_key); +// +// //删除 修改状态 +// $preInStock->is_delete = PreMysStockModel::IS_DELETE_YES; +// $preInStock->save(); +// return $this->toData('0', 'SUCCESS'); +// } catch (\Exception $exception) { +// return $this->toData('1', '系统繁忙', [$exception->getMessage()]); +// } +// } +} \ No newline at end of file diff --git a/app/admin/service/setting/BrokerageService.php b/app/admin/service/setting/BrokerageService.php new file mode 100644 index 0000000..72b4a6c --- /dev/null +++ b/app/admin/service/setting/BrokerageService.php @@ -0,0 +1,138 @@ +select(); + $rows = []; + if(!$list->isEmpty()){ + $rows = $list->toArray(); + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙'); + } + } + + public function add($param) + { + try { + if(!isset($param['brok_type']) || !in_array($param['brok_type'], [0,1,2])){ + return $this->toData('1', '返佣类型无效'); + } + + if(!isset($param['pay_type']) || !in_array($param['pay_type'], [0,1])){ + return $this->toData('1', '结算方式无效'); + } + + + if(!isset($param['parent_fee']) || !is_numeric($param['parent_fee']) || $param['parent_fee'] < 0){ + return $this->toData('1', '返佣比例无效1'); + } + + if(!isset($param['grandpa_fee']) || !is_numeric($param['grandpa_fee']) || $param['grandpa_fee'] < 0){ + return $this->toData('1', '返佣比例无效2'); + } + + if(!isset($param['top_fee']) || !is_numeric($param['top_fee']) || $param['top_fee'] < 0){ + return $this->toData('1', '返佣比例无效3'); + } + + if(isset($param['remark']) && (!is_string($param['remark']) || strlen($param['remark']) >= 15) ){ + return $this->toData('1', '备注无效'); + } + + $remark = $param['remark']?? ''; + + $brok = new BrokerageSettingModel; + $brok->brok_type = $param['brok_type']; + $brok->pay_type = $param['pay_type']; + $brok->parent_fee = $param['parent_fee']; + $brok->grandpa_fee = $param['grandpa_fee']; + $brok->top_fee = $param['top_fee']; + $brok->remark = $remark; + $brok->save(); + + $fee_key=$this->getBrokerageKey($param['brok_type']); + $redis = $this->getRedis(); + $redis->del($fee_key); + $redis->hMSet($fee_key, $param); + + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙'); + } + + } + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '主键无效'); + } + + $brok = BrokerageSettingModel::where('id', $param['id'])->find(); + if(empty($brok)){ + return $this->toData('1', '主键无效'); + } + + + if(!isset($param['brok_type']) || !in_array($param['brok_type'], [0,1,2])){ + return $this->toData('1', '返佣类型无效'); + } + + if(!isset($param['pay_type']) || !in_array($param['pay_type'], [0,1])){ + return $this->toData('1', '结算方式无效'); + } + + if(!isset($param['parent_fee']) || !is_numeric($param['parent_fee']) || $param['parent_fee'] < 0){ + return $this->toData('1', '返佣比例无效'); + } + + if(!isset($param['grandpa_fee']) || !is_numeric($param['grandpa_fee']) || $param['grandpa_fee'] < 0){ + return $this->toData('1', '返佣比例无效'); + } + + if(!isset($param['top_fee']) || !is_numeric($param['top_fee']) || $param['top_fee'] < 0){ + return $this->toData('1', '返佣比例无效'); + } + + if(isset($param['remark']) && (!is_string($param['remark']) || strlen($param['remark']) >= 15) ){ + return $this->toData('1', '备注无效'); + } + + $remark = $param['remark']?? ''; + + + $brok->brok_type = $param['brok_type']; + $brok->pay_type = $param['pay_type']; + $brok->parent_fee = $param['parent_fee']; + $brok->grandpa_fee = $param['grandpa_fee']; + $brok->top_fee = $param['top_fee']; + $brok->remark = $remark; + $brok->save(); + + $fee_key=$this->getBrokerageKey($param['brok_type']); + $redis = $this->getRedis(); + $redis->del($fee_key); + $redis->hMSet($fee_key, $param); + + return $this->toData('0', 'SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙'); + } + } + +} \ No newline at end of file diff --git a/app/admin/service/setting/ContractService.php b/app/admin/service/setting/ContractService.php new file mode 100644 index 0000000..101c8c8 --- /dev/null +++ b/app/admin/service/setting/ContractService.php @@ -0,0 +1,348 @@ +select(); + $rows = []; + if(!$list->isEmpty()){ + $rows =$list->toArray(); + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + // 新增 + public function add($param) + { + try { + // 交易对名称 + if(empty($param['trade_name']) || !is_string($param['trade_name']) || strlen($param['trade_name']) > 100){ + return $this->toData('1', '交易对名称无效', []); + } + + // 状态 + if(!isset($param['status']) || !in_array($param['status'], ['0', '1'])){ + return $this->toData('1', '状态无效', []); + } + + // 是否自发 + if(!isset($param['is_owner']) || !in_array($param['is_owner'], ['0', '1'])){ + return $this->toData('1', '是否自发无效', []); + } + + // 简介 + $info = ''; + if(isset($param['info']) && is_string($param['info'])){ + $info = $param['info']; + } + + // 面值 + if(!isset($param['face_value']) || !is_numeric($param['face_value']) || $param['face_value'] != ceil($param['face_value']) || $param['face_value'] <= 0){ + return $this->toData('1', '面值无效', []); + } + + + // 排序 + if(!isset($param['sort']) || !is_numeric($param['sort']) || $param['sort'] != ceil($param['sort']) || $param['sort'] < 0){ + return $this->toData('1', '排序值无效', []); + } + + // 最小杠杆 + if(empty($param['min_pry']) || !is_numeric($param['min_pry']) || $param['min_pry'] != ceil($param['min_pry']) || $param['min_pry'] <= 0){ + return $this->toData('1', '最小杠杆值无效', []); + } + + // 最大杠杆 + if(empty($param['max_pry']) || !is_numeric($param['max_pry']) || $param['max_pry'] != ceil($param['max_pry']) || $param['max_pry'] <= 0){ + return $this->toData('1', '最大杠杆值无效', []); + } + + // 强制平仓比例值 + if(empty($param['compel_num']) || !is_numeric($param['compel_num']) || $param['compel_num'] <= 0){ + return $this->toData('1', '强制平仓比例值无效', []); + } + + + // 小数位数 + if(!isset($param['keep_decimal']) || !is_numeric($param['keep_decimal']) || $param['keep_decimal'] != ceil($param['keep_decimal']) || $param['keep_decimal'] < 0){ + return $this->toData('1', '小数位数值无效', []); + } + + // 判断名称是否已被添加 + $count = ContractListMode::where('trade_name', $param['trade_name'])->count(); + if($count > 0){ + return $this->toData('1', '合约交易对名称已存在', []); + } + + $contract = new ContractListMode; + $contract->trade_name = $param['trade_name']; + $contract->status = $param['status']; + $contract->is_owner = $param['is_owner']; + $contract->info = $info; + $contract->logo_link = ''; + $contract->face_value = $param['face_value']; + $contract->sort = $param['sort']; + $contract->min_pry = $param['min_pry']; + $contract->max_pry = $param['max_pry']; + $contract->compel_num = $param['compel_num']; + $contract->keep_decimal = $param['keep_decimal']; + $contract->create_time = date('Y-m-d H:i:s'); + $contract->update_time = date('Y-m-d H:i:s'); + $contract->save(); + + $list_key="CONTRACT:LIST:".strtoupper($param['trade_name']); + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'name'=>strtoupper($param['trade_name']), + 'code'=>strtoupper($param['trade_name']), + 'sort'=>$param['sort'], + 'face_value'=>$param['face_value'], + 'min_pry'=>$param['min_pry'], + 'max_pry'=>$param['max_pry'], + 'compel_num'=>$param['compel_num'], + 'keep_decimal'=>$param['keep_decimal'], + 'is_owner'=>$param['is_owner'], + 'status'=>$param['status'] + ]); + + return $this->toData('0', '操作成功', []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在', []); + } + + $contract = ContractListMode::where('id', $param['id'])->find(); + $beforeStatus = $contract['status']; + if(empty($contract)){ + return $this->toData('1', '目标不存在', []); + } + + // 交易对名称 + if(empty($param['trade_name']) || !is_string($param['trade_name']) || strlen($param['trade_name']) > 100){ + return $this->toData('1', '交易对名称无效', []); + } + + // 状态 + if(!isset($param['status']) || !in_array($param['status'], ['0', '1'])){ + return $this->toData('1', '状态无效', []); + } + + // 是否自发 + if(!isset($param['is_owner']) || !in_array($param['is_owner'], ['0', '1'])){ + return $this->toData('1', '是否自发无效', []); + } + + // 简介 + $info = ''; + if(isset($param['info']) && is_string($param['info'])){ + $info = $param['info']; + } + + // 面值 + if(!isset($param['face_value']) || !is_numeric($param['face_value']) || $param['face_value'] != ceil($param['face_value']) || $param['face_value'] <= 0){ + return $this->toData('1', '面值无效', []); + } + + + // 排序 + if(!isset($param['sort']) || !is_numeric($param['sort']) || $param['sort'] != ceil($param['sort']) || $param['sort'] < 0){ + return $this->toData('1', '排序值无效', []); + } + + // 最小杠杆 + if(empty($param['min_pry']) || !is_numeric($param['min_pry']) || $param['min_pry'] != ceil($param['min_pry']) || $param['min_pry'] <= 0){ + return $this->toData('1', '最小杠杆值无效', []); + } + + // 最大杠杆 + if(empty($param['max_pry']) || !is_numeric($param['max_pry']) || $param['max_pry'] != ceil($param['max_pry']) || $param['max_pry'] <= 0){ + return $this->toData('1', '最大杠杆值无效', []); + } + + // 强制平仓比例值 + if(empty($param['compel_num']) || !is_numeric($param['compel_num']) || $param['compel_num'] <= 0){ + return $this->toData('1', '强制平仓比例值无效', []); + } + + // 小数位数 + if(!isset($param['keep_decimal']) || !is_numeric($param['keep_decimal']) || $param['keep_decimal'] != ceil($param['keep_decimal']) || $param['keep_decimal'] < 0){ + return $this->toData('1', '小数位数值无效', []); + } + + // 判断名称是否已被添加 + $count = ContractListMode::where('trade_name', $param['trade_name'])->where('id', '<>', $param['id'])->count(); + if($count > 0){ + return $this->toData('1', '合约交易对名称已存在', []); + } + + // 如果状态设置成关闭 则判断是否有正在交易的合约 + if($beforeStatus == 1 && $param['status'] == 0){ + $num=(new ContractTradeModel())->where([ + 'contract_id'=>strtoupper($contract['trade_name']), + 'status'=>1 + ])->count(); + if ($num != 0) { + return $this->toData('1', '交易对还存在交易,不能关闭', []); + } + } + + // 写入数据 + $contract->trade_name = $param['trade_name']; + $contract->status = $param['status']; + $contract->is_owner = $param['is_owner']; + $contract->info = $info; + $contract->logo_link = ''; + $contract->face_value = $param['face_value']; + $contract->sort = $param['sort']; + $contract->min_pry = $param['min_pry']; + $contract->max_pry = $param['max_pry']; + $contract->compel_num = $param['compel_num']; + $contract->keep_decimal = $param['keep_decimal']; + $contract->create_time = date('Y-m-d H:i:s'); + $contract->update_time = date('Y-m-d H:i:s'); + $contract->save(); + + + $list_key="CONTRACT:LIST:".strtoupper($param['trade_name']); + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'name'=>strtoupper($param['trade_name']), + 'code'=>strtoupper($param['trade_name']), + 'sort'=>$param['sort'], + 'face_value'=>$param['face_value'], + 'min_pry'=>$param['min_pry'], + 'max_pry'=>$param['max_pry'], + 'compel_num'=>$param['compel_num'], + 'keep_decimal'=>$param['keep_decimal'], + 'status'=>$param['status'] + ]); + return $this->toData('0', 'SUCCESS', []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + // 获取合约交易对 + public function getTradeNameList($param) + { + try { + if(isset($param['is_owner']) && in_array($param['is_owner'], [0,1])){ + $list = ContractListMode::where('status', 1)->order('id', 'desc') + ->where('is_owner', $param['is_owner']) + ->column('trade_name', 'id'); + } else { + $list = ContractListMode::where('status', 1)->order('id', 'desc') + ->column('trade_name', 'id'); + } + + return $this->toData('0', 'SUCCESS', ['list' => $list]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + public function setting($param) + { + try { + $list = ContractSettingModel::order('time_step', 'asc')->select(); + $rows = []; + if(!$list->isEmpty()){ + $rows =$list->toArray(); + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + public function set_add($param) + { + // 状态 + if(!isset($param['time_step'])){ + return $this->toData('1', '时间无效', []); + } + // 是否自发 + if(!isset($param['earnings_num'])){ + return $this->toData('1', '收益无效', []); + } + $contract = ContractSettingModel::where('time_step', $param['time_step'])->find(); + if(!empty($contract)){ + return $this->toData('1', '时间已存在', []); + } + $contract = new ContractSettingModel; + // 写入数据 + $contract->time_step = $param['time_step']; + $contract->earnings_num = $param['earnings_num']; + $contract->create_time = date('Y-m-d H:i:s'); + $contract->update_time = date('Y-m-d H:i:s'); + $contract->save(); + $this->initContractSetting(); + return $this->toData('0', 'SUCCESS', []); + } + public function set_edit($param) + { + // 状态 + if(!isset($param['time_step'])){ + return $this->toData('1', '时间无效', []); + } + // 是否自发 + if(!isset($param['earnings_num'])){ + return $this->toData('1', '收益无效', []); + } + // 是否自发 + if(!isset($param['id'])){ + return $this->toData('1', 'ID无效', []); + } + $contract = ContractSettingModel::where('id', $param['id'])->find(); + if(empty($contract)){ + return $this->toData('1', '目标不存在', []); + } + + // 写入数据 + $contract->time_step = $param['time_step']; + $contract->earnings_num = $param['earnings_num']; + $contract->create_time = date('Y-m-d H:i:s'); + $contract->update_time = date('Y-m-d H:i:s'); + $contract->save(); + + $this->initContractSetting(); + return $this->toData('0', 'SUCCESS', []); + } + public function set_del($param) + { + if(!isset($param['id'])){ + return $this->toData('1', 'ID无效', []); + } + $contract = ContractSettingModel::where('id', $param['id'])->find(); + if(empty($contract)){ + return $this->toData('1', '目标不存在', []); + } + $contract->where('id',$param['id'])->delete(); + $this->initContractSetting(); + return $this->toData('0', 'SUCCESS', []); + + } +} \ No newline at end of file diff --git a/app/admin/service/setting/DMarketService.php b/app/admin/service/setting/DMarketService.php new file mode 100644 index 0000000..4a38138 --- /dev/null +++ b/app/admin/service/setting/DMarketService.php @@ -0,0 +1,161 @@ +order('id', 'desc') + ->select(); + $rows = []; + if(!$list->isEmpty()){ + foreach ($list as $item){ + if(empty($rows[$item['trade_name']])){ + $rows[$item['trade_name']] = [ + 'trade_name' => $item['trade_name'], + 'begin_time' => $item['begin_time'], + 'end_time' => $item['end_time'], + 'max_price' => $item['max_price'], + 'step' => $item['step'], + ]; + } + } + } + + $rows = array_values($rows); + return $this->toData('0','SUCCSS',['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + // 详情 + public function detail($param) + { + try { + if(empty($param['trade_name']) || !is_string($param['trade_name'])){ + return $this->toData('1', '参数错误'); + } + $list = ContractMarketModel::where('type', ContractMarketModel::TYPE_DIGITAL_SELF) + ->where('trade_name', $param['trade_name']) + ->order('id', 'desc')->select(); + $rows = []; + if(!$list->isEmpty()){ + foreach ($list as $item){ + $rows[] = [ + 'id' => $item['id'], + 'trade_name' => $item['trade_name'], + 'begin_time' => $item['begin_time'], + 'end_time' => $item['end_time'], + 'max_price' => $item['max_price'], + 'step' => $item['step'], + ]; + } + } + return $this->toData('0','SUCCESS',['list' => $rows]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 新增 + public function add($param) + { + try { + // 参数校验 + validate(MarketValidate::class)->scene('add')->check($param); + + // 必须大于当前时间 + if(strtotime($param['end_time']) - time() <= 0){ + return $this->toData('1','结束时间无效1'); + } + + if((strtotime($param['begin_time']) - time()) <= 0 || (strtotime($param['end_time']) - strtotime($param['begin_time'])) <= 0){ + return $this->toData('1','开始时间无效2'); + } + + + $market = new ContractMarketModel; + $market->trade_name = $param['trade_name']; + $market->begin_time = $param['begin_time']; + $market->end_time = $param['end_time']; + $market->max_price = $param['max_price']; + $market->type = ContractMarketModel::TYPE_DIGITAL_SELF; + $market->save(); + + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + // 编辑 + public function edit($param) + { + try { + // 参数校验 + validate(MarketValidate::class)->scene('edit')->check($param); + + // 目标 + $market = ContractMarketModel::where('id', $param['id'])->where('type', ContractMarketModel::TYPE_DIGITAL_SELF)->find(); + if(empty($market)){ + return $this->toData('1','目标不存在'); + } + + + // 必须大于当前时间 + if(strtotime($param['end_time']) - time() <= 0){ + return $this->toData('1','时间无效'); + } + + if((strtotime($param['begin_time']) - time()) <= 0 || (strtotime($param['end_time']) - strtotime($param['begin_time'])) <= 0){ + return $this->toData('1','开始时间无效'); + } + + $market->trade_name = $param['trade_name']; + $market->begin_time = $param['begin_time']; + $market->end_time = $param['end_time']; + $market->max_price = $param['max_price']; + $market->save(); + + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + // 删除 + public function del($param) + { + try { + // 参数校验 + validate(MarketValidate::class)->scene('del')->check($param); + + // 目标 + $market = ContractMarketModel::where('id', $param['id'])->where('type',ContractMarketModel::TYPE_DIGITAL_SELF)->find(); + if(empty($market)){ + return $this->toData('1','目标不存在'); + } + + $market->delete(); + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/DigitalService.php b/app/admin/service/setting/DigitalService.php new file mode 100644 index 0000000..722fdc3 --- /dev/null +++ b/app/admin/service/setting/DigitalService.php @@ -0,0 +1,203 @@ +select(); + $rows = []; + if(!$list->isEmpty()){ + $rows = $list->toArray(); + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + public function add($param) + { + try { + if(empty($param['trade_name']) || !is_string($param['trade_name'])){ + return $this->toData('1', '数字货币名称无效'); + } + + + if(empty($param['exchange_name']) || !is_string($param['exchange_name'])){ + return $this->toData('1', '数字币兑换对名称无效'); + } + + // 简介 + if(!empty($param['info']) && !is_string($param['info'])){ + return $this->toData('1', '简介无效'); + } + $info = $param['info']?? ''; + + // 状态 + if(!isset($param['status']) || !in_array($param['status'], [0,1])){ + return $this->toData('1', '启用状态无效'); + } + + // 排序 + if(!isset($param['sort']) || !is_numeric($param['sort']) || ceil($param['sort']) != $param['sort']){ + return $this->toData('1', '排序无效'); + } + + // 图片链接 + if(empty($param['logo_link']) || !is_string($param['logo_link'])){ + return $this->toData('1', 'logo链接无效'); + } + + // 小数位数 + if(!isset($param['keep_decimal']) || !is_numeric($param['keep_decimal']) || $param['keep_decimal'] < 0 || ceil($param['keep_decimal']) != $param['keep_decimal']){ + return $this->toData('1', '保留小数位无效'); + } + + // 判断股票代码是否已经存在 + $count = DigitalListModel::where('trade_name', $param['trade_name'])->where('exchange_name', $param['exchange_name'])->count(); + if($count > 0){ + return $this->toData('1', '现货数字币交易对已经存在'); + } + + $digitalList = new DigitalListModel; + $digitalList->trade_name = $param['trade_name']; + $digitalList->exchange_name = $param['exchange_name']; + $digitalList->status = $param['status']; + $digitalList->logo_link = $param['logo_link']; + $digitalList->sort = $param['sort']; + $digitalList->keep_decimal = $param['keep_decimal']; + + $digitalList->info = $info; + $digitalList->create_time = date('Y-m-d H:i:s'); + $digitalList->update_time = date('Y-m-d H:i:s'); + $digitalList->save(); + + // 设置缓存 + $fee_key="DIGITAL:LIST:".strtoupper($param['trade_name']); + $redis = $this->getRedis(); + $redis->del($fee_key); + $redis->hMSet($fee_key,[ + 'name'=>strtoupper($param['trade_name']), + 'sort'=>$param['sort'], + 'exchange_name'=>$param['exchange_name'], + 'logo_link'=>$param['logo_link'], + 'keep_decimal'=>$param['keep_decimal'], + 'status'=>$param['status'], + ]); + + return $this->toData('0', '操作成功', []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + public function edit($param) + { + + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在', []); + } + + $digitalList = DigitalListModel::where('id', $param['id'])->find(); + if(empty($digitalList)){ + return $this->toData('1', '目标不存在', []); + } + + if(empty($param['trade_name']) || !is_string($param['trade_name'])){ + return $this->toData('1', '数字货币名称无效'); + } + + + if(empty($param['exchange_name']) || !is_string($param['exchange_name'])){ + return $this->toData('1', '数字币兑换对名称无效'); + } + + // 简介 + if(!empty($param['info']) && !is_string($param['info'])){ + return $this->toData('1', '简介无效'); + } + $info = $param['info']?? ''; + + // 状态 + if(!isset($param['status']) || !in_array($param['status'], [0,1])){ + return $this->toData('1', '启用状态无效'); + } + + // 排序 + if(!isset($param['sort']) || !is_numeric($param['sort']) || ceil($param['sort']) != $param['sort']){ + return $this->toData('1', '排序无效'); + } + + // 图片链接 + if(empty($param['logo_link']) || !is_string($param['logo_link'])){ + return $this->toData('1', 'logo链接无效'); + } + + // 小数位数 + if(!isset($param['keep_decimal']) || !is_numeric($param['keep_decimal']) || $param['keep_decimal'] < 0 || ceil($param['keep_decimal']) != $param['keep_decimal']){ + return $this->toData('1', '保留小数位无效'); + } + + // 判断股票代码是否已经存在 + $count = DigitalListModel::where('trade_name', $param['trade_name'])->where('exchange_name', $param['exchange_name']) + ->where('id','<>', $param['id']) + ->count(); + if($count > 0){ + return $this->toData('1', '现货数字币交易对已经存在'); + } + + $digitalList->trade_name = $param['trade_name']; + $digitalList->exchange_name = $param['exchange_name']; + $digitalList->status = $param['status']; + $digitalList->logo_link = $param['logo_link']; + $digitalList->sort = $param['sort']; + $digitalList->keep_decimal = $param['keep_decimal']; + + $digitalList->info = $info; + $digitalList->update_time = date('Y-m-d H:i:s'); + $digitalList->save(); + + // 设置缓存 + $fee_key="DIGITAL:LIST:".strtoupper($param['trade_name']); + $redis = $this->getRedis(); + $redis->del($fee_key); + $redis->hMSet($fee_key,[ + 'name'=>strtoupper($param['trade_name']), + 'sort'=>$param['sort'], + 'logo_link'=>$param['logo_link'], + 'keep_decimal'=>$param['keep_decimal'], + 'status'=>$param['status'], + ]); + + return $this->toData('0', '操作成功', []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + public function getTradeNameList($param) + { + try { + if(isset($param['is_owner']) && in_array($param['is_owner'], [0,1])){ + $list = DigitalListModel::where('status', 1)->order('id', 'desc') + ->where('is_owner', $param['is_owner']) + ->column('trade_name', 'id'); + } else { + $list = DigitalListModel::where('status', 1)->order('id', 'desc')->column('trade_name', 'id'); + } + + return $this->toData('0', 'SUCCESS', ['list' => $list]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/DrawalService.php b/app/admin/service/setting/DrawalService.php new file mode 100644 index 0000000..903de9f --- /dev/null +++ b/app/admin/service/setting/DrawalService.php @@ -0,0 +1,68 @@ +isEmpty()){ + $rows = $list->toArray(); + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在', []); + } + + if(empty($param['bank_drawal_fee']) || !is_numeric($param['bank_drawal_fee']) || $param['bank_drawal_fee'] < 0){ + return $this->toData('1', '银行提现手续费无效', []); + } + if(empty($param['digital_drawal_fee']) || !is_numeric($param['digital_drawal_fee']) || $param['digital_drawal_fee'] < 0){ + return $this->toData('1', '数字币提现手续费无效', []); + } + if(empty($param['min_recharge']) || !is_numeric($param['min_recharge']) || $param['min_recharge'] < 0){ + return $this->toData('1', '最小充值金额无效', []); + } + if(empty($param['min_drawal']) || !is_numeric($param['min_drawal']) || $param['min_drawal'] < 0){ + return $this->toData('1', '最小提现金额无效', []); + } + + $drawal = DrawalSettingModel::where('id', $param['id'])->find(); + if(empty($drawal)){ + return $this->toData('1', '目标不存在', []); + } + $drawal->bank_drawal_fee = $param['bank_drawal_fee']; + $drawal->digital_drawal_fee = $param['digital_drawal_fee']; + $drawal->min_recharge = $param['min_recharge']; + $drawal->min_drawal = $param['min_drawal']; + $drawal->save(); + + $fee_key="DRAWAL:FEE:SETTING"; + $redis = $this->getRedis(); + $redis->del($fee_key); + $redis->hMSet($fee_key,$param); + + return $this->toData('0','SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/FeeService.php b/app/admin/service/setting/FeeService.php new file mode 100644 index 0000000..5e464d1 --- /dev/null +++ b/app/admin/service/setting/FeeService.php @@ -0,0 +1,202 @@ +select(); + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows), 'extent' => [ + 'market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, 'pay_type' => FeeSettingModel::$payTypeList + ]]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + public function add($param) + { + try { + $marketTypeIds = array_keys(StockMarketModel::STOCK_MARKET_TYPE); + if (empty($param['market_type']) || !in_array($param['market_type'], $marketTypeIds)) { + return $this->toData('1', '市场类型无效', []); + } + + if (!is_numeric($param['buy_fee']) || $param['buy_fee'] < 0) { + return $this->toData('1', '买入手续费无效', []); + } + +// if(empty($param['purchase_fee']) || !is_numeric($param['purchase_fee']) || $param['purchase_fee'] < 0){ +// return $this->toData('1', '盘前申购手续费无效', []); +// } + + if (!is_numeric($param['sale_fee']) || $param['sale_fee'] < 0) { + return $this->toData('1', '卖出手续费无效', []); + } + + if (in_array($param['market_type'], [3, 4, 5, 6, 7, 9, 12,14])) { + if (empty($param['purchase_fee']) || !is_numeric($param['purchase_fee']) || $param['purchase_fee'] < 0) { + return $this->toData('1', '申购手续费无效', []); + } + } + + + // 结算方式:0固定费用,1按比例结算 + if (!isset($param['pay_type']) || !in_array($param['pay_type'], array_keys(FeeSettingModel::$payTypeList))) { + return $this->toData('1', '结算方式无效', []); + } + + // 买入最小下单金额 + if (empty($param['min_buy_num']) || !is_numeric($param['min_buy_num']) || ceil($param['min_buy_num']) != $param['min_buy_num']) { + return $this->toData('1', '买入最小下单金额无效', []); + } + + //卖出最小下单金额 + if (empty($param['min_sale_num']) || !is_numeric($param['min_sale_num']) || ceil($param['min_sale_num']) != $param['min_sale_num']) { + return $this->toData('1', '卖出最小下单金额无效', []); + } + + // max_entrust_num + if (empty($param['max_entrust_num']) || !is_numeric($param['max_entrust_num']) || ceil($param['max_entrust_num']) != $param['max_entrust_num']) { + return $this->toData('1', '最大挂单数量无效', []); + } + + // 最大持仓数量 + if (empty($param['max_hold_num']) || !is_numeric($param['max_hold_num']) || ceil($param['max_hold_num']) != $param['max_hold_num']) { + return $this->toData('1', '最大持仓数量无效', []); + } + + $count = FeeSettingModel::where('market_type', $param['market_type'])->count(); + if ($count > 0) { + return $this->toData('1', '市场类型已经存在', []); + } + $feeSetting = new FeeSettingModel; + $feeSetting->market_type = $param['market_type']; + $feeSetting->buy_fee = $param['buy_fee']; + $feeSetting->sale_fee = $param['sale_fee']; + $feeSetting->pay_type = $param['pay_type']; + $feeSetting->purchase_fee = isset($param['purchase_fee']) ? $param['purchase_fee'] : 0; + $feeSetting->min_buy_num = $param['min_buy_num']; + $feeSetting->min_sale_num = $param['min_sale_num']; + $feeSetting->max_entrust_num = $param['max_entrust_num']; + $feeSetting->max_hold_num = $param['max_hold_num']; + $feeSetting->min_withdrawal_num = empty($param['min_withdrawal_num']) ? 0 :$param['min_withdrawal_num']; + $feeSetting->min_recharge_num = empty($param['min_recharge_num']) ? 0 :$param['min_recharge_num']; + + $feeSetting->save(); + + // 设置缓存 + $fee_key = $this->getTradeFeeKey($param['market_type']); + $redis = $this->getRedis(); + $redis->del($fee_key); + $redis->hMSet($fee_key, $param); + + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function edit($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '目标不存在', []); + } + $feeSetting = FeeSettingModel::where('id', $param['id'])->find(); + + if (empty($feeSetting)) { + return $this->toData('1', '目标不存在', []); + } + + $marketTypeIds = array_keys(StockMarketModel::STOCK_MARKET_TYPE); + if (empty($param['market_type']) || !in_array($param['market_type'], $marketTypeIds)) { + return $this->toData('1', '市场类型无效', []); + } + + if (!is_numeric($param['buy_fee']) || $param['buy_fee'] < 0) { + return $this->toData('1', '买入手续费无效', []); + } + + if (in_array($param['market_type'], [3, 4, 5, 6, 7, 9, 12, 14])) { + if (empty($param['purchase_fee']) || !is_numeric($param['purchase_fee']) || $param['purchase_fee'] < 0) { + return $this->toData('1', '申购手续费无效', []); + } + } + + if (!is_numeric($param['sale_fee']) || $param['sale_fee'] < 0) { + return $this->toData('1', '卖出手续费无效', []); + } + +// if(empty($param['purchase_fee']) || !is_numeric($param['purchase_fee']) || $param['purchase_fee'] < 0){ +// return $this->toData('1', '申购手续费无效', []); +// } + + // 结算方式:0固定费用,1按比例结算 + if (!isset($param['pay_type']) || !in_array($param['pay_type'], array_keys(FeeSettingModel::$payTypeList))) { + return $this->toData('1', '结算方式无效', []); + } + + // 买入最小下单金额 + if (empty($param['min_buy_num']) || !is_numeric($param['min_buy_num']) || ceil($param['min_buy_num']) != $param['min_buy_num']) { + return $this->toData('1', '买入最小下单金额无效', []); + } + + //卖出最小下单金额 + if (empty($param['min_sale_num']) || !is_numeric($param['min_sale_num']) || ceil($param['min_sale_num']) != $param['min_sale_num']) { + return $this->toData('1', '卖出最小下单金额无效', []); + } + + // max_entrust_num + if (empty($param['max_entrust_num']) || !is_numeric($param['max_entrust_num']) || ceil($param['max_entrust_num']) != $param['max_entrust_num']) { + return $this->toData('1', '最大挂单数量无效', []); + } + + // 最大持仓数量 + if (empty($param['max_hold_num']) || !is_numeric($param['max_hold_num']) || ceil($param['max_hold_num']) != $param['max_hold_num']) { + return $this->toData('1', '最大持仓数量无效', []); + } + + $count = FeeSettingModel::where('market_type', $param['market_type'])->where('id', '<>', $feeSetting->id)->count(); + if ($count > 0) { + return $this->toData('1', '市场类型已经存在', []); + } + + $feeSetting->market_type = $param['market_type']; + $feeSetting->buy_fee = $param['buy_fee']; + $feeSetting->sale_fee = $param['sale_fee']; + $feeSetting->pay_type = $param['pay_type']; + $feeSetting->min_buy_num = $param['min_buy_num']; + $feeSetting->purchase_fee = $param['purchase_fee']; + $feeSetting->min_sale_num = $param['min_sale_num']; + $feeSetting->max_entrust_num = $param['max_entrust_num']; + $feeSetting->max_hold_num = $param['max_hold_num']; + + $feeSetting->min_withdrawal_num = empty($param['min_withdrawal_num']) ? 0 :$param['min_withdrawal_num']; + $feeSetting->min_recharge_num = empty($param['min_recharge_num']) ? 0 :$param['min_recharge_num']; + + $feeSetting->save(); + + // 设置缓存 + $fee_key = $this->getTradeFeeKey($param['market_type']); + $redis = $this->getRedis(); + $redis->del($fee_key); + $redis->hMSet($fee_key, $param); + + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/ForexService.php b/app/admin/service/setting/ForexService.php new file mode 100644 index 0000000..79c9c5b --- /dev/null +++ b/app/admin/service/setting/ForexService.php @@ -0,0 +1,425 @@ +select(); + $rows = []; + if(!$list->isEmpty()){ + $rows =$list->toArray(); + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + // 新增 + public function add($param) + { + try { + // 交易对名称 + if(empty($param['trade_name']) || !is_string($param['trade_name']) || strlen($param['trade_name']) > 100){ + return $this->toData('1', '交易对名称无效', []); + } + + // 状态 + if(!isset($param['status']) || !in_array($param['status'], ['0', '1'])){ + return $this->toData('1', '状态无效', []); + } + + // 是否自发 + if(!isset($param['is_owner']) || !in_array($param['is_owner'], ['0', '1'])){ + return $this->toData('1', '是否自发无效', []); + } + + // 简介 + $info = ''; + if(isset($param['info']) && is_string($param['info'])){ + $info = $param['info']; + } + + // 面值 + if(!isset($param['face_value']) || !is_numeric($param['face_value']) || $param['face_value'] != ceil($param['face_value']) || $param['face_value'] <= 0){ + return $this->toData('1', '面值无效', []); + } + + + // 排序 + if(!isset($param['sort']) || !is_numeric($param['sort']) || $param['sort'] != ceil($param['sort']) || $param['sort'] < 0){ + return $this->toData('1', '排序值无效', []); + } + + // 最小杠杆 + if(empty($param['min_pry']) || !is_numeric($param['min_pry']) || $param['min_pry'] != ceil($param['min_pry']) || $param['min_pry'] <= 0){ + return $this->toData('1', '最小杠杆值无效', []); + } + + // 最大杠杆 + if(empty($param['max_pry']) || !is_numeric($param['max_pry']) || $param['max_pry'] != ceil($param['max_pry']) || $param['max_pry'] <= 0){ + return $this->toData('1', '最大杠杆值无效', []); + } + + // 强制平仓比例值 + if(empty($param['compel_num']) || !is_numeric($param['compel_num']) || $param['compel_num'] <= 0){ + return $this->toData('1', '强制平仓比例值无效', []); + } + + + // 小数位数 + if(!isset($param['keep_decimal']) || !is_numeric($param['keep_decimal']) || $param['keep_decimal'] != ceil($param['keep_decimal']) || $param['keep_decimal'] < 0){ + return $this->toData('1', '小数位数值无效', []); + } + + // 判断名称是否已被添加 + $count = ForexListModel::where('trade_name', $param['trade_name'])->count(); + if($count > 0){ + return $this->toData('1', '合约交易对名称已存在', []); + } + + $contract = new ForexListModel; + $contract->trade_name = $param['trade_name']; + $contract->status = $param['status']; + $contract->is_owner = $param['is_owner']; + $contract->info = $info; + $contract->logo_link = ''; + $contract->face_value = $param['face_value']; + $contract->sort = $param['sort']; + $contract->min_pry = $param['min_pry']; + $contract->max_pry = $param['max_pry']; + $contract->compel_num = $param['compel_num']; + $contract->keep_decimal = $param['keep_decimal']; + $contract->create_time = date('Y-m-d H:i:s'); + $contract->update_time = date('Y-m-d H:i:s'); + $contract->save(); + + $list_key="FOREX:LIST:".strtoupper($param['trade_name']); + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'name'=>strtoupper($param['trade_name']), + 'code'=>strtoupper($param['trade_name']), + 'sort'=>$param['sort'], + 'face_value'=>$param['face_value'], + 'min_pry'=>$param['min_pry'], + 'max_pry'=>$param['max_pry'], + 'compel_num'=>$param['compel_num'], + 'keep_decimal'=>$param['keep_decimal'], + 'is_owner'=>$param['is_owner'], + 'status'=>$param['status'] + ]); + + return $this->toData('0', '操作成功', []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '目标不存在', []); + } + + $contract = ForexListModel::where('id', $param['id'])->find(); + $beforeStatus = $contract['status']; + if(empty($contract)){ + return $this->toData('1', '目标不存在', []); + } + + // 交易对名称 + if(empty($param['trade_name']) || !is_string($param['trade_name']) || strlen($param['trade_name']) > 100){ + return $this->toData('1', '交易对名称无效', []); + } + + // 状态 + if(!isset($param['status']) || !in_array($param['status'], ['0', '1'])){ + return $this->toData('1', '状态无效', []); + } + + // 是否自发 + if(!isset($param['is_owner']) || !in_array($param['is_owner'], ['0', '1'])){ + return $this->toData('1', '是否自发无效', []); + } + + // 简介 + $info = ''; + if(isset($param['info']) && is_string($param['info'])){ + $info = $param['info']; + } + + // 面值 + if(!isset($param['face_value']) || !is_numeric($param['face_value']) || $param['face_value'] != ceil($param['face_value']) || $param['face_value'] <= 0){ + return $this->toData('1', '面值无效', []); + } + + + // 排序 + if(!isset($param['sort']) || !is_numeric($param['sort']) || $param['sort'] != ceil($param['sort']) || $param['sort'] < 0){ + return $this->toData('1', '排序值无效', []); + } + + // 最小杠杆 + if(empty($param['min_pry']) || !is_numeric($param['min_pry']) || $param['min_pry'] != ceil($param['min_pry']) || $param['min_pry'] <= 0){ + return $this->toData('1', '最小杠杆值无效', []); + } + + // 最大杠杆 + if(empty($param['max_pry']) || !is_numeric($param['max_pry']) || $param['max_pry'] != ceil($param['max_pry']) || $param['max_pry'] <= 0){ + return $this->toData('1', '最大杠杆值无效', []); + } + + // 强制平仓比例值 + if(empty($param['compel_num']) || !is_numeric($param['compel_num']) || $param['compel_num'] <= 0){ + return $this->toData('1', '强制平仓比例值无效', []); + } + + // 小数位数 + if(!isset($param['keep_decimal']) || !is_numeric($param['keep_decimal']) || $param['keep_decimal'] != ceil($param['keep_decimal']) || $param['keep_decimal'] < 0){ + return $this->toData('1', '小数位数值无效', []); + } + + // 判断名称是否已被添加 + $count = ForexListModel::where('trade_name', $param['trade_name'])->where('id', '<>', $param['id'])->count(); + if($count > 0){ + return $this->toData('1', '合约交易对名称已存在', []); + } + + // 如果状态设置成关闭 则判断是否有正在交易的合约 + if($beforeStatus == 1 && $param['status'] == 0){ + $num=(new ForexListModel())->where([ + 'contract_id'=>strtoupper($contract['trade_name']), + 'status'=>1 + ])->count(); + if ($num != 0) { + return $this->toData('1', '交易对还存在交易,不能关闭', []); + } + } + + // 写入数据 + $contract->trade_name = $param['trade_name']; + $contract->status = $param['status']; + $contract->is_owner = $param['is_owner']; + $contract->info = $info; + $contract->logo_link = ''; + $contract->face_value = $param['face_value']; + $contract->sort = $param['sort']; + $contract->min_pry = $param['min_pry']; + $contract->max_pry = $param['max_pry']; + $contract->compel_num = $param['compel_num']; + $contract->keep_decimal = $param['keep_decimal']; + $contract->create_time = date('Y-m-d H:i:s'); + $contract->update_time = date('Y-m-d H:i:s'); + $contract->save(); + + + $list_key="FOREX:LIST:".strtoupper($param['trade_name']); + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'name'=>strtoupper($param['trade_name']), + 'code'=>strtoupper($param['trade_name']), + 'sort'=>$param['sort'], + 'face_value'=>$param['face_value'], + 'min_pry'=>$param['min_pry'], + 'max_pry'=>$param['max_pry'], + 'compel_num'=>$param['compel_num'], + 'keep_decimal'=>$param['keep_decimal'], + 'status'=>$param['status'] + ]); + return $this->toData('0', 'SUCCESS', []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + // 获取合约交易对 + public function getTradeNameList($param) + { + try { + $list = ForexListModel::where('status', 1)->order('id', 'desc') + ->column('trade_name', 'id'); + return $this->toData('0', 'SUCCESS', ['list' => $list]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + + public function hq_index() + { + try { + $list = ForexMarketModel::where('type', 0)->order('id', 'desc')->select(); + $rows = []; + if(!$list->isEmpty()){ + $rows = $list->toArray(); + } + return $this->toData('0','SUCCSS',['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + // 新增 + public function hq_add($param) + { + try { + // 参数校验 + validate(HqValidate::class)->scene('add')->check($param); + + // 已存在未执行的 不能再插入 + $count = ForexMarketModel::where('trade_name', $param['trade_name']) + ->where('is_get',1) + ->where('type', 0) + ->count(); + if($count > 0){ + return $this->toData('1','已存在未执行'); + } + + //判断 + $diff = strtotime($param['end_time']) - strtotime($param['begin_time']); + if($diff > 600 || $diff <=0){ + return $this->toData('1','时间无效-结束时间必须在开始时间十分钟以内'); + } + + // 不能有交叉时间 + $map1 = [ + ['trade_name', '=',$param['trade_name']], + ['begin_time','between', [$param['begin_time'], $param['end_time']]] + ]; + $map2 = [ + ['trade_name', '=',$param['trade_name']], + ['end_time','between', [$param['begin_time'], $param['end_time']]] + ]; + + $count = ForexMarketModel::whereOr([$map1,$map2]) + ->count(); + if($count > 0){ + return $this->toData('1','时间无效-时间不能有交叉'); + } + + $market = new ForexMarketModel; + $market->trade_name = $param['trade_name']; + $market->begin_time = $param['begin_time']; + $market->end_time = $param['end_time']; + $market->max_price = $param['max_price']; + $market->step = $param['step']; + $market->type = 0; + $market->save(); + + // 写入redis + $this->initForexHqData(); + + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + // 编辑 + public function hq_edit($param) + { + try { + // 参数校验 + validate(HqValidate::class)->scene('edit')->check($param); + + // 已存在未执行的 不能再插入 + $count = ForexMarketModel::where('trade_name', $param['trade_name']) + ->where('id', '<>', $param['id']) + ->where('is_get',1) + ->where('type', 0) + ->count(); + + if($count > 0){ + return $this->toData('1','已存在未执行'); + } + + // 目标 + $market = ForexMarketModel::where('id', $param['id'])->where('type', 0)->find(); + if(empty($market)){ + return $this->toData('1','目标不存在'); + } + + //判断 + $diff = strtotime($param['end_time']) - strtotime($param['begin_time']); + if($diff > 600 || $diff <=0){ + return $this->toData('1','时间无效'); + } + + // 不能有交叉时间 + $map1 = [ + ['trade_name', '=',$param['trade_name']], + ['id', '<>',$param['id']], + ['begin_time','between', [$param['begin_time'], $param['end_time']]] + ]; + $map2 = [ + ['trade_name', '=',$param['trade_name']], + ['id', '<>',$param['id']], + ['end_time','between', [$param['begin_time'], $param['end_time']]] + ]; + + $count = ForexMarketModel::whereOr([$map1,$map2]) + ->count(); + if($count > 0){ + return $this->toData('1','时间无效'); + } + + $market->trade_name = $param['trade_name']; + $market->begin_time = $param['begin_time']; + $market->end_time = $param['end_time']; + $market->max_price = $param['max_price']; + $market->is_get = 1; + $market->step = $param['step']; + $market->save(); + + // redis + $this->initForexHqData(); + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage(),$exception->getTrace()]); + } + } + + // 删除 + public function hq_del($param) + { + try { + // 参数校验 + validate(HqValidate::class)->scene('del')->check($param); + + // 目标 + $market = ForexMarketModel::where('id', $param['id'])->find(); + if(empty($market)){ + return $this->toData('1','目标不存在'); + } + + $market->delete(); + + $this->initForexHqData(); + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('12', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('11', '系统繁忙', [$exception->getMessage()]); + } + } + +} \ No newline at end of file diff --git a/app/admin/service/setting/GiveStockService.php b/app/admin/service/setting/GiveStockService.php new file mode 100644 index 0000000..de4161a --- /dev/null +++ b/app/admin/service/setting/GiveStockService.php @@ -0,0 +1,133 @@ +toData('1', '分页参数错误'); + } + + $where = []; + $userId = 0; + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => StockMarketModel::STOCK_MARKET_TYPE]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => StockMarketModel::STOCK_MARKET_TYPE]); + } + + // 股票号 + if (!empty($param['stock_code']) && is_string($param['stock_code'])) { + $where[] = [ + 'stock_code', 'like', '%' . $param['stock_code'] + ]; + } + $tableObj = (new IPOService())->getStockModel($marketType); + + $query = Db::table($tableObj['give_order_table'])->where($where)->where($whereU)->with(['user' => function ($query) { + $query->field('user_id,user_no,nick_name,email,phone_number'); + }])->order('id', 'desc'); + $totalQuery = Db::table($tableObj['give_order_table'])->where($where)->where($whereU)->order('id', 'desc'); + $list = $query->page($param['page'], $param['limit'])->select()->toArray(); + $total = $totalQuery->count(); + $stockCodeArr = array_column($list, 'stock_code'); + $stockNameArr = Db::table($tableObj['list_table'])->whereIn('stock_code', $stockCodeArr)->column('stock_name', 'stock_code'); + foreach ($list as &$v) { + $v['stock_name'] = $stockNameArr[$v['stock_code']]; + } + + return $this->toData('0', 'SUCCESS', ['list' => $list, 'total' => $total, 'extent' => StockMarketModel::STOCK_MARKET_TYPE]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 新增 + public function add($marketType, $param) + { + try { + // 股票代码 + if (empty($param['stock_code']) || !is_string($param['stock_code'])) { + return $this->toData('1', '股票代码 无效'); + } + + if (empty($param['tape']) || !is_numeric($param['tape'])) { + return $this->toData('1', '交易所 无效'); + } + + $tapeList = (new StockMarketModel)->getAllTape(); + if (strpos($param['stock_code'], ':') !== false) { + $param['stock_code'] = explode(':', $param['stock_code'])[1]; + } + + $tape = $tapeList[$marketType][$param['tape']]; + if ($marketType != 3) $param['stock_code'] = $tape . ':' . $param['stock_code']; + + $tableObj = (new IPOService())->getStockModel($marketType); + $isHas = Db::table($tableObj['list_table'])->where('stock_code', $param['stock_code'])->value('id'); + if (empty($isHas)) return $this->toData('1', '股票 无效'); + + // 股票代码 + if (empty($param['user_id']) || !is_numeric($param['user_id'])) { + return $this->toData('1', '用户 无效'); + } + + if (empty($param['num']) || !is_numeric($param['num']) || $param['num'] <= 0) { + return $this->toData('1', '送股数量 无效'); + } + + $price=!empty($param['price']) ? floatval($param['price']) : 0; + + $date = date('Y-m-d H:i:s'); + $orderNo = (new Tool())->orderNo(20); + $insertArr = [ + 'user_id' => $param['user_id'], + 'stock_code' => $param['stock_code'], + 'order_no' => $orderNo, + 'num' => $param['num'], + 'price' => $price, + 'amount' => $price*$param['num'], + 'create_time' => $date, + 'update_time' => $date + ]; + $insertBool = Db::table($tableObj['give_order_table'])->insert($insertArr); + if ($insertBool) { + // 通知交易 + $bool = (new ClientGo())->giveawaysStock($param['stock_code'], $orderNo, $param['market_type']); + if (!$bool) { + return $this->toData('1', '给交易推送数据异常', []); + } + } + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('0', '系统繁忙', [$exception->getMessage()]); + } + } + +} \ No newline at end of file diff --git a/app/admin/service/setting/HqService.php b/app/admin/service/setting/HqService.php new file mode 100644 index 0000000..50af83b --- /dev/null +++ b/app/admin/service/setting/HqService.php @@ -0,0 +1,176 @@ +order('id', 'desc')->select(); + $rows = []; + if(!$list->isEmpty()){ + $rows = $list->toArray(); + } + return $this->toData('0','SUCCSS',['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + // 新增 + public function add($param) + { + try { + // 参数校验 + validate(HqValidate::class)->scene('add')->check($param); + + // 已存在未执行的 不能再插入 + $count = ContractMarketModel::where('trade_name', $param['trade_name']) + ->where('is_get',1) + ->where('type', 0) + ->count(); + if($count > 0){ + return $this->toData('1','已存在未执行'); + } + + //判断 + $diff = strtotime($param['end_time']) - strtotime($param['begin_time']); + if($diff > 600 || $diff <=0){ + return $this->toData('1','时间无效-结束时间必须在开始时间十分钟以内'); + } + + // 不能有交叉时间 + $map1 = [ + ['trade_name', '=',$param['trade_name']], + ['begin_time','between', [$param['begin_time'], $param['end_time']]] + ]; + $map2 = [ + ['trade_name', '=',$param['trade_name']], + ['end_time','between', [$param['begin_time'], $param['end_time']]] + ]; + + $count = ContractMarketModel::whereOr([$map1,$map2]) + ->count(); + if($count > 0){ + return $this->toData('1','时间无效-时间不能有交叉'); + } + + $market = new ContractMarketModel; + $market->trade_name = $param['trade_name']; + $market->begin_time = $param['begin_time']; + $market->end_time = $param['end_time']; + $market->max_price = $param['max_price']; + $market->step = $param['step']; + $market->type = 0; + $market->save(); + + // 写入redis + $this->initContractHqData(); + + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + // 编辑 + public function edit($param) + { + try { + // 参数校验 + validate(HqValidate::class)->scene('edit')->check($param); + + // 已存在未执行的 不能再插入 + $count = ContractMarketModel::where('trade_name', $param['trade_name']) + ->where('id', '<>', $param['id']) + ->where('is_get',1) + ->where('type', 0) + ->count(); + + if($count > 0){ + return $this->toData('1','已存在未执行'); + } + + // 目标 + $market = ContractMarketModel::where('id', $param['id'])->where('type', 0)->find(); + if(empty($market)){ + return $this->toData('1','目标不存在'); + } + + //判断 + $diff = strtotime($param['end_time']) - strtotime($param['begin_time']); + if($diff > 600 || $diff <=0){ + return $this->toData('1','时间无效'); + } + + // 不能有交叉时间 + $map1 = [ + ['trade_name', '=',$param['trade_name']], + ['id', '<>',$param['id']], + ['begin_time','between', [$param['begin_time'], $param['end_time']]] + ]; + $map2 = [ + ['trade_name', '=',$param['trade_name']], + ['id', '<>',$param['id']], + ['end_time','between', [$param['begin_time'], $param['end_time']]] + ]; + + $count = ContractMarketModel::whereOr([$map1,$map2]) + ->count(); + if($count > 0){ + return $this->toData('1','时间无效'); + } + + $market->trade_name = $param['trade_name']; + $market->begin_time = $param['begin_time']; + $market->end_time = $param['end_time']; + $market->max_price = $param['max_price']; + $market->step = $param['step']; + $market->is_get = 1; + $market->save(); + + // redis + $this->initContractHqData(); + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage(),$exception->getTrace()]); + } + } + + // 删除 + public function del($param) + { + try { + // 参数校验 + validate(HqValidate::class)->scene('del')->check($param); + + // 目标 + $market = ContractMarketModel::where('id', $param['id'])->find(); + if(empty($market)){ + return $this->toData('1','目标不存在'); + } + + $market->delete(); + + $this->initContractHqData(); + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('12', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('11', '系统繁忙', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/IPOService.php b/app/admin/service/setting/IPOService.php new file mode 100644 index 0000000..734133b --- /dev/null +++ b/app/admin/service/setting/IPOService.php @@ -0,0 +1,1701 @@ +getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '市场类型无效'); + } + if (empty($param['page']) || !is_numeric($param['page']) || empty($param['limit']) || !is_numeric($param['limit'])) { + return $this->toData('1', '分页参数错误'); + } + + $userId = 0; + $where = []; + $stockTypeList = $this->getStockTape($market_type); + // 用户号精确搜索 + if (!empty($param['user_no'])) { + $user = UserModel::where('user_no', $param['user_no'])->find(); + if (empty($user)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => [ + 'tape_list' => $stockTypeList['tape'], + 'stock_type_list' => $stockTypeList['type'], + 'symbol' => $table_obj['stock_id']]]); + } + $userId = $user['user_id']; + } + + // 判断是否是代理 如果是代理 只能看他自己管理的用户 + $whereU = $this->getWhereByIsAgentAndUserId($adminId, $where, $userId); + if (!is_array($whereU)) { + return $this->toData('0', 'SUCCESS', ['total' => 0, 'list' => [], 'extent' => [ + 'tape_list' => $stockTypeList['tape'], + 'stock_type_list' => $stockTypeList['type'], + 'symbol' => $table_obj['stock_id']]]); + } + + // 未删除 + $where[] = [ + 'is_delete', '=', 1 + ]; + // 股票号 + if (!empty($param['stock_code']) && is_string($param['stock_code'])) { + $where[] = [ + 'stock_code', 'like', '%' . $param['stock_code'] + ]; + } + + // 状态 + if (!empty($param['status']) && in_array($param['status'], [1, 2])) { + $where[] = [ + 'status', '=', $param['status'] + ]; + } + + // 上市状态 1 待申购 2 (申购中)待中签 3 (申购结束)待中签 4 待上市 5 已上市 + $query = Db::table($table_obj['stock_table'])->where($where)->where($whereU); + $totalQuery = Db::table($table_obj['stock_table'])->where($where)->where($whereU); + if (!empty($param['open_status']) && in_array($param['open_status'], ['1', '2', '3', '4'])) { + switch ($param['open_status']) { + case '1': + $query = $query->whereTime('start_time', '>', date('Y-m-d H:i:s')); + $totalQuery = $totalQuery->whereTime('start_time', '>', date('Y-m-d H:i:s')); + break; + case '2': + $query = $query->whereTime('start_time', '<=', date('Y-m-d H:i:s'))->whereTime('end_time', '>=', date('Y-m-d H:i:s')); + $totalQuery = $totalQuery->whereTime('start_time', '<=', date('Y-m-d H:i:s'))->whereTime('end_time', '>=', date('Y-m-d H:i:s')); + break; + case '3': + $query = $query->whereTime('end_time', '<=', date('Y-m-d H:i:s'))->whereTime('get_time', '>', date('Y-m-d H:i:s')); + $totalQuery = $totalQuery->whereTime('end_time', '<=', date('Y-m-d H:i:s'))->whereTime('get_time', '>', date('Y-m-d H:i:s')); + break; + case '4': + $query = $query->where('open_status', 1)->whereTime('get_time', '<', date('Y-m-d H:i:s')); + $totalQuery = $totalQuery->where('open_status', 2); + break; + case '5': + $query = $query->where('open_status', 2); + $totalQuery = $totalQuery->where('open_status', 2); + break; + } + } + + $list = $query->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + $total = $totalQuery->order('id', 'desc')->count(); + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + foreach ($rows as $key => $item) { + $open_status_name = '-'; + if (strtotime($item['start_time']) > time()) { + $open_status_name = '待申购'; + $re_status = 1; + } + + if (strtotime($item['start_time']) <= time() && strtotime($item['end_time']) >= time()) { + $open_status_name = '待中签(申购中)'; + $re_status = 2; + } + + if (strtotime($item['end_time']) < time()) { + $open_status_name = '待中签(申购结束)'; + $re_status = 3; + } + + if ($item['sign_status'] == 1) { + $open_status_name = '待上市(已中签)'; + $re_status = 4; + } + + if ($item['open_status'] == 2) { + $open_status_name = '已上市'; + $re_status = 5; + } + + $rows[$key]['open_status_name'] = $open_status_name; + $rows[$key]['re_status'] = $re_status; + + if (strpos($item['stock_code'], ':') !== false) { + $rows[$key]['stock_code'] = explode(':', $item['stock_code'])[1]; + } + } + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total, 'extend' => [ + 'tape_list' => $stockTypeList['tape'], + 'stock_type_list' => $stockTypeList['type'], + 'symbol' => $table_obj['stock_id'], + 're_status_list' => ['1' => '待申购', '2' => '待中签(申购中)', '3' => '待中签(申购结束)', '4' => '待上市(已中签)', '5' => '已上市'] + ]]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 添加IPO + */ + public function addStockIPO($market_type, $param) + { + try { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '市场类型无效'); + } + // 股票代码 + if (empty($param['stock_code']) || !is_string($param['stock_code']) || !preg_match('/^[a-zA-Z0-9]+$/', $param['stock_code'])) { + return $this->toData('1', '股票代码 无效'); + } + + // 股票名称 + if (empty($param['stock_name']) || !is_string($param['stock_name'])) { + return $this->toData('1', '股票名称 无效'); + } + + if ($market_type == 5) { + if (empty($param['numeric_code']) || !preg_match('/^[a-zA-Z0-9]+$/', $param['numeric_code'])) { + return $this->toData('1', '数字编码 无效'); + } + } + + $stockTypeList = $this->getStockTape($market_type); + // 股票类型 + if (empty($param['stock_type']) || !in_array($param['stock_type'], array_keys($stockTypeList['type']))) { + return $this->toData('1', '股票类型 无效'); + } + + // 交易所类型 + if (empty($param['tape']) || !in_array($param['tape'], array_keys($stockTypeList['tape']))) { + return $this->toData('1', '交易所类型 无效'); + } + + // 发布状态 + if (empty($param['status']) || !in_array($param['status'], [1, 2])) { + return $this->toData('1', '发布状态 无效'); + } + + // 单股价格 + if (empty($param['price']) || !is_numeric($param['price']) || $param['price'] <= 0) { + return $this->toData('1', '单股价格 无效'); + } + + // 最小申购数量 + if (empty($param['min']) || !is_numeric($param['min']) || $param['min'] <= 0 || ceil($param['min']) != $param['min']) { + return $this->toData('1', '最小申购数量 无效'); + } + + // 发行总数 + if (empty($param['total']) || !is_numeric($param['total']) || $param['total'] <= 0 || ceil($param['total']) != $param['total']) { + return $this->toData('1', '发行总数 无效'); + } + + // 中签率 两位小数 + if (empty($param['rate']) || !is_numeric($param['rate']) || is_float($param['rate']) || $param['rate'] < 0 || $param['rate'] > 100) { + return $this->toData('1', '中签率无效;范围 0 - 100 , 必须是整数'); + } + + // 开始认购时间 + if (empty($param['start_time']) || !is_string($param['start_time'])) { + return $this->toData('1', '开始认购时间 无效'); + } + + // 认购结束时间 + if (empty($param['end_time']) || !is_string($param['end_time'])) { + return $this->toData('1', '认购结束时间 无效'); + } + + // 中签时间 + if (empty($param['get_time']) || !is_string($param['get_time'])) { + return $this->toData('1', '中签时间 无效'); + } + + // 上市时间 + if (empty($param['open_time']) || !is_string($param['open_time'])) { + return $this->toData('1', '上市时间 无效'); + } + + // 公司注册资本 + $companyRegAmount = ""; + if (!empty($param['company_reg_amount']) && is_string($param['company_reg_amount'])) { + $companyRegAmount = $param['company_reg_amount']; + } + + // 公司上市时间 + if (empty($param['company_open_time']) || !is_string($param['company_open_time'])) { + return $this->toData('1', '公司上市时间 无效'); + } + + // 公司简介 + if (empty($param['company_info']) || !is_string($param['company_info'])) { + return $this->toData('1', '公司简介 无效'); + } + + // 股票logo + if (empty($param['logo']) || !is_string($param['logo'])) { + return $this->toData('1', '股票logo 无效'); + } + + // 上市时间 要大于 中签时间 中签时间要大于 认购结结束时间 + if (strtotime($param['open_time']) <= strtotime($param['get_time']) || strtotime($param['get_time']) <= strtotime($param['end_time'])) { + return $this->toData('1', '上市时间 要大于 中签时间 中签时间要大于 认购结结束时间'); + } + + // 是否后支付 + if (empty($param['is_post_pay']) || !in_array($param['is_post_pay'], [1, 2])) { + return $this->toData('1', '交易所类型 无效'); + } + + // 后支付截止时间 > 中签时间 && 后支付截止时间 < 上市时间 +// if ($param['is_post_pay'] == 2 && (empty($param['pay_deadline_time']) || strtotime($param['pay_deadline_time']) <= strtotime($param['get_time']) || strtotime($param['pay_deadline_time']) >= strtotime($param['open_time']))) { +// return $this->toData('1', '后支付截止时间 要大于 中签时间 且 后支付截止时间 要小于 上市时间'); +// } + + if (strpos($param['stock_code'], ':') !== false) { + $param['stock_code'] = explode(':', $param['stock_code'])[1]; + } + //除了美股 其他的 code前拼交易所 + if ($market_type != 3) { + $param['stock_code'] = $this->getStockTape($market_type)['tape'][$param['tape']] . ":" . $param['stock_code']; + } + + // 1.0 判断股票号是否已经存在 + $preStock = Db::table($table_obj['stock_table'])->where('stock_code', $param['stock_code'])->where('is_delete', 1)->find(); + if (!empty($preStock)) { + return $this->toData('1', '股票号已经存在'); + } + $stock = Db::table($table_obj['list_table'])->where('stock_code', $param['stock_code'])->find(); + if (!empty($stock)) { + return $this->toData('1', '股票号已经上市'); + } + + // 新增数据 + + $preHkStock['stock_code'] = $param['stock_code']; + $preHkStock['stock_name'] = $param['stock_name']; + $preHkStock['stock_type'] = $param['stock_type']; + $preHkStock['tape'] = $param['tape']; + $preHkStock['status'] = $param['status']; + $preHkStock['price'] = $param['price']; + $preHkStock['min'] = $param['min']; + $preHkStock['max'] = $param['max'] ?? 0; + $preHkStock['total'] = $param['total']; + $preHkStock['rate'] = $param['rate']; + $preHkStock['start_time'] = $param['start_time']; + $preHkStock['end_time'] = $param['end_time']; + $preHkStock['get_time'] = $param['get_time']; + $preHkStock['open_time'] = $param['open_time']; + $preHkStock['is_post_pay'] = $param['is_post_pay']; + if (!empty($param['pay_deadline_time'])) $preHkStock['pay_deadline_time'] = $param['pay_deadline_time']; + $preHkStock['limit_get_num'] = $param['limit_get_num'] ?? 100; + $preHkStock['is_delete'] = 1; + $preHkStock['open_status'] = 1; + $preHkStock['create_time'] = date('Y-m-d H:i:s'); + $preHkStock['update_time'] = date('Y-m-d H:i:s'); + $preHkStock['company_reg_amount'] = $companyRegAmount; + $preHkStock['company_open_time'] = $param['company_open_time']; + $preHkStock['company_info'] = $param['company_info']; + $preHkStock['logo'] = $param['logo']; + if ($market_type == 5) $preHkStock['numeric_code'] = $param['numeric_code'] ?? '0'; + + $bool = Db::table($table_obj['stock_table'])->insert($preHkStock); + if ($bool) { + return $this->toData('0', 'SUCCESS'); + } else { + return $this->toData('1', 'FAIL'); + } + } catch (\Exception $exception) { + return $this->toData('0', '系统繁忙', [$exception->getMessage()]); + } + } + + /** + * 编辑IPO + */ + public function editStockIPO($market_type, $param) + { + try { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '主键 无效'); + } + + $preHkStock = Db::table($table_obj['stock_table'])->where('id', $param['id'])->where('is_delete', 1)->find(); + if (empty($preHkStock)) { + return $this->toData('1', '主键 无效'); + } + $stockTypeList = $this->getStockTape($market_type); + // 股票类型 + if (empty($param['stock_type']) || !in_array($param['stock_type'], array_keys($stockTypeList['type']))) { + return $this->toData('1', '股票类型 无效'); + } + + // 股票代码 + if (empty($param['stock_code']) || !is_string($param['stock_code']) || !preg_match('/^[a-zA-Z0-9]+$/', $param['stock_code'])) { + return $this->toData('1', '股票代码 无效'); + } + + // 股票名称 + if (empty($param['stock_name']) || !is_string($param['stock_name'])) { + return $this->toData('1', '股票代码 无效'); + } + + if ($market_type == 5) { + if (empty($param['numeric_code']) || !preg_match('/^[a-zA-Z0-9]+$/', $param['numeric_code'])) { + return $this->toData('1', '数字编码 无效'); + } + } + + // 交易所类型 + if (empty($param['tape']) || !in_array($param['tape'], array_keys($stockTypeList['tape']))) { + return $this->toData('1', '交易所类型 无效'); + } + + // 发布状态 + if (empty($param['status']) || !in_array($param['status'], [1, 2])) { + return $this->toData('1', '发布状态 无效'); + } + + // 单股价格 + if (empty($param['price']) || !is_numeric($param['price']) || $param['price'] <= 0) { + return $this->toData('1', '单股价格 无效'); + } + + // 开始认购时间 + if (empty($param['start_time']) || !is_string($param['start_time'])) { + return $this->toData('1', '开始认购时间 无效'); + } + // 最小申购数量 + if (empty($param['min']) || !is_numeric($param['min']) || $param['min'] <= 0 || ceil($param['min']) != $param['min']) { + return $this->toData('1', '最小申购数量 无效'); + } + + // 发行总数 + if (empty($param['total']) || !is_numeric($param['total']) || $param['total'] <= 0 || ceil($param['total']) != $param['total']) { + return $this->toData('1', '发行总数 无效'); + } + + // 中签率 两位小数 + if (empty($param['rate']) || !is_numeric($param['rate']) || is_float($param['rate']) || $param['rate'] < 0 || $param['rate'] > 100) { + return $this->toData('1', '中签率无效;范围 0 - 100 , 必须是整数'); + } + + // 认购结束时间 + if (empty($param['end_time']) || !is_string($param['end_time'])) { + return $this->toData('1', '认购结束时间 无效'); + } + + // 中签时间 + if (empty($param['get_time']) || !is_string($param['get_time'])) { + return $this->toData('1', '中签时间 无效'); + } + + // 上市时间 + if (empty($param['open_time']) || !is_string($param['open_time'])) { + return $this->toData('1', '上市时间 无效'); + } + + // 公司注册资本 + $companyRegAmount = ""; + if (!empty($param['company_reg_amount']) && is_string($param['company_reg_amount'])) { + $companyRegAmount = $param['company_reg_amount']; + } + + // 公司上市时间 + if (empty($param['company_open_time']) || !is_string($param['company_open_time'])) { + return $this->toData('1', '公司上市时间 无效'); + } + + // 公司简介 + if (empty($param['company_info']) || !is_string($param['company_info'])) { + return $this->toData('1', '公司简介 无效'); + } + + // 股票logo + if (empty($param['logo']) || !is_string($param['logo'])) { + return $this->toData('1', '股票logo 无效'); + } + + // 上市时间 要大于 中签时间 中签时间要大于 认购结结束时间 + if (strtotime($param['open_time']) <= strtotime($param['get_time']) || strtotime($param['get_time']) <= strtotime($param['end_time'])) { + return $this->toData('1', '上市时间 要大于 中签时间 中签时间要大于 认购结结束时间'); + } + + // 是否后支付 + if (empty($param['is_post_pay']) || !in_array($param['is_post_pay'], [1, 2])) { + return $this->toData('1', '交易所类型 无效'); + } + + // 后支付截止时间 > 中签时间 && 后支付截止时间 < 上市时间 +// if ($param['is_post_pay'] == 2 && (empty($param['pay_deadline_time']) || strtotime($param['pay_deadline_time']) <= strtotime($param['get_time']) || strtotime($param['pay_deadline_time']) >= strtotime($param['open_time']))) { +// return $this->toData('1', '后支付截止时间 要大于 中签时间 且 后支付截止时间 要小于 上市时间'); +// } + + if (strpos($param['stock_code'], ':') !== false) { + $param['stock_code'] = explode(':', $param['stock_code'])[1]; + } + //除了美股 其他的 code前拼交易所 + if ($market_type != 3) { + $param['stock_code'] = $this->getStockTape($market_type)['tape'][$param['tape']] . ":" . $param['stock_code']; + } + //code变更进行通知 + if ($preHkStock['stock_code'] != $param['stock_code'] && $preHkStock['open_status'] == 2) { + $source = 0; + if ($market_type == 7) $source = 1; + // 通知行情 + $bool = $this->sendNewStockToGo($table_obj['country'], $param['stock_code'], $preHkStock['stock_code'], $param['stock_name'], $stockTypeList['tape'][$preHkStock['tape']], $preHkStock['price'], 1, $preHkStock['company_info'], $source, $param['numeric_code'] ?? 0); + if (!$bool) { + return $this->toData('1', '给行情推送数据异常', []); + } + + // 通知交易 + $bool = $this->sendUpdateCodeGo($param['stock_code'], $preHkStock['stock_code'], $market_type); + if (!$bool) { + return $this->toData('1', '给交易推送数据异常', []); + } + + //修改股票code + $stock = Db::table($table_obj['list_table'])->where('stock_code', $preHkStock['stock_code'])->find(); + $stock_update['stock_code'] = $param['stock_code']; + $stock_update['update_time'] = date('Y-m-d H:i:m'); + $updateCodeBool = Db::table($table_obj['list_table'])->where('id', $stock['id'])->update($stock_update); + if (!$updateCodeBool) return $this->toData('1', '修改股票code失败'); + + $oldKey = $table_obj['redis_key'] . $preHkStock['stock_code']; + $redis = $this->getRedis(); + $redis->del($oldKey); + $newKey = $table_obj['redis_key'] . $param['stock_code']; + $cacheArr = [ + 'stock_name' => $stock['stock_name'], + 'stock_code' => $param['stock_code'], + 'status' => $stock['status'], + 'keep_decimal' => $stock['keep_decimal'], + 'forced_closure' => $stock['forced_closure'], + 'up_limit' => $stock['up_limit'], + 'down_limit' => $stock['down_limit'], + 'info' => $stock['info'], + 'tape' => $stock['tape'], + ]; + if ($market_type == 5) $cacheArr['numeric_code'] = $param['numeric_code'] ?? '0'; + $redis->hMset($newKey, $cacheArr); + } + + $preHkStock['stock_code'] = $param['stock_code']; + $preHkStock['stock_name'] = $param['stock_name']; + $preHkStock['tape'] = $param['tape']; + $preHkStock['status'] = $param['status']; + $preHkStock['price'] = $param['price']; + $preHkStock['start_time'] = $param['start_time']; + + // 新增数据 + $preHkStock['min'] = $param['min']; + $preHkStock['max'] = $param['max'] ?? 0; + $preHkStock['total'] = $param['total']; + $preHkStock['rate'] = $param['rate']; + $preHkStock['end_time'] = $param['end_time']; + $preHkStock['get_time'] = $param['get_time']; + $preHkStock['open_time'] = $param['open_time']; + $preHkStock['is_post_pay'] = $param['is_post_pay']; + if (!empty($param['pay_deadline_time'])) $preHkStock['pay_deadline_time'] = $param['pay_deadline_time']; + $preHkStock['limit_get_num'] = $param['limit_get_num'] ?? 100; + $preHkStock['is_delete'] = 1; + $preHkStock['update_time'] = date('Y-m-d H:i:s'); + $preHkStock['company_reg_amount'] = $companyRegAmount; + $preHkStock['company_open_time'] = $param['company_open_time']; + $preHkStock['company_info'] = $param['company_info']; + $preHkStock['logo'] = $param['logo']; + if ($market_type == 5) $preHkStock['numeric_code'] = $param['numeric_code'] ?? '0'; + $bool = Db::table($table_obj['stock_table'])->where('id', $param['id'])->update($preHkStock); + if ($bool) { + return $this->toData('0', 'SUCCESS'); + } else { + return $this->toData('1', 'FAIL'); + } + } catch (\Exception $exception) { + return $this->toData('0', '系统繁忙', [$exception->getMessage()]); + } + + } + + /** + * 删除IPO + */ + public function delStockIPO($market_type, $param) + { + try { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '主键 无效'); + } + + $preHkStock = Db::table($table_obj['stock_table'])->where('id', $param['id'])->where('is_delete', 1)->find(); + if (empty($preHkStock)) { + return $this->toData('1', '主键 无效'); + } + + + // 删除 + $list_key = $table_obj['redis_key'] . $preHkStock['stock_code']; + $redis = $this->getRedis(); + $redis->del($list_key); + + //删除 修改状态 + $preHkStock['is_delete'] = 2; + $preHkStock['update_time'] = date('Y-m-d H:i:s'); + $bool = Db::table($table_obj['stock_table'])->where('id', $param['id'])->update($preHkStock); + if ($bool) { + return $this->toData('0', 'SUCCESS'); + } else { + return $this->toData('1', 'FAIL'); + } + + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + /** + * IPO上市 + */ + public function stockIPO($market_type, $param) + { + try { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '市场类型无效'); + } + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '主键 无效'); + } + + $isReal = 1; + if (isset($param['is_real']) && is_numeric($param['is_real']) && $param['is_real'] == '2') { + $isReal = 2; + } + + $preInStock = Db::table($table_obj['stock_table'])->where('id', $param['id'])->where('is_delete', 1)->find(); + if (empty($preInStock)) { + return $this->toData('1', '主键 无效'); + } + + // 判断是否签名 + if ($preInStock['sign_status'] != 1) { + return $this->toData('1', '还未签名'); + } + + // 未签名 上市 + if ($preInStock['open_status'] != 1 || strtotime($preInStock['get_time']) < date('Y-m-d H:i:s')) { + return $this->toData('1', '无法操作'); + } + + + Db::startTrans(); + // 修改股票状态 + $num = Db::table($table_obj['stock_table'])->where('id', $preInStock['id'])->update(['open_status' => 2, + 'open_time' => date('Y-m-d H:i:s'), + 'update_time' => date('Y-m-d H:i:s')]); + if ($num <= 0) { + Db::rollback(); + return $this->toData('1', '股票状态修改失败'); + } + + $tape_list = $this->getStockTape($market_type); + + if (Db::table($table_obj['list_table'])->where('stock_code', $preInStock['stock_code'])->find()) { + Db::rollback(); + return $this->toData('1', '股票列表已存在该股票'); + } + // 将新股加入股票 + $inStock['stock_name'] = $preInStock['stock_name']; + $inStock['stock_code'] = $preInStock['stock_code']; + $inStock['status'] = 1; + $inStock['tape'] = $preInStock['tape']; + $inStock['keep_decimal'] = 4; + $inStock['info'] = ''; + $inStock['forced_closure'] = 30; + $inStock['up_limit'] = 30; + $inStock['down_limit'] = 30; + $inStock['create_time'] = date('Y-m-d H:i:s'); + $inStock['update_time'] = date('Y-m-d H:i:s'); + if ($market_type == 5) $inStock['numeric_code'] = $preInStock['numeric_code']; + $bool = Db::table($table_obj['list_table'])->insert($inStock); + if (!$bool) { + Db::rollback(); + return $this->toData('1', '股票转移失败'); + } + + // 加入缓存 + $list_key = $table_obj['redis_key'] . $preInStock['stock_code']; + $redis = $this->getRedis(); + $redis->del($list_key); + $cacheArr = [ + 'stock_name' => $inStock['stock_name'], + 'stock_code' => $inStock['stock_code'], + 'status' => $inStock['status'], + 'keep_decimal' => $inStock['keep_decimal'], + 'forced_closure' => $inStock['forced_closure'], + 'up_limit' => $inStock['up_limit'], + 'down_limit' => $inStock['down_limit'], + 'info' => $inStock['info'], + 'tape' => $inStock['tape'], + ]; + if ($market_type == 5) $cacheArr['numeric_code'] = $preInStock['numeric_code']; + + $redis->hMset($list_key, $cacheArr); + + + $hqArr = [ + 'type' => 'hq', + 'stock_code' => $inStock['stock_code'], + 'stock_name' => $inStock['stock_name'], + 'tape' => $tape_list['tape'][$inStock['tape']], + 'price' => $preInStock['price'], + 'isReal' => $isReal, + 'company_info' => $preInStock['company_info'], + 'country' => $table_obj['country'], + 'id' => $preInStock['id'], + 'market_type' => $market_type, + 'source' => 0 + ]; + if ($market_type == 7) $hqArr['source'] = 2; + if ($market_type == 5) $hqArr['numeric_code'] = $preInStock['numeric_code']; + + + Db::commit(); + + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + Db::rollback(); + trace('预售股上市失败' . $exception->getMessage(), 'error'); + return $this->toData('1', '系统繁忙', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function updateIPOStatus($market_type, $id, $type, $status, $order_no = '') + { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return false; + } + switch ($type) { + case 'trade': + $bool = Db::table($table_obj['stock_table'])->where('id', $id)->update([ + 'update_time' => date('Y-m-d H:i:s'), + 'trade_status' => $status + ]); + if ($bool && $status == 1) { + Db::table($table_obj['order_table'])->where('pre_stock_id', $id)->where('status', 3)->update([ + 'update_time' => date('Y-m-d H:i:s'), + 'trade_status' => 1 + ]); + } + break; + case 'last_trade': + $bool = Db::table($table_obj['order_table'])->where('pre_stock_id', $id)->where('order_no', $order_no)->update([ + 'update_time' => date('Y-m-d H:i:s'), + 'trade_status' => 1 + ]); + break; + case 'hq': + $bool = Db::table($table_obj['stock_table'])->where('id', $id)->update([ + 'update_time' => date('Y-m-d H:i:s'), + 'hq_status' => $status + ]); + break; + } + + if (!$bool) { + trace('预售股上市修改通知状态失败-' . $id, 'error'); + } + } + + public function repeatNoteGo($market_type, $param) + { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '市场类型无效'); + } + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '主键 无效'); + } + if (empty($param['type'])) { + return $this->toData('1', '缺少参数'); + } + $tape_list = $this->getStockTape($market_type); + + $preInStock = Db::table($table_obj['stock_table'])->where('id', $param['id'])->where('open_status', 2)->where('is_delete', 1)->find(); + if (empty($preInStock)) { + return $this->toData('1', '股票未上市'); + } + if ($preInStock['hq_status'] == 2 && $param['type'] == 'hq') { + // 给行情发送数据 + Queue::push('app\admin\job\SendGo', [ + 'type' => 'hq', + 'stock_code' => $preInStock['stock_code'], + 'stock_name' => $preInStock['stock_name'], + 'tape' => $tape_list['tape'][$preInStock['tape']], + 'price' => $preInStock['price'], + 'isReal' => 1, + 'company_info' => $preInStock['company_info'], + 'country' => $table_obj['country'], + 'id' => $preInStock['id'], + ], 'sendGo'); + } + if ($preInStock['trade_status'] == 2 && $param['type'] == 'trade') { + Queue::push('app\admin\job\SendGo', [ + 'type' => 'trade', + 'id' => $preInStock['id'], + 'stock_code' => $preInStock['stock_code'], + 'market_type' => $market_type + ], 'sendGo'); + } + return $this->toData('0', 'SUCCESS'); + + } + + + /** + * 处理股票IPO中签 + */ + public function signStockIPO($market_type) + { + try { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + trace('数据异常,股票市场:' . $market_type, 'info'); + return json(["数据异常"]); + } + $now = date('Y-m-d H:i:s'); + $preStockList = Db::table($table_obj['stock_table'])->where('is_delete', 1) + ->where('status', 1) + // 签名状态 + ->where('sign_status', 2) + // 中签时间已过 + ->whereTime('get_time', '<=', $now) + ->select(); + if ($preStockList->isEmpty()) { + trace('没有需要处理的新股,股票市场:' . $market_type, 'info'); + return json(["没有需要处理的新股"]); + } + foreach ($preStockList as $preStock) { + try { + // 单个股票 开始事务 + Db::startTrans(); + // 中签率 + $rate = bcdiv($preStock['rate'], 100, 6); + $rate = number_format($rate, '6', '.', ''); + + // 申购的订单列表 + $orderList = Db::table($table_obj['order_table'])->where('pre_stock_id', $preStock['id'])->whereIn('status', [1, 5])->select(); + if (!$orderList->isEmpty()) { + foreach ($orderList as $order) { + $status = ($order['status'] == 5) ? 5 : 2; // 中签 + $get_num = $order['get_num'] > 0 ? $order['get_num'] : ceil($order['num'] * $rate); // 计算中签 数量 * 中签率 向上取整 + $orderPrice = number_format($order['price'], '6', '.', ''); + $get_amount = bcmul($get_num, $orderPrice, 6); + $orderAmount = number_format($order['amount'], '6', '.', ''); + $diffAmount = bcsub($orderAmount, $get_amount, 6); + $feeRate = number_format($order['fee_rate'], '6', '.', ''); + $get_fee = bcmul($get_amount, $feeRate, 6); + $orderFee = number_format($order['fee'], '6', '.', ''); // 总手续费 + $diff_fee = bcsub($orderFee, $get_fee, 6); // 手续费差值 + // 修改订单数据 + $num = Db::table($table_obj['order_table'])->where('id', $order['id']) + ->update([ + 'status' => $status, + 'get_num' => $get_num, + 'get_amount' => $get_amount, + 'get_fee' => $get_fee, + 'get_time' => $now, + 'update_time' => $now]); + + if ($num <= 0) { + Db::rollback(); + trace('股票签名失败01,股票市场:' . $market_type . "股票名称:" . $preStock['stock_code'], 'info'); + return json(["股票签名失败00"]); + } + + //已退款订单 直接跳过 + if ($order['status'] == 7) continue; + + //后支付-未支付 直接跳过 + if ($order['pay_type'] == 2 && $order['status'] == 5) continue; + + // 回退本金 + if ($diffAmount > 0) { + // 新增金额 + $beforeAmount = Db::table($table_obj['user_table'])->where('user_id', $order['user_id'])->where('stock_id', $table_obj['stock_id'])->value('usable_num'); + $num = Db::table($table_obj['user_table'])->where('user_id', $order['user_id'])->where('stock_id', $table_obj['stock_id']) + ->inc('usable_num', $diffAmount) + ->dec('frozen_num', $diffAmount) + ->update(['update_time' => $now]); + if ($num <= 0) { + Db::rollback(); + trace('股票签名失败02,股票市场:' . $market_type . "股票名称:" . $preStock['stock_code'], 'info'); + return json(["股票签名失败02"]); + } + // 生成日志 + $userStockLog['user_id'] = $order['user_id']; + $userStockLog['change_type'] = 17; + $userStockLog['stock_id'] = $table_obj['stock_id']; + $userStockLog['before_num'] = $beforeAmount; + $userStockLog['change_num'] = $diffAmount; + $userStockLog['order_id'] = $order['order_no']; + $userStockLog['update_time'] = $now; + $userStockLog['create_time'] = $now; + $bool = Db::table($table_obj['log_table'])->insert($userStockLog); + if (!$bool) { + Db::rollback(); + trace('股票签名失败03,股票市场:' . $market_type . "股票名称:" . $preStock['stock_code'], 'info'); + return json(["股票签名失败03"]); + } + } + + // 退回手续费 + if ($diff_fee > 0) { + // 新增金额 + $beforeFee = Db::table($table_obj['user_table'])->where('user_id', $order['user_id'])->where('stock_id', $table_obj['stock_id'])->value('usable_num'); + $num = Db::table($table_obj['user_table'])->where('user_id', $order['user_id'])->where('stock_id', $table_obj['stock_id']) + ->inc('usable_num', $diff_fee) + ->dec('frozen_num', $diff_fee) + ->update(['update_time' => $now]); + if ($num <= 0) { + Db::rollback(); + trace('股票签名失败04,股票市场:' . $market_type . "股票名称:" . $preStock['stock_code'], 'info'); + return json(["股票签名失败04"]); + } + + // 生成日志 + + $userStockLogFee['user_id'] = $order['user_id']; + $userStockLogFee['change_type'] = 18; + $userStockLogFee['stock_id'] = $table_obj['stock_id']; + $userStockLogFee['before_num'] = $beforeFee; + $userStockLogFee['change_num'] = $diff_fee; + $userStockLogFee['order_id'] = $order['order_no']; + $userStockLogFee['update_time'] = $now; + $userStockLogFee['create_time'] = $now; + $bool = Db::table($table_obj['log_table'])->insert($userStockLogFee); + if (!$bool) { + Db::rollback(); + trace('股票签名失败05,股票市场:' . $market_type . "股票名称:" . $preStock['stock_code'], 'info'); + return json(["股票签名失败05"]); + } + } + } + + } + // 更新股票数据 + $bool = Db::table($table_obj['stock_table'])->where('id', $preStock['id'])->update(['sign_status' => 1, 'update_time' => $now]); + if (!$bool) { + Db::rollback(); + trace('股票签名失败07,股票市场:' . $market_type . "股票名称:" . $preStock['stock_code'], 'info'); + return json(["股票签名失败07"]); + } + // 提交事务 + Db::commit(); + + } catch (\Exception $exception) { + Db::rollback(); + trace("股票签名失败-exception 股票市场:" . $market_type . $exception->getMessage(), 'error'); + return json([$exception->getMessage()]); + } + } + return json(["SUCCESS"]); + } catch (\Exception $exception) { + trace("股票签名失败-exception 股票市场:" . $market_type . $exception->getMessage(), 'error'); + return json([$exception->getMessage()]); + } + } + + /** + * 股票列表 + */ + public function stockList($market_type, $param) + { + try { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + + validate(StockValidate::class)->scene($table_obj['check'] . 'index')->check($param); + $tapeList = $this->getStockTape($market_type); + + $stockCode = $param['stock_code'] ?? ''; + $where = []; + $whereOr = []; + if (!empty($stockCode)) { + if ($market_type == 5) { + $whereOr[] = ['stock_code', 'like', '%' . $stockCode]; + $whereOr[] = ['numeric_code', 'like', '%' . $stockCode]; + } else { + $where[] = ['stock_code', 'like', '%' . $stockCode]; + } + } + + $list = Db::table($table_obj['list_table'])->order('id', 'desc'); + $total = Db::table($table_obj['list_table'])->order('id', 'desc'); + + if (!empty($whereOr)) { + $list = $list->whereOr($whereOr); + $total = $total->whereOr($whereOr); + } + + if (!empty($where)) { + $list = $list->where($where); + $total = $total->where($where); + } + + $list = $list->page($param['page'], $param['limit'])->select(); + $total = $total->count(); + + return $this->toData('0', 'SUCCESS', ['list' => $list, 'total' => $total, 'extend' => [ + 'tape_list' => $tapeList['tape'], + 'source_list' => $tapeList['source'] ?? [], + ]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 添加股票 + */ + public function addStock($market_type, $param) + { + try { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + validate(StockValidate::class)->scene($table_obj['check'] . 'add')->check($param); + $info = ''; + if (isset($param['info']) && is_string($param['info'])) { + $info = $param['info']; + } + $tapeList = $this->getStockTape($market_type); + + // 判断股票交易所 + $tape = '0'; + if (isset($param['tape']) && in_array($param['tape'], array_keys($tapeList['tape']))) { + $tape = $param['tape']; + } + + if (empty($param['yesterday_close']) || !is_numeric($param['yesterday_close']) || $param['yesterday_close'] <= 0) { + return $this->toData('1', '昨日收盘价错误'); + } + if (strpos($param['stock_code'], ':') !== false) { + $param['stock_code'] = explode(':', $param['stock_code'])[1]; + } + if ($market_type != 3) { + $stock_code = $tapeList['tape'][$tape] . ":" . $param['stock_code']; + } else { + $stock_code = $param['stock_code']; + } + + // 判断股票代码是否已经存在 + $count = Db::table($table_obj['list_table'])->where('stock_code', $stock_code)->count(); + if ($count > 0) { + return $this->toData('1', '股票代码已经存在'); + } + + $source = 0; + if ($market_type == 7) { + $stockList['source'] = $source = $param['source'] ?? 1; + } + // 给行情推送 + $bool = $this->sendNewStockToGo($table_obj['country'], $stock_code, $stock_code, $param['stock_name'], $tapeList['tape'][$tape], $param['yesterday_close'], 1, '', $source, $param['numeric_code'] ?? '0'); + if (!$bool) { + return $this->toData('1', '数据设置成功 但给行情推送数据异常', []); + } + // 新增数据 + $stockList['stock_name'] = $param['stock_name']; + $stockList['stock_code'] = $stock_code; + $stockList['status'] = $param['status']; + $stockList['keep_decimal'] = $param['keep_decimal']; + $stockList['forced_closure'] = $param['forced_closure']; + $stockList['up_limit'] = $param['up_limit']; + $stockList['down_limit'] = $param['down_limit']; + $stockList['tape'] = $tape; // 交易所类型 + $stockList['info'] = $info; + $stockList['yesterday_close'] = $param['yesterday_close']; + $stockList['create_time'] = date('Y-m-d H:i:s'); + $stockList['update_time'] = date('Y-m-d H:i:s'); + if ($market_type == 5) $stockList['numeric_code'] = $param['numeric_code'] ?? '0'; + + $bool = Db::table($table_obj['list_table'])->insert($stockList); + if ($bool) { + // 新增缓存 + $list_key = $table_obj['redis_key'] . $stock_code; + $redis = $this->getRedis(); + $redis->del($list_key); + $redis_arr = [ + 'stock_name' => $param['stock_name'], + 'stock_code' => $stock_code, + 'status' => $param['status'], + 'keep_decimal' => $param['keep_decimal'], + 'forced_closure' => $param['forced_closure'], + 'up_limit' => $param['up_limit'], + 'down_limit' => $param['down_limit'], + 'info' => $info, + 'tape' => $tape, + ]; + if ($market_type == 5) $redis_arr['numeric_code'] = $param['numeric_code'] ?? '0'; + $redis->hMset($list_key, $redis_arr); + } + return $this->toData('0', 'SUCCESS', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + /** + * 编辑股票 + */ + public function editStock($market_type, $param) + { + try { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + validate(StockValidate::class)->scene($table_obj['check'] . 'edit')->check($param); + $stockList = Db::table($table_obj['list_table'])->where('id', $param['id'])->find(); + if (empty($stockList)) { + return $this->toData('1', '目标不存在', []); + } + + $info = ''; + if (isset($param['info']) && is_string($param['info'])) { + $info = $param['info']; + } + $tapeList = $this->getStockTape($market_type); + // 判断股票交易所 + $tape = '0'; + if (isset($param['tape']) && in_array($param['tape'], array_keys($tapeList['tape']))) { + $tape = $param['tape']; + } + + if (empty($param['yesterday_close']) || !is_numeric($param['yesterday_close']) || $param['yesterday_close'] <= 0) { + return $this->toData('1', '昨日收盘价错误'); + } + + if (strpos($param['stock_code'], ':') !== false) { + $param['stock_code'] = explode(':', $param['stock_code'])[1]; + } + if ($market_type != 3) { + $stock_code = $tapeList['tape'][$param['tape']] . ":" . $param['stock_code']; + } else { + $stock_code = $param['stock_code']; + } + $old_code = $stockList['stock_code']; + // 判断股票代码是否已经存在 + $count = Db::table($table_obj['list_table'])->where('stock_code', $stock_code)->where('id', '<>', $param['id'])->count(); + if ($count > 0) { + return $this->toData('1', '股票代码已经存在'); + } + + $source = 0; + if ($stock_code != $old_code || ($market_type == 7 && $param['source'] != $stockList['source'])) { + if ($market_type == 7) { + $stockList['source'] = $source = $param['source'] ?? 1; + } + // 给行情推送 + $bool = $this->sendNewStockToGo($table_obj['country'], $stock_code, $old_code, $param['stock_name'], $tapeList['tape'][$tape], $param['yesterday_close'], 1, '', $source, $param['numeric_code'] ?? '0'); + if (!$bool) { + return $this->toData('1', '数据设置成功 但给行情推送数据异常', []); + } + } + + if ($stock_code != $old_code) { + // 通知交易 + $bool = $this->sendUpdateCodeGo($stock_code, $old_code, $market_type); + if (!$bool) { + return $this->toData('1', '数据设置成功 但给交易推送数据异常', []); + } + //插针 + $stockPrices = StockPricesSettingModel::where('market_type', $market_type)->where('stock_id', $param['id'])->find(); + if (!empty($stockPrices)) { + // 添加缓存 + $old_key = 'STOCK_PRICES:' . $stockPrices->market_type . ':' . $old_code; + $new_key = 'STOCK_PRICES:' . $stockPrices->market_type . ':' . $stock_code; + $redis = $this->getRedis(); + $redis->del($old_key); + $redis->hMSet($new_key, [ + 'market_type' => $stockPrices->market_type, + 'stock_id' => $stockPrices->stock_id, + 'stock_code' => $stock_code, + 'status' => $stockPrices->status, + 'price' => $stockPrices->price, + ]); + } + //IPO + $stockIPO = Db::table($table_obj['stock_table'])->where('stock_code', $old_code)->find(); + if (!empty($stockIPO)) { + Db::table($table_obj['stock_table'])->where('stock_code', $old_code)->update(['stock_code' => $stock_code, 'update_time' => date('Y-m-d H:i:s')]); + } + } + + // 修改数据 + $stockList['stock_name'] = $param['stock_name']; + $stockList['stock_code'] = $stock_code; + $stockList['status'] = $param['status']; + $stockList['keep_decimal'] = $param['keep_decimal']; + $stockList['forced_closure'] = $param['forced_closure']; + $stockList['up_limit'] = $param['up_limit']; + $stockList['down_limit'] = $param['down_limit']; + $stockList['info'] = $info; + $stockList['tape'] = $tape; + $stockList['update_time'] = date('Y-m-d H:i:s'); + $stockList['yesterday_close'] = $param['yesterday_close']; + if ($market_type == 5) $stockList['numeric_code'] = $param['numeric_code'] ?? '0'; + + $bool = Db::table($table_obj['list_table'])->where('id', $param['id'])->update($stockList); + if ($bool) { + // 新增缓存 + $old_key = $table_obj['redis_key'] . $old_code; + $new_key = $table_obj['redis_key'] . $stock_code; + $redis = $this->getRedis(); + $redis->del($old_key); + $redis_arr = [ + 'stock_name' => $param['stock_name'], + 'stock_code' => $stock_code, + 'status' => $param['status'], + 'keep_decimal' => $param['keep_decimal'], + 'forced_closure' => $param['forced_closure'], + 'up_limit' => $param['up_limit'], + 'down_limit' => $param['down_limit'], + 'info' => $info, + 'tape' => $tape, + ]; + if ($market_type == 5) $redis_arr['numeric_code'] = $param['numeric_code'] ?? '0'; + $redis->hMset($new_key, $redis_arr); + } + + return $this->toData('0', 'SUCCESS', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 自动添加股票 + */ + public function autoAddStock($param) + { + try { + $market_type = intval($param['country']); + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + validate(StockValidate::class)->scene('stock_auto_add')->check($param); + + $tapeList = $this->getStockTape($market_type); + + $tape_arr = array_flip($tapeList['tape']); + + // 判断股票交易所 + $tape = '0'; + if (isset($param['tape']) && in_array($param['tape'], array_keys($tape_arr))) { + $tape = $tape_arr[$param['tape']]; + } + + $stock_code = $param['stock_code']; + // 判断股票代码是否已经存在 + $count = Db::table($table_obj['list_table'])->where('stock_code', $stock_code)->count(); + if ($count > 0) { + return $this->toData('1', '股票代码已经存在'); + } + // 新增数据 + $stockList['stock_name'] = $param['stock_name']; + $stockList['stock_code'] = $stock_code; + $stockList['status'] = 1; + $stockList['keep_decimal'] = 4; + $stockList['forced_closure'] = 30; + $stockList['up_limit'] = 30; + $stockList['down_limit'] = 30; + $stockList['tape'] = $tape; // 交易所类型 + $stockList['info'] = ''; + $stockList['yesterday_close'] = 0; + $stockList['create_time'] = date('Y-m-d H:i:s'); + $stockList['update_time'] = date('Y-m-d H:i:s'); + + $bool = Db::table($table_obj['list_table'])->insert($stockList); + if ($bool) { + // 新增缓存 + $list_key = $table_obj['redis_key'] . $stock_code; + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'stock_name' => $stockList['stock_name'], + 'stock_code' => $stock_code, + 'status' => $stockList['status'], + 'keep_decimal' => $stockList['keep_decimal'], + 'forced_closure' => $stockList['forced_closure'], + 'up_limit' => $stockList['up_limit'], + 'down_limit' => $stockList['down_limit'], + 'info' => '', + 'tape' => $tape, + ]); + } + return $this->toData('0', 'SUCCESS', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + + /** + * 取消上市 + */ + public function cancelIPO($market_type,$param){ + $table_obj = $this->getStockModel($market_type); + $redis = $this->getRedis(); + if (empty($table_obj)) { + return false; + } + $preStock = Db::table($table_obj['stock_table'])->where('is_delete', 1) + ->where('status', 1) + ->where('id', $param['pre_id']) + // 签名状态 + ->where('sign_status', 1) + ->where('open_status', 1) + ->find(); + if(empty($preStock)){ + return $this->toData('1', '数据异常'); + } + + //1、2已支付,5、6未支付可能存在借款 + $order_list = Db::table($table_obj['order_table'])->where('pre_stock_id', $param['pre_id']) + ->whereIn('status',[1,2,5,6]) + ->select(); + + $now = date('Y-m-d H:i:s'); + foreach ($order_list as $order){ + Db::startTrans(); + $total_num=$order['amount']+$order['fee']; + //查询订单有没有欠款 + $user_arrears=UserArrearsModel::where('order_no', $order['order_no'])->where('status',0)->where('user_id', $order['user_id'])->find(); + if($user_arrears){ + $user_arrears=$user_arrears->toArray(); + if($user_arrears['is_add']==1){ + //扣除冻结,不加可用 + $updateNum = Db::table($table_obj['user_table'])->where('stock_id', $table_obj['stock_id'])->where('user_id', $order['user_id']) + ->where('frozen_num', '>=', $total_num) + ->dec('frozen_num',$total_num) + ->update(['update_time' => $now]); + if(!$updateNum){ + Db::rollback(); + trace('给用户ID:' . $order['user_id'] . "解冻资金异常" . $order['order_no'], 'error'); + continue; + } + } + $update_bool=UserArrearsModel::where('order_no', $order['order_no'])->where('user_id', $order['user_id']) + ->update([ + 'update_time'=>$now, + 'status'=>1 + ]); + if(!$update_bool){ + Db::rollback(); + trace('给用户ID:' . $order['user_id'] . "更新贷款订单异常" . $order['order_no'], 'error'); + continue; + } + + $status=8; + }else{ + //扣除冻结 加可用 + $updateNum = Db::table($table_obj['user_table'])->where('stock_id', $table_obj['stock_id'])->where('user_id', $order['user_id']) + ->where('frozen_num', '>=', $total_num) + ->inc('usable_num', $total_num) + ->dec('frozen_num',$total_num) + ->update(['update_time' => $now]); + if(!$updateNum){ + Db::rollback(); + trace('给用户ID:' . $order['user_id'] . "解冻资金异常" . $order['order_no'], 'error'); + continue; + } + $status=7; + } + //更新状态 + $bool_status = Db::table($table_obj['order_table'])->where('id', $order['id'])->update([ + 'status' => $status, + 'update_time' => $now + ]); + if (!$bool_status) { + Db::rollback(); + trace('更新订单状态异常' . $order['order_no'], 'error'); + continue; + } + //删除缓存订单 + $key = "USER:ARREAR:ORDER:" . $order['order_no']; + $redis->del($key); + Db::commit(); + } + $bool = Db::table($table_obj['stock_table'])->where('id', $param['pre_id'])->update([ + 'is_delete'=>2, + 'update_time' => $now + ]); + if($bool){ + return $this->toData('0', 'SUCCESS'); + }else{ + return $this->toData('1', '数据异常'); + } + } + // 美股列表 + public function getTradeNameList($market_type) + { + try { + $table_obj = $this->getStockModel($market_type); + if (empty($table_obj)) { + return $this->toData('1', '数据异常'); + } + $list = Db::table($table_obj['list_table'])->where('status', 1)->order('id', 'desc')->column('stock_name', 'id'); + return $this->toData('0', 'SUCCESS', ['list' => $list]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + public function getStockModel($market_type) + { + //3美股、4印尼股、5马股、6泰股、7印度股、9新加坡股、12港股、14英股 + $prefix = env('database.prefix'); + switch ($market_type) { + case 3: + $result = [ + 'stock_table' => $prefix . 'pre_us_stock', + 'order_table' => $prefix . 'user_us_pre_stock_order', + 'user_table' => $prefix . 'user_stock', + 'log_table' => $prefix . 'user_stock_log', + 'list_table' => $prefix . 'stock_list', + 'trade_table' => $prefix . 'stock_trade', + 'give_order_table' => $prefix . 'user_us_give_stock_order', + 'redis_key' => 'US:STOCK:LIST:', + 'stock_id' => 'USD', + 'country' => 'US', + 'check' => 'us_stock_', + ]; + break; + case 4: + $result = [ + 'stock_table' => $prefix . 'pre_idn_stock', + 'order_table' => $prefix . 'user_idn_pre_stock_order', + 'user_table' => $prefix . 'user_stock_idn', + 'log_table' => $prefix . 'user_stock_idn_log', + 'list_table' => $prefix . 'stock_idn_list', + 'trade_table' => $prefix . 'stock_idn_trade', + 'give_order_table' => $prefix . 'user_idn_give_stock_order', + 'redis_key' => 'IDN:STOCK:LIST:', + 'stock_id' => 'IDR', + 'country' => 'Indonesia', + 'check' => 'idn_stock_', + ]; + break; + case 5: + $result = [ + 'stock_table' => $prefix . 'pre_mys_stock', + 'order_table' => $prefix . 'user_mys_pre_stock_order', + 'user_table' => $prefix . 'user_stock_mys', + 'log_table' => $prefix . 'user_stock_mys_log', + 'list_table' => $prefix . 'stock_mys_list', + 'trade_table' => $prefix . 'stock_mys_trade', + 'give_order_table' => $prefix . 'user_mys_give_stock_order', + 'redis_key' => 'MYS:STOCK:LIST:', + 'stock_id' => 'MYR', + 'country' => 'Malaysia', + 'check' => 'mys_stock_', + ]; + break; + case 6: + $result = [ + 'stock_table' => $prefix . 'pre_tha_stock', + 'order_table' => $prefix . 'user_tha_pre_stock_order', + 'user_table' => $prefix . 'user_stock_tha', + 'log_table' => $prefix . 'user_stock_tha_log', + 'list_table' => $prefix . 'stock_tha_list', + 'trade_table' => $prefix . 'stock_tha_trade', + 'give_order_table' => $prefix . 'user_tha_give_stock_order', + 'redis_key' => 'THA:STOCK:LIST:', + 'stock_id' => 'THB', + 'country' => 'Thailand', + 'check' => 'tha_stock_', + ]; + break; + case 7: + $result = [ + 'stock_table' => $prefix . 'pre_in_stock', + 'order_table' => $prefix . 'user_in_pre_stock_order', + 'user_table' => $prefix . 'user_stock_in', + 'log_table' => $prefix . 'user_stock_in_log', + 'list_table' => $prefix . 'stock_in_list', + 'trade_table' => $prefix . 'stock_in_trade', + 'give_order_table' => $prefix . 'user_in_give_stock_order', + 'redis_key' => 'IN:STOCK:LIST:', + 'stock_id' => 'INR', + 'country' => 'India', + 'check' => 'idn_stock_', + ]; + break; + case 9: + $result = [ + 'stock_table' => $prefix . 'pre_sgd_stock', + 'order_table' => $prefix . 'user_sgd_pre_stock_order', + 'user_table' => $prefix . 'user_stock_sgd', + 'log_table' => $prefix . 'user_stock_sgd_log', + 'list_table' => $prefix . 'stock_sgd_list', + 'trade_table' => $prefix . 'stock_sgd_trade', + 'give_order_table' => $prefix . 'user_sgd_give_stock_order', + 'redis_key' => 'SGD:STOCK:LIST:', + 'stock_id' => 'SGD', + 'country' => 'Singapore', + 'check' => 'sgd_stock_', + ]; + break; + case 12: + $result = [ + 'stock_table' => $prefix . 'pre_hkd_stock', + 'order_table' => $prefix . 'user_hkd_pre_stock_order', + 'user_table' => $prefix . 'user_stock_hkd', + 'log_table' => $prefix . 'user_stock_hkd_log', + 'list_table' => $prefix . 'stock_hkd_list', + 'trade_table' => $prefix . 'stock_hkd_trade', + 'give_order_table' => $prefix . 'user_hkd_give_stock_order', + 'redis_key' => 'HKD:STOCK:LIST:', + 'stock_id' => 'HKD', + 'country' => 'HongKong', + 'check' => 'hk_stock_', + ]; + break; + case 14: + $result = [ + 'stock_table' => $prefix . 'pre_gbx_stock', + 'order_table' => $prefix . 'user_gbx_pre_stock_order', + 'user_table' => $prefix . 'user_stock_gbx', + 'log_table' => $prefix . 'user_stock_gbx_log', + 'list_table' => $prefix . 'stock_gbx_list', + 'trade_table' => $prefix . 'stock_gbx_trade', + 'give_order_table' => $prefix . 'user_gbx_give_stock_order', + 'redis_key' => 'UK:STOCK:LIST:', + 'stock_id' => 'GBX', + 'country' => 'UK', + 'check' => 'gbx_stock_', + ]; + break; + case 15: + $result = [ + 'stock_table' => $prefix . 'pre_fur_stock', + 'order_table' => $prefix . 'user_fur_pre_stock_order', + 'user_table' => $prefix . 'user_stock_fur', + 'log_table' => $prefix . 'user_stock_fur_log', + 'list_table' => $prefix . 'stock_fur_list', + 'trade_table' => $prefix . 'stock_fur_trade', + 'give_order_table' => $prefix . 'user_fur_give_stock_order', + 'redis_key' => 'FUR:STOCK:LIST:', + 'stock_id' => 'EUR', + 'country' => 'FUR', + 'check' => 'fur_stock_', + ]; + break; + case 16: + $result = [ + 'stock_table' => $prefix . 'pre_eur_stock', + 'order_table' => $prefix . 'user_eur_pre_stock_order', + 'user_table' => $prefix . 'user_stock_eur', + 'log_table' => $prefix . 'user_stock_eur_log', + 'list_table' => $prefix . 'stock_eur_list', + 'trade_table' => $prefix . 'stock_eur_trade', + 'give_order_table' => $prefix . 'user_eur_give_stock_order', + 'redis_key' => 'EUR:STOCK:LIST:', + 'stock_id' => 'EUR', + 'country' => 'EUR', + 'check' => 'eur_stock_', + ]; + break; + case 17: + $result = [ + 'stock_table' => $prefix . 'pre_brl_stock', + 'order_table' => $prefix . 'user_brl_pre_stock_order', + 'user_table' => $prefix . 'user_stock_brl', + 'log_table' => $prefix . 'user_stock_brl_log', + 'list_table' => $prefix . 'stock_brl_list', + 'trade_table' => $prefix . 'stock_brl_trade', + 'give_order_table' => $prefix . 'user_brl_give_stock_order', + 'redis_key' => 'BR:STOCK:LIST:', + 'stock_id' => 'BRL', + 'country' => 'BRL', + 'check' => 'brl_stock_', + ]; + break; + case 18: + $result = [ + 'stock_table' => $prefix . 'pre_jp_stock', + 'order_table' => $prefix . 'user_jp_pre_stock_order', + 'user_table' => $prefix . 'user_stock_jp', + 'log_table' => $prefix . 'user_stock_jp_log', + 'list_table' => $prefix . 'stock_jp_list', + 'trade_table' => $prefix . 'stock_jp_trade', + 'give_order_table' => $prefix . 'user_jp_give_stock_order', + 'redis_key' => 'JP:STOCK:LIST:', + 'stock_id' => 'JPY', + 'country' => 'Japan', + 'check' => 'jp_stock_', + ]; + break; + default: + $result = []; + break; + } + return $result; + } + + public function getStockTape($market_type) + { + //3美股、4印尼股、5马股、6泰股、7印度股、9新加坡股、12港股 + $result = []; + switch ($market_type) { + case 3: + $result = [ + 'tape' => StockListModel::$tapeList, + 'type' => PreUsStockModel::$stockTypeList, + ]; + break; + case 4: + $result = [ + 'tape' => StockIdnListModel::$tapeList, + 'type' => PreIdnStockModel::$stockTypeList, + ]; + break; + case 5: + $result = [ + 'tape' => StockMysListModel::$tapeList, + 'type' => PreMysStockModel::$stockTypeList, + ]; + break; + case 6: + $result = [ + 'tape' => StockThaListModel::$tapeList, + 'type' => PreThaStockModel::$stockTypeList, + ]; + break; + case 7: + $result = [ + 'tape' => StockInListModel::$tapeList, + 'type' => PreInStockModel::$stockTypeList, + 'source' => StockInListModel::SOURCE_LIST, + ]; + break; + case 9: + $result = [ + 'tape' => StockSgdListModel::$tapeList, + 'type' => PreSgdStockModel::$stockTypeList, + ]; + break; + case 12: + $result = [ + 'tape' => StockHkdListModel::$tapeList, + 'type' => PreHkdStockModel::$stockTypeList, + ]; + break; + case 14: + $result = [ + 'tape' => StockGBXListModel::$tapeList, + 'type' => PreGBXStockModel::$stockTypeList, + ]; + break; + case 15: + $result = [ + 'tape' => StockFurListModel::$tapeList, + 'type' => PreFurStockModel::$stockTypeList, + ]; + break; + case 16: + $result = [ + 'tape' => StockEurListModel::$tapeList, + 'type' => PreEurStockModel::$stockTypeList, + ]; + break; + case 17: + $result = [ + 'tape' => StockBrlListModel::$tapeList, + 'type' => PreBrlStockModel::$stockTypeList, + ]; + break; + case 18: + $result = [ + 'tape' => StockJpListModel::$tapeList, + 'type' => PreJpStockModel::$stockTypeList, + ]; + break; + } + return $result; + } + +} diff --git a/app/admin/service/setting/LanguageService.php b/app/admin/service/setting/LanguageService.php new file mode 100644 index 0000000..f95c36e --- /dev/null +++ b/app/admin/service/setting/LanguageService.php @@ -0,0 +1,123 @@ +select(); + $rows = []; + if(!$list->isEmpty()){ + $rows = $list->toArray(); + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + public function add($param) + { + + try { + if(empty($param['language_name']) || !is_string($param['language_name']) || strlen($param['language_name']) > 20){ + return $this->toData('1','参错错误'); + } + if(empty($param['language_code']) || !is_string($param['language_code']) || strlen($param['language_code']) > 20){ + return $this->toData('1','参错错误'); + } + if(empty($param['china_name']) || !is_string($param['china_name']) || strlen($param['china_name']) > 20){ + return $this->toData('1','参错错误'); + } + + $count = LanguageSettingModel::where('language_code', $param['language_code'])->count(); + if($count > 0){ + return $this->toData('1','语言代码已经存在'); + } + + $lang = new LanguageSettingModel; + $lang->language_name = $param['language_name']; + $lang->language_code = $param['language_code']; + $lang->china_name = $param['china_name']; + $lang->save(); + return $this->toData('0', 'SUCCESS', []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1','参错错误1'); + } + + $lang = LanguageSettingModel::where('id', $param['id'])->find(); + if(empty($lang)){ + return $this->toData('1','目标不存在'); + } + + if(empty($param['language_name']) || !is_string($param['language_name']) || strlen($param['language_name']) > 20){ + return $this->toData('1','参错错误2'); + } + if(empty($param['language_code']) || !is_string($param['language_code']) || strlen($param['language_code']) > 20){ + return $this->toData('1','参错错误3'); + } + if(empty($param['china_name']) || !is_string($param['china_name']) || strlen($param['china_name']) > 20){ + return $this->toData('1','参错错误4'); + } + + $count = LanguageSettingModel::where('language_code', $param['language_code']) + ->where('id', '<>', $param['id']) + ->count(); + if($count > 0){ + return $this->toData('1','语言代码已经存在'); + } + + $lang->language_name = $param['language_name']; + $lang->language_code = $param['language_code']; + $lang->china_name = $param['china_name']; + $lang->save(); + return $this->toData('0', 'SUCCESS', []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + + public function del($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1','参错错误'); + } + + $lang = LanguageSettingModel::where('id', $param['id'])->find(); + if(empty($lang)){ + return $this->toData('1','目标不存在'); + } + + $lang->delete(); + return $this->toData('0','SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + public function getNameList() + { + try { + $list = LanguageSettingModel::order('id', 'desc')->column('language_name', 'id'); + return $this->toData('0', 'SUCCESS', ['list' => $list]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/MarketService.php b/app/admin/service/setting/MarketService.php new file mode 100644 index 0000000..b118190 --- /dev/null +++ b/app/admin/service/setting/MarketService.php @@ -0,0 +1,161 @@ +order('id', 'desc') + ->select(); + $rows = []; + if(!$list->isEmpty()){ + foreach ($list as $item){ + if(empty($rows[$item['trade_name']])){ + $rows[$item['trade_name']] = [ + 'trade_name' => $item['trade_name'], + 'begin_time' => $item['begin_time'], + 'end_time' => $item['end_time'], + 'max_price' => $item['max_price'], + 'step' => $item['step'], + ]; + } + } + } + + $rows = array_values($rows); + return $this->toData('0','SUCCSS',['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + // 详情 + public function detail($param) + { + try { + if(empty($param['trade_name']) || !is_string($param['trade_name'])){ + return $this->toData('1', '参数错误'); + } + $list = ContractMarketModel::where('type', 1) + ->where('trade_name', $param['trade_name']) + ->order('id', 'desc')->select(); + $rows = []; + if(!$list->isEmpty()){ + foreach ($list as $item){ + $rows[] = [ + 'id' => $item['id'], + 'trade_name' => $item['trade_name'], + 'end_time' => $item['end_time'], + 'begin_time' => $item['begin_time'], + 'max_price' => $item['max_price'], + 'step' => $item['step'], + ]; + } + } + return $this->toData('0','SUCCSS',['list' => $rows]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 新增 + public function add($param) + { + try { + // 参数校验 + validate(MarketValidate::class)->scene('add')->check($param); + + // 必须大于当前时间 + if(strtotime($param['end_time']) - time() <= 0){ + return $this->toData('1','时间无效'); + } + + + if((strtotime($param['begin_time']) - time()) <= 0 || (strtotime($param['end_time']) - strtotime($param['begin_time'])) <= 0){ + return $this->toData('1','开始时间无效'); + } + + $market = new ContractMarketModel; + $market->trade_name = $param['trade_name']; + $market->begin_time = $param['begin_time']; + $market->end_time = $param['end_time']; + $market->max_price = $param['max_price']; + $market->type = 1; + $market->save(); + + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + // 编辑 + public function edit($param) + { + try { + // 参数校验 + validate(MarketValidate::class)->scene('edit')->check($param); + + // 目标 + $market = ContractMarketModel::where('id', $param['id'])->where('type', 1)->find(); + if(empty($market)){ + return $this->toData('1','目标不存在'); + } + + // 必须大于当前时间 + if(strtotime($param['end_time']) - time() <= 0){ + return $this->toData('1','时间无效'); + } + + if((strtotime($param['begin_time']) - time()) <= 0 || (strtotime($param['end_time']) - strtotime($param['begin_time'])) <= 0){ + return $this->toData('1','开始时间无效'); + } + + + $market->trade_name = $param['trade_name']; + $market->begin_time = $param['begin_time']; + $market->end_time = $param['end_time']; + $market->max_price = $param['max_price']; + $market->save(); + + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } + + // 删除 + public function del($param) + { + try { + // 参数校验 + validate(MarketValidate::class)->scene('del')->check($param); + + // 目标 + $market = ContractMarketModel::where('id', $param['id'])->where('type',1)->find(); + if(empty($market)){ + return $this->toData('1','目标不存在'); + } + + $market->delete(); + return $this->toData('0','SUCCESS'); + }catch (ValidateException $validateException){ + return $this->toData('1', $validateException->getMessage(), []); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/OptionInService.php b/app/admin/service/setting/OptionInService.php new file mode 100644 index 0000000..e64c314 --- /dev/null +++ b/app/admin/service/setting/OptionInService.php @@ -0,0 +1,327 @@ +scene('in_option_index')->check($param); + + $stockCode = $param['stock_code'] ?? ''; + $where = []; + if ($stockCode) { + $where[] = ['stock_code', '=', $stockCode]; + } + $list = StockOptionInrListModel::where($where)->page($param['page'], $param['limit'])->append(['tape_text', 'status_text'])->order('id', 'desc')->select(); + $total = StockOptionInrListModel::order('id', 'desc')->where($where)->count(); + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total, 'extend' => [ + 'tape_list' => StockOptionInrListModel::$tapeListText, + 'status_list' => StockOptionInrListModel::$statusList + ]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + public function add($param) + { + try { + validate(StockValidate::class)->scene('in_option_add')->check($param); + $info = ''; + if (isset($param['info']) && is_string($param['info'])) { + $info = $param['info']; + } + + // 判断股票交易所 + $tape = '0'; + if (isset($param['tape']) && in_array($param['tape'], array_keys(StockOptionInrListModel::$tapeList))) { + $tape = $param['tape']; + } + + // 判断股票代码是否已经存在 + $count = StockOptionInrListModel::where('stock_code', $param['stock_code'])->count(); + if ($count > 0) { + return $this->toData('1', '股票代码已经存在'); + } + + // 新增数据 + $stockList = new StockOptionInrListModel; + $stockList->stock_name = $param['stock_name']; + $stockList->stock_code = $param['stock_code']; + $stockList->status = $param['status']; + $stockList->rate = $param['rate'] ?? 0; + $stockList->keep_decimal = $param['keep_decimal'] ?? 4; + $stockList->forced_closure = $param['forced_closure'] ?? 30; + $stockList->up_limit = $param['up_limit'] ?? 30; + $stockList->down_limit = $param['down_limit'] ?? 30; + $stockList->info = $info; + $stockList->tape = $tape; + $stockList->create_time = date('Y-m-d H:i:s'); + $stockList->update_time = date('Y-m-d H:i:s'); + $stockList->save(); + + // 新增缓存 + $list_key = "IN:OPTION:LIST:" . $param['stock_code']; + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'stock_name' => $param['stock_name'], + 'stock_code' => $param['stock_code'], + 'status' => $param['status'], + 'keep_decimal' => $param['keep_decimal'] ?? 4, + 'forced_closure' => $param['forced_closure'] ?? 30, + 'up_limit' => $param['up_limit'] ?? 30, + 'down_limit' => $param['down_limit'] ?? 30, + 'rate' => $param['rate'] ?? 0, + 'info' => $info, + 'tape' => $tape, + ]); + + // 给行情推送 +// $bool = $this->sendDecimalToGo('Indonesia', $stockList->stock_code, $stockList->keep_decimal); +// $bool = $this->sendNewStockToGo('India', $stockList->stock_code, $stockList->stock_name, StockOptionInrListModel::$tapeList[$tape]); + +// if (!$bool) { +// return $this->toData('1', '数据设置成功 但给行情推送数据异常', []); +// } + + return $this->toData('0', 'SUCCESS', []); + + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + + public function edit($param) + { + try { + validate(StockValidate::class)->scene('in_option_edit')->check($param); + + $stockList = StockOptionInrListModel::where('id', $param['id'])->find(); + if (empty($stockList)) { + return $this->toData('1', '目标不存在', []); + } + + $info = ''; + if (isset($param['info']) && is_string($param['info'])) { + $info = $param['info']; + } + + // 判断股票交易所 + $tape = '0'; + if (isset($param['tape']) && in_array($param['tape'], array_keys(StockOptionInrListModel::$tapeList))) { + $tape = $param['tape']; + } + + // 判断股票代码是否已经存在 + $count = StockOptionInrListModel::where('stock_code', $param['stock_code'])->where('id', '<>', $param['id'])->count(); + if ($count > 0) { + return $this->toData('1', '股票代码已经存在'); + } + + // 修改数据 + $stockList->stock_name = $param['stock_name']; + $stockList->stock_code = $param['stock_code']; + $stockList->status = $param['status']; + $stockList->rate = $param['rate'] ?? 0; + $stockList->keep_decimal = $param['keep_decimal'] ?? 4; + $stockList->forced_closure = $param['forced_closure'] ?? 30; + $stockList->up_limit = $param['up_limit'] ?? 30; + $stockList->down_limit = $param['down_limit'] ?? 30; + $stockList->info = $info; + $stockList->tape = $tape; + $stockList->update_time = date('Y-m-d H:i:s'); + $stockList->save(); + + // 新增缓存 + $list_key = "IN:OPTION:LIST:" . $param['stock_code']; + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'stock_name' => $param['stock_name'], + 'stock_code' => $param['stock_code'], + 'status' => $param['status'], + 'keep_decimal' => $param['keep_decimal'] ?? 4, + 'forced_closure' => $param['forced_closure'] ?? 30, + 'up_limit' => $param['up_limit'] ?? 30, + 'down_limit' => $param['down_limit'] ?? 30, + 'rate' => $param['rate'] ?? 0, + 'info' => $info, + 'tape' => $tape, + ]); + + // 给行情推送 +// $bool = $this->sendNewStockToGo('India', $stockList->stock_code, $stockList->stock_name, StockOptionInrListModel::$tapeList[$tape]); +// +// if (!$bool) { +// return $this->toData('1', '数据设置成功 但给行情推送数据异常', []); +// } + + return $this->toData('0', 'SUCCESS', []); + + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + // 列表 + public function getTradeNameList() + { + try { + $list = StockOptionInrListModel::where('status', 1)->order('id', 'desc')->column('stock_name', 'id'); + return $this->toData('0', 'SUCCESS', ['list' => $list]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + public function refresh() + { + try { + + $ch = curl_init(); + + $url = env('OPTION_REFRESH.OPTION_REFRESH_IN_URL'); + + curl_setopt($ch, CURLOPT_URL, $url); // Set the URL + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Return the response as a string + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Follow any redirects + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // This should be set to true in production, disables SSL certificate verification (only for testing) + + $response = curl_exec($ch); + if (curl_errno($ch)) { + echo 'Curl error: ' . curl_error($ch); + } + + curl_close($ch); + + $data = json_decode($response, true); + if (empty($data) || empty($data['data']) || empty($data['code']) || (!empty($data['code']) && $data['code'] != 200)) { + return; + } + + $now = date('Y-m-d H:i:s'); // 订单时间 + $insertArr = []; + $responseCodeArr = array_column($data['data'], 'Code'); + $dataCodeArr = StockOptionInrListModel::column('stock_code'); + $result = array_diff($responseCodeArr, $dataCodeArr); + foreach ($data['data'] as $v) { + if (in_array($v['Code'], $result)) { + $insertArr[] = [ + 'stock_name' => $v['Code'], + 'stock_code' => $v['Code'], + 'status' => 1, + 'tape' => StockOptionInrListModel::$tapeList[$v['Exchange']] ?? 1, + 'keep_decimal' => 4, + 'create_time' => $now, + 'update_time' => $now, + 'rate' => 30, + 'forced_closure' => 30, + 'up_limit' => 30, + 'down_limit' => 30 + ]; + } + } + $StockOptionInrListModel = new StockOptionInrListModel(); + $StockOptionInrListModel::insertAll($insertArr); + + $redis = $this->getRedis(); + foreach ($insertArr as $cacheV) { + $list_key = "IN:OPTION:LIST:" . $cacheV['stock_code']; + $redis->del($list_key); + $redis->hMset($list_key, [ + 'stock_name' => $cacheV['stock_name'], + 'stock_code' => $cacheV['stock_code'], + 'status' => $cacheV['status'], + 'keep_decimal' => $cacheV['keep_decimal'], + 'forced_closure' => $cacheV['forced_closure'], + 'up_limit' => $cacheV['up_limit'], + 'down_limit' => $cacheV['down_limit'], + 'rate' => $cacheV['rate'], + 'info' => '', + 'tape' => $cacheV['tape'], + ]); + } + + + } catch (\Exception $exception) { + } + } + + public function batchEdit($param) + { + try { + $rate = $param['rate']; + $keep_decimal = $param['keep_decimal']; + $forced_closure = $param['forced_closure']; + $status = $param['status']; + $updateArr = ['rate' => $rate, 'keep_decimal' => $keep_decimal, 'forced_closure' => $forced_closure, 'status' => $status, 'update_time' => date('Y-m-d H:i:s')]; + StockOptionInrListModel::where(1, '=', 1)->update($updateArr); + + $dataCodeArr = StockOptionInrListModel::select()->toArray(); + $redis = $this->getRedis(); + foreach ($dataCodeArr as $cacheV) { + $list_key = "IN:OPTION:LIST:" . $cacheV['stock_code']; + $redis->del($list_key); + $redis->hMset($list_key, [ + 'stock_name' => $cacheV['stock_name'], + 'stock_code' => $cacheV['stock_code'], + 'status' => $cacheV['status'], + 'keep_decimal' => $cacheV['keep_decimal'], + 'forced_closure' => $cacheV['forced_closure'], + 'up_limit' => $cacheV['up_limit'], + 'down_limit' => $cacheV['down_limit'], + 'rate' => $cacheV['rate'], + 'info' => $cacheV['info'], + 'tape' => $cacheV['tape'], + ]); + } + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + public function onOff($param) + { + try { + $id = $param['id']; + $stockList = StockOptionInrListModel::where('id', $param['id'])->find(); + if (empty($stockList)) { + return $this->toData('1', '目标不存在', []); + } + $status = $stockList->status == 0 ? 1 : 0; + $updateArr = ['status' => $status, 'update_time' => date('Y-m-d H:i:s')]; + StockOptionInrListModel::where('id', $id)->update($updateArr); + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/PaymentService.php b/app/admin/service/setting/PaymentService.php new file mode 100644 index 0000000..eb83683 --- /dev/null +++ b/app/admin/service/setting/PaymentService.php @@ -0,0 +1,154 @@ +scene('payment_index')->check($param); + $list = PaymentListModel::order('id', 'desc')->page($param['page'], $param['limit'])->select(); + $total = PaymentListModel::order('id', 'desc')->count(); + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total, 'extend' => ['type_list' => PaymentListModel::TPYE_LIST]]); + } catch (ValidateException $validateException) { + // 参数校验失败 + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + public function add($param) + { + try { + validate(PaymentValidate::class)->scene('payment_add')->check($param); + // 新增数据 + $payment = new PaymentListModel(); + $payment->country = $param['country']; + $payment->channel = $param['channel']; + $payment->pay_type = $param['pay_type']; + $payment->service_rate = $param['service_rate']; + $payment->type = $param['type'] ?? 1; + $payment->status = $param['status']; + $payment->channel_type = $param['channel_type']; +// $payment->exchange_rate = $param['exchange_rate']; + $payment->is_recharge = $param['is_recharge']; + $payment->is_withdrawal = $param['is_withdrawal']; + $payment->is_online = $param['is_online']; + if (isset($param['bank_name'])) { + $payment->bank_name = $param['bank_name']; + } + if (isset($param['bank_branch'])) { + $payment->bank_branch = $param['bank_branch']; + } + if (isset($param['bank_user'])) { + $payment->bank_user = $param['bank_user']; + } + if (isset($param['bank_account'])) { + $payment->bank_account = $param['bank_account']; + } + if (isset($param['wallet_address'])) { + $payment->wallet_address = $param['wallet_address']; + } + if (isset($param['unit'])) { + $payment->unit = $param['unit']; + } + if (isset($param['account_type'])) { + $payment->account_type = $param['account_type']; + } + if (isset($param['ifsc'])) { + $payment->ifsc = $param['ifsc']; + } + if (isset($param['extra_name'])) { + $payment->extra_name = $param['extra_name']; + } + if (isset($param['extra_list'])) { + $payment->extra_list = $param['extra_list']; + } + $payment->save(); + return $this->toData('0', 'SUCCESS', []); + + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + public function edit($param) + { + try { + validate(PaymentValidate::class)->scene('payment_edit')->check($param); + + $payment_info = PaymentListModel::where('id', $param['id'])->find(); + if (empty($payment_info)) { + return $this->toData('1', '目标不存在', []); + } + $param['type'] = $param['type'] ?? 1; + PaymentListModel::where('id', $param['id'])->update($param); + return $this->toData('0', 'SUCCESS', []); + + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function info($param) + { + try { + validate(PaymentValidate::class)->scene('payment_info')->check($param); + $payment_info = PaymentListModel::where('id', $param['id'])->find(); + if (empty($payment_info)) { + return $this->toData('1', '目标不存在', []); + } + return $this->toData('0', 'SUCCESS', $payment_info->toArray()); + + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + + } + + public function del($param) + { + try { + validate(PaymentValidate::class)->scene('payment_info')->check($param); + $payment_info = PaymentListModel::where('id', $param['id'])->find(); + if (empty($payment_info)) { + return $this->toData('1', '目标不存在', []); + } + PaymentListModel::where('id', $param['id'])->delete(); + return $this->toData('0', 'SUCCESS', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('1', $message); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + + } +} \ No newline at end of file diff --git a/app/admin/service/setting/PreFundStockService.php b/app/admin/service/setting/PreFundStockService.php new file mode 100644 index 0000000..a725fab --- /dev/null +++ b/app/admin/service/setting/PreFundStockService.php @@ -0,0 +1,690 @@ +toData('1', '分页参数错误'); + } + $where = []; + // 未删除 + $where[] = [ + 'is_delete', '=', PreFundStockModel::IS_DELETE_NO + ]; + // 基金号 + if (!empty($param['stock_code']) && is_string($param['stock_code'])) { + $where[] = [ + 'stock_code', '=', $param['stock_code'] + ]; + } + + $query = PreFundStockModel::where($where)->withJoin(['history' => ['stock_code', 'start_date', 'end_date', 'start_point', 'end_point']])->order('id', 'desc'); + $totalQuery = PreFundStockModel::where($where)->order('id', 'desc'); + if (!empty($param['open_status']) && in_array($param['open_status'], PreFundStockModel::$openStatusList)) { + $query = $query->where('open_status', $param['open_status']); + $totalQuery = $totalQuery->where('open_status', $param['open_status']); + } + + $list = $query->append(['stock_type_text', 'open_status_text'])->order('id', 'desc')->page($param['page'], $param['limit'])->select(); + $total = $totalQuery->order('id', 'desc')->count(); + $rows = []; + if (!$list->isEmpty()) { + $rows = $list->toArray(); + foreach ($rows as $key => $item) { + $rows[$key]['product_file'] = json_decode($item['product_file'], true); + $rows[$key]['current_manager'] = json_decode($item['current_manager'], true); + } + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total, 'extend' => [ + 'open_status_list' => PreFundStockModel::$openStatusList, + 'stock_type_list' => PreFundStockModel::$stockTypeList, + 'interest_type_list' => PreFundStockModel::$interestTypeList, + 'cycle_type_list' => PreFundStockModel::$cycleTypeList, + 'symbol' => 'USD' + + ]]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 历史走势 + public function history($param) + { + try { + if (empty($param['stock_code'])) { + return $this->toData('1', '基本代码 无效'); + } + $history = HistoryFundStockModel::where('stock_code', $param['stock_code'])->value('history_info'); + $history = json_decode($history, true); + return $this->toData('0', 'SUCCESS', ['history_info' => $history]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 新增 + public function add($param) + { + try { + // 基金代码 + if (empty($param['stock_code']) || !is_string($param['stock_code'])) { + return $this->toData('1', '基金代码 无效'); + } + + // 基金名称 + if (empty($param['stock_name']) || !is_string($param['stock_name'])) { + return $this->toData('1', '基金名称 无效'); + } + + // 基金类型 + if (empty($param['stock_type']) || !in_array($param['stock_type'], array_keys(PreFundStockModel::$stockTypeList))) { + return $this->toData('1', '基金类型 无效'); + } + + // 返利类型 + if (empty($param['interest_type']) || !in_array($param['interest_type'], array_keys(PreFundStockModel::$interestTypeList))) { + return $this->toData('1', '返利类型 无效'); + } + + // 周期单位 + if (empty($param['cycle_type']) || !in_array($param['cycle_type'], array_keys(PreFundStockModel::$cycleTypeList))) { + return $this->toData('1', '返利类型 无效'); + } + + // 收益率 两位小数 + if (empty($param['rate']) || !is_numeric($param['rate']) || $param['rate'] <= 0) { + return $this->toData('1', '基金收益率 无效'); + } + + // 基金周期 + if (empty($param['cycle']) || !is_numeric($param['cycle']) || $param['cycle'] <= 0) { + return $this->toData('1', '基金周期 无效'); + } + + // 最低申购价格 + if (empty($param['min_price']) || !is_numeric($param['min_price']) || $param['min_price'] <= 0) { + return $this->toData('1', '最低申购金额 无效'); + } + + // 开始认购时间 + if (empty($param['start_time']) || !is_string($param['start_time'])) { + return $this->toData('1', '开始认购时间 无效'); + } + + // 认购结束时间 + if (empty($param['end_time']) || !is_string($param['end_time'])) { + return $this->toData('1', '认购结束时间 无效'); + } + + // 基金logo + if (empty($param['logo']) || !is_string($param['logo'])) { + return $this->toData('1', '基金logo 无效'); + } + + // 基金标签 + $tag = ""; + if (!empty($param['tag']) && is_string($param['tag'])) { + $tag = $param['tag']; + } + + // 认购结束时间要大于 认购开始时间 + if (strtotime($param['end_time']) <= strtotime($param['start_time'])) { + return $this->toData('1', ' 认购结束时间 晚于 认购开始时间'); + } + + // 1.0 判断基金号是否已经存在 + $preStock = PreFundStockModel::where('stock_code', $param['stock_code'])->find(); + if (!empty($preStock)) { + return $this->toData('1', '基金号已经存在'); + } + + // 历史走势 起始日期 + if (empty($param['start_date']) || !is_string($param['start_date'])) { + return $this->toData('1', '历史走势 起始日期 无效'); + } + + // 历史走势 结束日期 + if (empty($param['end_date']) || !is_string($param['end_date'])) { + return $this->toData('1', '历史走势 结束日期 无效'); + } + + if (strtotime($param['end_date']) <= strtotime($param['start_date']) || strtotime($param['end_date']) - time() > 0) { + return $this->toData('1', '历史走势-开始日期 要大于 历史走势-结束日期 ; 历史走势-结束日期 要小于 当前时间'); + } + + // 历史走势 起始值 + if (empty($param['start_point']) || !is_numeric($param['start_point'])) { + return $this->toData('1', '历史走势 起始值 无效'); + } + + // 历史走势 结束值 + if (empty($param['end_point']) || !is_numeric($param['end_point'])) { + return $this->toData('1', '历史走势 结束值 无效'); + } + + Db::startTrans(); + // 新增数据 + $preFundStock = new PreFundStockModel(); + $preFundStock->stock_code = $param['stock_code']; + $preFundStock->stock_name = $param['stock_name']; + $preFundStock->stock_type = $param['stock_type']; + $preFundStock->show_interest = $param['show_interest'] ?? 66; + $preFundStock->tape = $param['tape'] ?? 1; + $preFundStock->status = $param['status'] ?? 0; + $preFundStock->min_price = $param['min_price']; + $preFundStock->rate = $param['rate']; + $preFundStock->cycle = $param['cycle']; + $preFundStock->start_time = $param['start_time']; + $preFundStock->end_time = $param['end_time']; + $preFundStock->sort = $param['sort'] ?? 0; + $preFundStock->interest_type = $param['interest_type']; + $preFundStock->cycle_type = $param['cycle_type']; + $preFundStock->phase_count = $param['phase_count'] ?? 1; + + $preFundStock->is_delete = PreFundStockModel::IS_DELETE_NO; + $preFundStock->open_status = PreFundStockModel::OPEN_STATUS_NO; + $preFundStock->create_time = date('Y-m-d H:i:s'); + $preFundStock->update_time = date('Y-m-d H:i:s'); + + $preFundStock->stock_info = $param['stock_info'] ?? ""; + $preFundStock->logo = $param['logo']; + $preFundStock->tag = $tag; + $preFundStock->remark = $param['remark']; + $preFundStock->product_file = json_encode($param['product_file']); + $preFundStock->current_manager = json_encode($param['current_manager']); + $preFundStockBool = $preFundStock->save(); + if (!$preFundStockBool) { + Db::rollback(); + return $this->toData('1', '新增基金失败'); + } + + // 基金历史走势 + $HistoryStock = new HistoryFundStockModel(); + $HistoryStock->stock_code = $param['stock_code']; + $HistoryStock->start_date = $param['start_date']; + $HistoryStock->end_date = $param['end_date']; + $HistoryStock->start_point = $param['start_point']; + $HistoryStock->end_point = $param['end_point']; + $HistoryStock->history_info = $this->autoHistory($param['start_date'], $param['end_date'], $param['start_point'], $param['end_point']); + $HistoryStockBool = $HistoryStock->save(); + if (!$HistoryStockBool) { + Db::rollback(); + return $this->toData('1', '新增基金走势失败'); + } + + Db::commit(); + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + Db::rollback(); + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 编辑 + public function edit($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '主键 无效'); + } + + $preFundStock = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); + if (empty($preFundStock)) { + return $this->toData('1', '主键 无效'); + } + + // 已中签或者已上市不支持修改 +// if ($preFundStock->open_status == PreFundStockModel::OPEN_STATUS_HAD) { +// return $this->toData('1', '已上市 不支持修改'); +// } + + // 基金类型 + if (empty($param['stock_type']) || !in_array($param['stock_type'], array_keys(PreFundStockModel::$stockTypeList))) { + return $this->toData('1', '基金类型 无效'); + } + + if ($preFundStock->had_get_price == 0) { + // 基金代码 + if (empty($param['stock_code']) || !is_string($param['stock_code'])) { + return $this->toData('1', '基金代码 无效'); + } + + // 基金名称 + if (empty($param['stock_name']) || !is_string($param['stock_name'])) { + return $this->toData('1', '基金代码 无效'); + } + + // 单股价格 + if (empty($param['min_price']) || !is_numeric($param['min_price']) || $param['min_price'] <= 0) { + return $this->toData('1', '最低申购金额 无效'); + } + + // 开始认购时间 + if (empty($param['start_time']) || !is_string($param['start_time'])) { + return $this->toData('1', '开始认购时间 无效'); + } + + // 收益率 两位小数 + if (empty($param['rate']) || !is_numeric($param['rate']) || $param['rate'] <= 0) { + return $this->toData('1', '基金收益率 无效'); + } + + // 基金周期 + if (empty($param['cycle']) || !is_numeric($param['cycle']) || $param['cycle'] <= 0) { + return $this->toData('1', '基金周期 无效'); + } + + // 返利类型 + if (empty($param['interest_type']) || !in_array($param['interest_type'], array_keys(PreFundStockModel::$interestTypeList))) { + return $this->toData('1', '返利类型 无效'); + } + + // 周期单位 + if (empty($param['cycle_type']) || !in_array($param['cycle_type'], array_keys(PreFundStockModel::$cycleTypeList))) { + return $this->toData('1', '返利类型 无效'); + } + } + + // 认购结束时间 + if (empty($param['end_time']) || !is_string($param['end_time'])) { + return $this->toData('1', '认购结束时间 无效'); + } + + // 基金logo + if (empty($param['logo']) || !is_string($param['logo'])) { + return $this->toData('1', '基金logo 无效'); + } + + // 基金标签 + $tag = ""; + if (!empty($param['tag']) && is_string($param['tag'])) { + $tag = $param['tag']; + } + + // 历史走势 起始日期 + if (empty($param['start_date']) || !is_string($param['start_date'])) { + return $this->toData('1', '历史走势 起始日期 无效'); + } + + // 历史走势 结束日期 + if (empty($param['end_date']) || !is_string($param['end_date'])) { + return $this->toData('1', '历史走势 结束日期 无效'); + } + + // 历史走势 起始值 + if (empty($param['start_point']) || !is_numeric($param['start_point'])) { + return $this->toData('1', '历史走势 起始值 无效'); + } + + // 历史走势 结束值 + if (empty($param['end_point']) || !is_numeric($param['end_point'])) { + return $this->toData('1', '历史走势 结束值 无效'); + } + + // 上市时间 要大于 认购结束时间 认购结束时间要大于 认购开始时间 + if (strtotime($param['end_time']) <= strtotime($param['start_time'])) { + return $this->toData('1', '认购结束时间 要晚于 认购开始时间'); + } + + // 1.0 判断基金号是否已经存在 + $preStock = PreFundStockModel::where('stock_code', $param['stock_code']) + ->where('id', '<>', $param['id']) + ->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); + if (!empty($preStock)) { + return $this->toData('1', '基金号已经存在'); + } + + Db::startTrans(); + // 编辑数据 + if ($preFundStock->had_get_price == 0) { + $UpdatePreFundStockArr['stock_code'] = $param['stock_code']; + $UpdatePreFundStockArr['stock_name'] = $param['stock_name']; + $UpdatePreFundStockArr['status'] = $param['status'] ?? 0; + $UpdatePreFundStockArr['min_price'] = $param['min_price']; + $UpdatePreFundStockArr['start_time'] = $param['start_time']; + $UpdatePreFundStockArr['rate'] = $param['rate']; + $UpdatePreFundStockArr['cycle'] = $param['cycle']; + $UpdatePreFundStockArr['interest_type'] = $param['interest_type']; + $UpdatePreFundStockArr['cycle_type'] = $param['cycle_type']; + $UpdatePreFundStockArr['phase_count'] = $param['phase_count'] ?? 1; + $UpdatePreFundStockArr['tape'] = $param['tape'] ?? 1; + } + + $UpdatePreFundStockArr['show_interest'] = $param['show_interest'] ?? 66; + $UpdatePreFundStockArr['end_time'] = $param['end_time']; + $UpdatePreFundStockArr['is_delete'] = PreFundStockModel::IS_DELETE_NO; + $UpdatePreFundStockArr['update_time'] = date('Y-m-d H:i:s'); + $UpdatePreFundStockArr['sort'] = $param['sort'] ?? 0; + + $UpdatePreFundStockArr['stock_info'] = $param['stock_info'] ?? ""; + $UpdatePreFundStockArr['logo'] = $param['logo']; + $UpdatePreFundStockArr['tag'] = $tag; + $UpdatePreFundStockArr['remark'] = $param['remark']; + $UpdatePreFundStockArr['product_file'] = json_encode($param['product_file']); + $UpdatePreFundStockArr['current_manager'] = json_encode($param['current_manager']); + $UpdatePreFundStockBool = PreFundStockModel::where('id', $param['id'])->update($UpdatePreFundStockArr); + if (!$UpdatePreFundStockBool) { + Db::rollback(); + return $this->toData('1', '编辑基金失败'); + } + + // 基金历史走势 + $HistoryStockArr['stock_code'] = $param['stock_code']; + $HistoryStockArr['start_date'] = $param['start_date']; + $HistoryStockArr['end_date'] = $param['end_date']; + $HistoryStockArr['start_point'] = $param['start_point']; + $HistoryStockArr['end_point'] = $param['end_point']; + $HistoryStockArr['history_info'] = $this->autoHistory($param['start_date'], $param['end_date'], $param['start_point'], $param['end_point']); + $HistoryStock = HistoryFundStockModel::where('stock_code', $param['stock_code'])->find(); + if (empty($HistoryStock)) { + HistoryFundStockModel::where('stock_code', $preFundStock->stock_code)->delete(); + $HistoryStockBool = HistoryFundStockModel::create($HistoryStockArr); + } else { + $HistoryStockBool = HistoryFundStockModel::where('stock_code', $param['stock_code'])->update($HistoryStockArr); + } + if (!$HistoryStockBool) { + Db::rollback(); + return $this->toData('1', '编辑基金走势失败'); + } + + Db::commit(); + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + Db::rollback(); + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 上市 + public function open($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '主键 无效'); + } + +// $isReal = 1; +// if (isset($param['is_real']) && is_numeric($param['is_real']) && $param['is_real'] == '2') { +// $isReal = 2; +// } + + $preFundStock = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); + if (empty($preFundStock)) { + return $this->toData('1', '主键 无效'); + } + + // 判断是否签名 +// if ($preFundStock->sign_status != PreFundStockModel::SIGN_STATUS_DONE) { +// return $this->toData('1', '还未签名'); +// } + +// if ($preFundStock->open_status != PreFundStockModel::OPEN_STATUS_NO) { +// return $this->toData('1', '无法操作'); +// } + + // 修改基金状态 + $num = PreFundStockModel::where('id', $preFundStock->id)->update(['open_status' => PreFundStockModel::OPEN_STATUS_HAD, + 'open_time' => date('Y-m-d H:i:s'), + 'update_time' => date('Y-m-d H:i:s')]); + + if ($num <= 0) { + return $this->toData('1', '基金状态修改失败-上市'); + } + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + Log::error("基金上市失败 " . $exception->getMessage()); + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 退市 + public function close($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '主键 无效'); + } + + $preFundStock = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); + if (empty($preFundStock)) { + return $this->toData('1', '主键 无效'); + } + + // + if ($preFundStock->open_status != PreFundStockModel::OPEN_STATUS_HAD) { + return $this->toData('1', '上市中 无法操作'); + } + + // 修改基金状态 + $num = PreFundStockModel::where('id', $preFundStock->id)->update(['open_status' => PreFundStockModel::OPEN_STATUS_OUT, + 'close_time' => date('Y-m-d H:i:s'), + 'update_time' => date('Y-m-d H:i:s')]); + + if ($num <= 0) { + return $this->toData('1', '基金状态修改失败-退市'); + } + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + Log::error("基金退市失败 " . $exception->getMessage()); + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 删除 + public function del($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '主键 无效'); + } + + $preFundStock = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); + if (empty($preFundStock)) { + return $this->toData('1', '主键 无效'); + } + + // + if ($preFundStock->open_status != PreFundStockModel::OPEN_STATUS_HAD) { + return $this->toData('1', '上市中 无法操作'); + } + + // 修改删除状态 + $num = PreFundStockModel::where('id', $preFundStock->id)->update([ + 'is_delete' => PreFundStockModel::IS_DELETE_YES, + 'update_time' => date('Y-m-d H:i:s')]); + + if ($num <= 0) { + return $this->toData('1', '基金删除失败'); + } + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + Log::error("基金删除失败 " . $exception->getMessage()); + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + private function autoHistory($startDate, $endDate, $startPoint, $endPoint) + { + $startDateOjb = new DateTime($startDate); + $endDateOjb = new DateTime($endDate); + $endDateOjb->modify('+1 day'); //DateTime 取两个日期中间日期,不含结束日期 + $period = new DatePeriod($startDateOjb, new DateInterval('P1D'), $endDateOjb); + $interval = $startDateOjb->diff($endDateOjb); + $daysCount = $interval->format('%a'); + $numberArr = $this->autoNumber($startPoint, $endPoint, $daysCount); + $start = 0; + foreach ($period as $k => $date) { + $dates[$date->format("Y-m-d")] = number_format($start += $numberArr[$k], 2, '.', ''); + } + + return json_encode($dates); + } + + private function autoNumber($startPoint, $endPoint, $count) + { + $rand = round(($endPoint - $startPoint) / $count, 2); + $randomNumbers = array(); + $randomNumbers[] = $startPoint; + for ($i = 0; $i < $count - 2; $i++) { + $temp = bcmul(rand(1, 10) > 4 ? 1 : -1, (rand(1, 10) > 5 ? rand(1, 5) : rand(4, 8)) / 100, 2); + // 生成随机的增减值 + $randomChange = bcmul(rand(1, 10) > 4 ? 1 : -1, rand(1, 10) > 5 ? rand(1, 10) > 3 ? $rand * 2 : $rand * 4 : $rand * 3, 2); + $randomChange = bcadd($randomChange, $temp, 2); + // 将当前值添加到数组中 + $randomNumbers[] = round($randomChange, 2); + } + + $end = round($endPoint - array_sum($randomNumbers), 2); + if (abs($end) > 30) { + return $this->autoNumber($startPoint, $endPoint, $count); + } else { + $randomNumbers[] = $end; + return $randomNumbers; + } + } + + public function interest() + { + try { +// $interestSwitch = env(); +// if (!$interestSwitch)return; + + $today = date("Y-m-d"); + $interestList = UserStockFundInterestReceiptModel::where("return_date", $today)->where('status', UserStockFundInterestReceiptModel::STATUS_ONE)->select(); + if (count($interestList) == 0) { + trace('fund_interest count=0 基金没有需要处理的返息单-完成', 'error'); + return json(["SUCCESS"]); + } + + foreach ($interestList as $interestV) { + try { + // 单个股票 开始事务 + Db::startTrans(); + $vId = $interestV->id; + //用户基金账户加钱 + $beforeAmount = UserStockFundModel::where('stock_id', 'USD')->where('user_id', $interestV->user_id)->value('usable_num'); + if (empty($beforeAmount)) { + Db::rollback(); + trace("基金返息失败0 返息单ID=$vId", 'error'); + return json(["基金返息失败0"]); + } + + $addNum = bcadd($interestV->capital, $interestV->interest, 18);//本金+利息 + $addBool = UserStockFundModel::where('user_id', $interestV->user_id)->where('stock_id', 'USD')->inc('usable_num', $addNum)->update(['update_time' => date('Y-m-d H:i:s')]); + if (!$addBool) { + Db::rollback(); + trace("基金返息失败1 返息单ID=$vId", 'error'); + return json(["基金返息失败1"]); + } + + // 新增用户基金账户流水 + // 生成流水 + $userStockLog = new UserStockFundLogModel(); + $userStockLog->user_id = $interestV->user_id; + $userStockLog->change_type = 19; + $userStockLog->stock_id = 'USD'; + $userStockLog->before_num = $beforeAmount; + $userStockLog->change_num = $addNum; + $userStockLog->order_id = $interestV->order_no; + $userStockLog->create_time = date('Y-m-d H:i:s'); + $userStockLog->update_time = date('Y-m-d H:i:s'); + $updateNum2 = $userStockLog->save(); + if ($updateNum2 <= 0) { + Db::rollback(); + trace("基金返息失败2 返息单ID=$vId", 'error'); + return json(["基金返息失败2"]); + } + + //修改返息单状态 + $interestReceiptUpdateBool = UserStockFundInterestReceiptModel::where('id', $interestV->id)->update(['status' => UserStockFundInterestReceiptModel::STATUS_TWO, 'update_time' => date('Y-m-d H:i:s')]); + if (!$interestReceiptUpdateBool) { + Db::rollback(); + trace("基金返息失败3 返息单ID=$vId", 'error'); + return json(["基金返息失败3"]); + } + + //修改订单状态 + $order = UserFundPreStockOrderModel::where('id', $interestV->order_id)->find(); + if (empty($order)) { + Db::rollback(); + trace("基金返息失败4 返息单ID=$vId", 'error'); + return json(["基金返息失败4"]); + } + + if ($order->phase_count == $interestV->phase_time) { + $orderStatus = UserFundPreStockOrderModel::STATUS_THREE;//已结束 + } else { + $orderStatus = UserFundPreStockOrderModel::STATUS_TWO;//进行中 + } + $order->status = $orderStatus; + $order->save(); + // 提交事务 + Db::commit(); + } catch (\Exception $exception) { + Db::rollback(); + trace("基金返息息失败5-exception " . $exception->getMessage(), 'error'); + return json(["基金返息失败5-exception"]); + } + } + + trace('基金返息-完成', 'error'); + return json(["SUCCESS"]); + } catch (\Exception $exception) { + trace("基金返息失败6-exception " . $exception->getMessage(), 'error'); + return json([$exception->getMessage()]); + } + } + + public function referStockAdd($param) + { + try { + $bool = PreFundStockReferModel::insert(['name' => $param['name'], 'year' => $param['year'], 'rate' => $param['rate']]); + if (!$bool) { + return $this->toData('1', '基金状态修改失败-退市'); + } + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + public function referStockDel($param) + { + try { + $bool = PreFundStockReferModel::where('id', $param['id'])->delete(); + if (!$bool) { + return $this->toData('1', '基金状态修改失败-退市'); + } + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/ServiceService.php b/app/admin/service/setting/ServiceService.php new file mode 100644 index 0000000..d4fe071 --- /dev/null +++ b/app/admin/service/setting/ServiceService.php @@ -0,0 +1,112 @@ +select(); + if (!$list->isEmpty()) { + $rows = $list->toArray(); + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows), 'extend' => ['type_list' => ServiceSettingModel::$typeList]]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + public function add($param) + { + try { + if (empty($param['type']) || !in_array($param['type'], array_keys(ServiceSettingModel::$typeList))) { + return $this->toData('1', '类型 无效', []); + } + + if (empty($param['header_photo']) || !is_string($param['header_photo'])) { + return $this->toData('1', '头像图片地址无效', []); + } + + if (empty($param['server_name']) || !is_string($param['server_name'])) { + return $this->toData('1', '客服名称无效', []); + } + + if (!empty($param['server_link']) && !is_string($param['server_link'])) { + return $this->toData('1', '类型内容 无效', []); + } + + $service = new ServiceSettingModel; + $service->header_photo = $param['header_photo']; + $service->type = $param['type']; + $service->server_link = $param['server_link'] ?? ''; + $service->server_name = $param['server_name']; + $service->save(); + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + public function edit($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '目标不存在', []); + } + $service = ServiceSettingModel::where('id', $param['id'])->find(); + if (empty($service)) { + return $this->toData('1', '目标不存在', []); + } + + if (empty($param['type']) || !in_array($param['type'], array_keys(ServiceSettingModel::$typeList))) { + return $this->toData('1', '类型 无效', []); + } + + if (empty($param['header_photo']) || !is_string($param['header_photo'])) { + return $this->toData('1', '头像图片地址无效', []); + } + + if (empty($param['server_name']) || !is_string($param['server_name'])) { + return $this->toData('1', '客服名称无效', []); + } + + if (!empty($param['server_link']) && !is_string($param['server_link'])) { + return $this->toData('1', '类型内容 无效', []); + } + $service->type = $param['type']; + $service->header_photo = $param['header_photo']; + $service->server_link = $param['server_link'] ?? ''; + $service->server_name = $param['server_name']; + $service->save(); + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } + + + public function del($param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '参错错误'); + } + + $lang = ServiceSettingModel::where('id', $param['id'])->find(); + if (empty($lang)) { + return $this->toData('1', '目标不存在'); + } + + $lang->delete(); + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/StockIndexService.php b/app/admin/service/setting/StockIndexService.php new file mode 100644 index 0000000..d444a1c --- /dev/null +++ b/app/admin/service/setting/StockIndexService.php @@ -0,0 +1,65 @@ +order('id', 'desc')->select(); + $rows = []; + if(!$list->isEmpty()){ + $rows = $list->toArray(); + } + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => count($rows)]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', []); + } + + } + + public function update($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '参数错误1', []); + } + + if(!isset($param['sort']) || !is_numeric($param['sort'])){ + return $this->toData('1', '参数错误2', []); + } + + if(empty($param['status']) || !in_array($param['status'], [1,2])){ + return $this->toData('1', '参数错误3', []); + } + + $stockIndex = StockIndexModel::where('id', $param['id'])->find(); + if(empty($stockIndex)){ + return $this->toData('1', '目标不存在', []); + } + + $stockIndex->sort = ceil($param['sort']); + $stockIndex->status = ceil($param['status']); + $stockIndex->update_time = date('Y-m-d H:i:s'); + $stockIndex->save(); + + // 通知go + $bool = $this->sendStockIndexToGo($stockIndex->code, $stockIndex->country, $stockIndex->sort, $stockIndex->status); + if(!$bool){ + return $this->toData('1', '通知行情失败 请重新设置数据', []); + } + return $this->toData('0', 'SUCCESS'); + + + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/admin/service/setting/StockMarketService.php b/app/admin/service/setting/StockMarketService.php new file mode 100644 index 0000000..40c6eab --- /dev/null +++ b/app/admin/service/setting/StockMarketService.php @@ -0,0 +1,534 @@ +select(); + $rows = []; + if(!$list->isEmpty()){ + $rows = $list->toArray(); + } + + return $this->toData('0','SUCCESS', ['total' => count($rows), 'list' => $rows, 'extent' => [ + 'stock_market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, + 'trade_day_type' => StockMarketModel::TRADE_DAY_TYPE, + ]]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + // 新增 + public function add($param) + { + try { + $stockMarketTypeArr = StockMarketModel::STOCK_MARKET_TYPE; + $tradeDayTypeArr = StockMarketModel::TRADE_DAY_TYPE; + $stockMarketTypeKeys = array_keys($stockMarketTypeArr); + $tradeDayTypeKeys = array_keys($tradeDayTypeArr); + if(empty($param['stock_market_type']) || !in_array($param['stock_market_type'], $stockMarketTypeKeys)){ + return $this->toData('1', '股票市场类型无效', []); + } + + // 判断是否已经存在 + $stockM = StockMarketModel::where('stock_market_type', $param['stock_market_type'])->find(); + if($stockM){ + return $this->toData('1', '股票市场类型已经存在', []); + } + + $amOpenTime = '00:00'; + $amCloseTime = '00:00'; + $pmOpenTime = '00:00'; + $pmCloseTime = '00:00'; + $num = 0; + if(isset($param['am_open_time']) && is_string($param['am_open_time'])){ + $amOpenTimestamp = strtotime($param['am_open_time']); + if($amOpenTimestamp !== false && date('H:i', $amOpenTimestamp) === $param['am_open_time']){ + $amOpenTime = $param['am_open_time']; + $num++; + } + } + + if(isset($param['am_close_time']) && is_string($param['am_close_time'])){ + $amCloseTimestamp = strtotime($param['am_close_time']); + if($amCloseTimestamp !== false && date('H:i', $amCloseTimestamp) === $param['am_close_time']){ + $amCloseTime = $param['am_close_time']; + $num++; + } + } + + if(isset($param['pm_open_time']) && is_string($param['pm_open_time'])){ + $pmOpenTimestamp = strtotime($param['pm_open_time']); + if($pmOpenTimestamp !== false && date('H:i', $pmOpenTimestamp) === $param['pm_open_time']){ + $pmOpenTime = $param['pm_open_time']; + $num++; + } + } + + if(isset($param['pm_close_time']) && is_string($param['pm_close_time'])){ + $pmCloseTimestamp = strtotime($param['pm_close_time']); + if($pmCloseTimestamp !== false && date('H:i', $pmCloseTimestamp) === $param['pm_close_time']){ + $pmCloseTime = $param['pm_close_time']; + $num++; + } + } + + + if(empty($param['status']) || !in_array($param['status'], [StockMarketModel::STATUS_NO, StockMarketModel::STATUS_OFF])){ + return $this->toData('1', '状态类型无效', []); + } + + // 如果是开启状态 必须设置开盘时间 + if($param['status'] == StockMarketModel::STATUS_NO && $num < 4){ + return $this->toData('1', '需要设置开盘时间', []); + } + + // 货币单位 + if(empty($param['unit']) || !is_string($param['unit']) || strlen($param['unit']) > 10){ + return $this->toData('1', '货币单位无效', []); + } + + // 货币符号 + if(empty($param['symbol']) || !is_string($param['symbol']) || strlen($param['symbol']) > 10){ + return $this->toData('1', '货币符号无效', []); + } + + // 兑换汇率 + if(empty($param['rate']) || !is_numeric($param['rate']) || strlen($param['rate']) > 200){ + return $this->toData('1', '兑换汇率无效', []); + } + + // 如果是开启状态必须设置 交易日限制 如果是关闭状态 + if($param['status'] == StockMarketModel::STATUS_NO){ + if(empty($param['trade_day_type']) || !in_array($param['trade_day_type'], $tradeDayTypeKeys)){ + return $this->toData('1', '交易日限制无效', []); + } + $tradeDayType = $param['trade_day_type']; + }else{ + if(empty($param['trade_day_type']) || !in_array($param['trade_day_type'], $tradeDayTypeKeys)){ + $tradeDayType = 0; + } else{ + $tradeDayType = $param['trade_day_type']; + } + } + + // 设置股票杠杆 + $leverStatus = StockMarketModel::LEVER_STATUS_OFF; + $stockMin = 0; + $leverMin = 1; + $leverMax = 1; + if(!empty($param['lever_status']) && is_numeric($param['lever_status']) && $param['lever_status'] == StockMarketModel::LEVER_STATUS_ON){ + $leverStatus = $param['lever_status']; + if(empty($param['stock_min']) || !is_numeric($param['stock_min']) || $param['stock_min'] <=0){ + return $this->toData('1', '杠杆最小使用股数无效', []); + } + + if(empty($param['lever_min']) || !is_numeric($param['lever_min']) || $param['lever_min'] <=0){ + return $this->toData('1', '最小杠杆无效', []); + } + + if(empty($param['lever_max']) || !is_numeric($param['lever_max']) || $param['lever_max'] <=0 || $param['lever_max'] < $param['lever_min']){ + return $this->toData('1', '最大杠杆无效', []); + } + + $stockMin = ceil($param['stock_min']); + $leverMin = ceil($param['lever_min']); + $leverMax = ceil($param['lever_max']); + } + + + $stockMarket = new StockMarketModel; + $stockMarket->stock_market_type = $param['stock_market_type']; + $stockMarket->status = $param['status']; + $stockMarket->symbol = $param['symbol']; + $stockMarket->unit = $param['unit']; + $stockMarket->rate = $param['rate']; + // 开盘时间 + $stockMarket->am_open_time = $amOpenTime; + $stockMarket->am_close_time = $amCloseTime; + $stockMarket->pm_open_time = $pmOpenTime; + $stockMarket->pm_close_time = $pmCloseTime; + $stockMarket->trade_day_type = $tradeDayType; + $stockMarket->create_time = date('Y-m-d H:i:s'); + $stockMarket->update_time = date('Y-m-d H:i:s'); + + $stockMarket->stock_min = $stockMin; + $stockMarket->lever_min = $leverMin; + $stockMarket->lever_max = $leverMax; + $stockMarket->lever_status = $leverStatus; + + $stockMarket->save(); + + // 缓存 + $list_key="STOCK_MARKET:LIST:" .$stockMarket->stock_market_type; + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'id'=>$stockMarket->id, + 'stock_market_type'=>$stockMarket->stock_market_type, + 'trade_day_type'=>$stockMarket->trade_day_type, + 'unit'=>$stockMarket->unit, + 'rate'=>$stockMarket->rate, + 'symbol'=>$stockMarket->symbol, + 'status'=>$stockMarket->status, + 'am_open_time'=>$stockMarket->am_open_time, + 'am_close_time'=>$stockMarket->am_close_time, + 'pm_open_time'=>$stockMarket->pm_open_time, + 'pm_close_time'=>$stockMarket->pm_close_time, + + 'lever_status' => $leverStatus, + 'stock_min' => $stockMin, + 'lever_min' => $leverMin, + 'lever_max' => $leverMax, + + ]); + + return $this->toData('0','SUCCESS'); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage(),$exception->getLine()]); + } + } + + public function edit($param) + { + try { + if(empty($param['id']) || !is_numeric($param['id'])){ + return $this->toData('1', '主键无效', []); + } + + $stockMarket = StockMarketModel::where('id', $param['id'])->find(); + if(empty($stockMarket)){ + return $this->toData('1', '主键无效', []); + } + + $tradeDayTypeArr = StockMarketModel::TRADE_DAY_TYPE; + $tradeDayTypeKeys = array_keys($tradeDayTypeArr); + + + // 状态 + if(empty($param['status']) || !in_array($param['status'], [StockMarketModel::STATUS_NO, StockMarketModel::STATUS_OFF])){ + return $this->toData('1', '状态类型无效', []); + } + + $amOpenTime = '00:00'; + $amCloseTime = '00:00'; + $pmOpenTime = '00:00'; + $pmCloseTime = '00:00'; + $num = 0; + if(isset($param['am_open_time']) && is_string($param['am_open_time'])){ + $amOpenTimestamp = strtotime($param['am_open_time']); + if($amOpenTimestamp !== false && date('H:i', $amOpenTimestamp) === $param['am_open_time']){ + $amOpenTime = $param['am_open_time']; + $num++; + } + } + + if(isset($param['am_close_time']) && is_string($param['am_close_time'])){ + $amCloseTimestamp = strtotime($param['am_close_time']); + if($amCloseTimestamp !== false && date('H:i', $amCloseTimestamp) === $param['am_close_time']){ + $amCloseTime = $param['am_close_time']; + $num++; + } + } + + if(isset($param['pm_open_time']) && is_string($param['pm_open_time'])){ + $pmOpenTimestamp = strtotime($param['pm_open_time']); + if($pmOpenTimestamp !== false && date('H:i', $pmOpenTimestamp) === $param['pm_open_time']){ + $pmOpenTime = $param['pm_open_time']; + $num++; + } + } + + if(isset($param['pm_close_time']) && is_string($param['pm_close_time'])){ + $pmCloseTimestamp = strtotime($param['pm_close_time']); + if($pmCloseTimestamp !== false && date('H:i', $pmCloseTimestamp) === $param['pm_close_time']){ + $pmCloseTime = $param['pm_close_time']; + $num++; + } + } + + // 如果是开启状态 必须设置开盘时间 + if($param['status'] == StockMarketModel::STATUS_NO && $num < 4){ + return $this->toData('1', '需要设置开盘时间', []); + } + + + // 货币单位 + if(empty($param['unit']) || !is_string($param['unit']) || strlen($param['unit']) > 10){ + return $this->toData('1', '货币单位无效', []); + } + + // 货币符号 + if(empty($param['symbol']) || !is_string($param['symbol']) || strlen($param['symbol']) > 10){ + return $this->toData('1', '货币符号无效', []); + } + + // 兑换汇率 + if(empty($param['rate']) || !is_numeric($param['rate']) || strlen($param['rate']) > 200){ + return $this->toData('1', '兑换汇率无效', []); + } + + $tradeDayType = $stockMarket->trade_day_type; + + // 只有在没有设置过的情况下可以设置 设置之后不能修改 + if($tradeDayType == 0){ + if($param['status'] == StockMarketModel::STATUS_NO){ + // 如果是开启状态 必须设置 + if(empty($param['trade_day_type']) || !in_array($param['trade_day_type'], $tradeDayTypeKeys)){ + return $this->toData('1', '交易日限制无效', []); + } + $tradeDayType = $param['trade_day_type']; + }else{ + // 关闭状态 可以不设置 + if(!empty($param['trade_day_type']) && in_array($param['trade_day_type'], $tradeDayTypeKeys)){ + $tradeDayType = $param['trade_day_type']; + } else{ + $tradeDayType = 0; + } + } + } + + // 设置股票杠杆 + $leverStatus = StockMarketModel::LEVER_STATUS_OFF; + $stockMin = 0; + $leverMin = 1; + $leverMax = 1; + if(!empty($param['lever_status']) && is_numeric($param['lever_status']) && $param['lever_status'] == StockMarketModel::LEVER_STATUS_ON){ + $leverStatus = $param['lever_status']; + if(empty($param['stock_min']) || !is_numeric($param['stock_min']) || $param['stock_min'] <=0){ + return $this->toData('1', '杠杆最小使用股数无效', []); + } + + if(empty($param['lever_min']) || !is_numeric($param['lever_min']) || $param['lever_min'] <=0){ + return $this->toData('1', '最小杠杆无效', []); + } + + if(empty($param['lever_max']) || !is_numeric($param['lever_max']) || $param['lever_max'] <=0 || $param['lever_max'] < $param['lever_min']){ + return $this->toData('1', '最大杠杆无效', []); + } + + + + } + $stockMin = ceil($param['stock_min']); + $leverMin = ceil($param['lever_min']); + $leverMax = ceil($param['lever_max']); + + + $stockMarket->status = $param['status']; + $stockMarket->trade_day_type = $tradeDayType; + $stockMarket->symbol = $param['symbol']; + $stockMarket->unit = $param['unit']; + $stockMarket->rate = $param['rate']; + $stockMarket->am_open_time = $amOpenTime; + $stockMarket->am_close_time = $amCloseTime; + $stockMarket->pm_open_time = $pmOpenTime; + $stockMarket->pm_close_time = $pmCloseTime; + $stockMarket->trade_day_type = $tradeDayType; + $stockMarket->update_time = date('Y-m-d H:i:s'); + + $stockMarket->stock_min = $stockMin; + $stockMarket->lever_min = $leverMin; + $stockMarket->lever_max = $leverMax; + $stockMarket->lever_status = $leverStatus; + + $stockMarket->save(); + + // 缓存 + $list_key="STOCK_MARKET:LIST:" .$stockMarket->stock_market_type; + $redis = $this->getRedis(); + $redis->del($list_key); + $redis->hMset($list_key, [ + 'id'=>$stockMarket->id, + 'stock_market_type'=>$stockMarket->stock_market_type, + 'trade_day_type'=>$stockMarket->trade_day_type, + 'status'=>$stockMarket->status, + 'symbol'=>$stockMarket->symbol, + 'unit'=>$stockMarket->unit, + 'rate'=>$stockMarket->rate, + 'am_open_time'=>$stockMarket->am_open_time, + 'am_close_time'=>$stockMarket->am_close_time, + 'pm_open_time'=>$stockMarket->pm_open_time, + 'pm_close_time'=>$stockMarket->pm_close_time, + + 'lever_status' => $leverStatus, + 'stock_min' => $stockMin, + 'lever_min' => $leverMin, + 'lever_max' => $leverMax, + ]); + $arr=$redis->hGetAll($list_key); + + return $this->toData('0','SUCCESS',$arr); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + + // 股票筛选 根据股票号 股票市场 模糊搜索股票数据 + public function searchStock($param) + { + try { + $marketTypeList = StockMarketModel::STOCK_MARKET_TYPE; + if(empty($param['market_type']) || !in_array($param['market_type'], array_keys($marketTypeList))){ + return $this->toData('1', '股票市场无效', []); + } + + $where = []; + if(empty($param['page']) || !is_numeric($param['page']) || ceil($param['page']) != $param['page'] || $param['page'] <= 0){ + return $this->toData('1', '分页参数无效', []); + } + + if(empty($param['limit']) || !is_numeric($param['limit']) || ceil($param['limit']) != $param['limit'] || $param['limit'] <= 0){ + return $this->toData('1', '分页参数无效', []); + } + + if(!empty($param['stock_code']) && is_string($param['stock_code'])){ + $where[] = ['stock_code', 'like', '%'.$param['stock_code']]; + } + + switch ($param['market_type']) + { + // 美股 + case StockMarketModel::STOCK_MARKET_USA: + $stockList = StockListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_YNG: + $stockList = StockIdnListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockIdnListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_MG: + $stockList = StockMysListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockMysListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_TG: + $stockList = StockThaListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockThaListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_IN: + $stockList = StockInListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockInListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_HK: + $stockList = StockHkdListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockHkdListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_UK: + $stockList = StockGBXListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockGBXListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_FUR: + $stockList = StockFurListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockFurListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_EUR: + $stockList = StockEurListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockEurListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_BRL: + $stockList = StockBrlListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockBrlListModel::where($where)->count(); + break; + case StockMarketModel::STOCK_MARKET_JP: + $stockList = StockJpListModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockJpListModel::where($where)->count(); + break; + default: + return $this->toData('1', '股票市场无效', []); + } + + $rows = []; + if(!$stockList->isEmpty()){ + $rows = $stockList->toArray(); + } + + return $this->toData('0','SUCCESS', ['total' => $total, 'list' => $rows, 'extent' => [ + 'stock_market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, + 'trade_day_type' => StockMarketModel::TRADE_DAY_TYPE, + ]]); + }catch (\Exception $exception){ + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 根据股票市场 股票主键 查询股票 + public function searchStockById($param) + { + $marketTypeList = StockMarketModel::STOCK_MARKET_TYPE; + if(empty($param['market_type']) || !in_array($param['market_type'], array_keys($marketTypeList))){ + return []; + } + + if(empty($param['stock_id']) || !is_numeric($param['stock_id'])){ + return []; + } + + + switch ($param['market_type']) + { + // 美股 + case StockMarketModel::STOCK_MARKET_USA: + $stock = StockListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_YNG: + $stock = StockIdnListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_MG: + $stock = StockMysListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_TG: + $stock = StockThaListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_IN: + $stock = StockInListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_HK: + $stock = StockHkdListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_UK: + $stock = StockGBXListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_FUR: + $stock = StockFurListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_EUR: + $stock = StockEurListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_BRL: + $stock = StockBrlListModel::where('id', $param['stock_id'])->find(); + break; + case StockMarketModel::STOCK_MARKET_JP: + $stock = StockJpListModel::where('id', $param['stock_id'])->find(); + break; + default: + return []; + } + + if(empty($stock)){ + return []; + } + return $stock->toArray(); + } +} \ No newline at end of file diff --git a/app/admin/service/setting/StockPriceSettingService.php b/app/admin/service/setting/StockPriceSettingService.php new file mode 100644 index 0000000..ae21df0 --- /dev/null +++ b/app/admin/service/setting/StockPriceSettingService.php @@ -0,0 +1,227 @@ +toData('1', '分页参数无效', []); + } + + if (empty($param['limit']) || !is_numeric($param['limit']) || ceil($param['limit']) != $param['limit'] || $param['limit'] <= 0) { + return $this->toData('1', '分页参数无效', []); + } + + $list = StockPricesSettingModel::order('id', 'desc')->page($param['page'], $param['limit'])->select(); + $total = StockPricesSettingModel::where('id', '>', 0)->count(); + + + $rows = []; + // 股票市场货币符号 + $marketSymbol = StockMarketModel::where('id', '>', 0)->column('symbol', 'stock_market_type'); + if (!$list->isEmpty()) { + $rows = $list->toArray(); + foreach ($list as $key => $item) { + $stock = (new StockMarketService)->searchStockById(['market_type' => $item->market_type, 'stock_id' => $item->stock_id]); + $rows[$key]['stock_code'] = $stock['stock_code'] ?? '-'; + $rows[$key]['stock_name'] = $stock['stock_name'] ?? '-'; + $rows[$key]['symbol'] = $marketSymbol[$item->market_type] ?? '-'; + $rows[$key]['price'] = rtrim(rtrim($item['price'], '0'), '.'); + } + } + + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total, 'extent' => [ + 'market_type_list' => StockMarketModel::STOCK_MARKET_TYPE, + 'market_symbol' => $marketSymbol + ]]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 新增 + public function add($param) + { + try { + $marketTypeList = StockMarketModel::STOCK_MARKET_TYPE; + // 股票市场 + if (empty($param['market_type']) || !in_array($param['market_type'], array_keys($marketTypeList))) { + return $this->toData('1', '市场类型无效', []); + } + + // 股票主键 + if (empty($param['stock_id']) || !is_numeric($param['stock_id'])) { + return $this->toData('1', '股票无效', []); + } + + $stock = (new StockMarketService)->searchStockById(['market_type' => $param['market_type'], 'stock_id' => $param['stock_id']]); + if (empty($stock)) { + return $this->toData('1', '股票无效', []); + } + + // 盘前状态 + if (empty($param['status']) || !in_array($param['status'], [StockPricesSettingModel::STATUS_ON, StockPricesSettingModel::STATUS_OFF])) { + return $this->toData('1', '状态无效', []); + } + + if (empty($param['price']) || !is_numeric($param['price'])) { + return $this->toData('1', '价格无效', []); + } + + // 判断市场是否已经存在 + $count = StockPricesSettingModel::where('market_type', $param['market_type'])->where('stock_id', $param['stock_id'])->count(); + if ($count > 0) { + return $this->toData('1', '已存在相同配置', []); + } + + // 添加缓存 + $key = 'STOCK_PRICES:' . $param['market_type'] . ':' . $stock['stock_code']; + $redis = $this->getRedis(); + $redis->del($key); + $bool = $redis->hMSet($key, [ + 'market_type' => $param['market_type'], + 'stock_id' => $param['stock_id'], + 'stock_code' => $stock['stock_code'], + 'status' => $param['status'], + 'price' => $param['price'], + ]); + + if ($bool) { + $stockPriceSetting = new StockPricesSettingModel; + $stockPriceSetting->market_type = $param['market_type']; + $stockPriceSetting->stock_id = $param['stock_id']; + $stockPriceSetting->status = $param['status']; + $stockPriceSetting->price = $param['price']; + $stockPriceSetting->create_time = date('Y-m-d H:i:s'); + $stockPriceSetting->update_time = date('Y-m-d H:i:s'); + $stockPriceSetting->save(); + } + + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 编辑 + public function edit($param) + { + try { + $marketTypeList = StockMarketModel::STOCK_MARKET_TYPE; + // 目标 + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '目标不存在', []); + } + + $stockPriceSetting = StockPricesSettingModel::where('id', $param['id'])->find(); + if (empty($stockPriceSetting)) { + return $this->toData('1', '目标不存在', []); + } + + // 股票市场 + if (empty($param['market_type']) || !in_array($param['market_type'], array_keys($marketTypeList))) { + return $this->toData('1', '市场类型无效', []); + } + + // 股票主键 + if (empty($param['stock_id']) || !is_numeric($param['stock_id'])) { + return $this->toData('1', '股票无效', []); + } + + $stock = (new StockMarketService)->searchStockById(['market_type' => $param['market_type'], 'stock_id' => $param['stock_id']]); + if (empty($stock)) { + return $this->toData('1', '股票无效', []); + } + + // 盘前状态 + if (empty($param['status']) || !in_array($param['status'], [StockPricesSettingModel::STATUS_ON, StockPricesSettingModel::STATUS_OFF])) { + return $this->toData('1', '盘前状态无效', []); + } + + if (empty($param['price']) || !is_numeric($param['price'])) { + return $this->toData('1', '价格无效', []); + } + + // 判断市场是否已经存在 + $count = StockPricesSettingModel::where('market_type', $param['market_type'])->where('stock_id', $param['stock_id']) + ->where('id', '<>', $param['id']) + ->count(); + + if ($count > 0) { + return $this->toData('1', '已存在相同配置', []); + } + + // 添加缓存 + $key = 'STOCK_PRICES:' . $param['market_type'] . ':' . $stock['stock_code']; + $redis = $this->getRedis(); + $redis->del($key); + $bool = $redis->hMSet($key, [ + 'market_type' => $param['market_type'], + 'stock_id' => $param['stock_id'], + 'stock_code' => $stock['stock_code'], + 'status' => $param['status'], + 'price' => $param['price'], + ]); + + if ($bool) { + $stockPriceSetting->market_type = $param['market_type']; + $stockPriceSetting->stock_id = $param['stock_id']; + $stockPriceSetting->status = $param['status']; + $stockPriceSetting->price = $param['price']; + $stockPriceSetting->update_time = date('Y-m-d H:i:s'); + $stockPriceSetting->save(); + } + + return $this->toData('0', 'SUCCESS', [$stockPriceSetting->price]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + + // 删除 + public function del($param) + { + try { + // 目标 + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', '目标不存在', []); + } + + $stockPriceSetting = StockPricesSettingModel::where('id', $param['id'])->find(); + if (empty($stockPriceSetting)) { + return $this->toData('1', '目标不存在', []); + } + + if ($stockPriceSetting->status == StockPricesSettingModel::STATUS_ON) { + return $this->toData('1', '配置开启中 不可删除', []); + } + + $stock = (new StockMarketService)->searchStockById(['market_type' => $stockPriceSetting->market_type, 'stock_id' => $stockPriceSetting->stock_id]); + if (empty($stock)) { + return $this->toData('1', '股票无效', []); + } + + $key = 'STOCK_PRICES:' . $stockPriceSetting->market_type . ':' . $stock['stock_code']; + $redis = $this->getRedis(); + $num = $redis->del($key); + if ($num > 0) { + $stockPriceSetting->delete(); + } + + return $this->toData('0', 'SUCCESS'); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', [$exception->getMessage()]); + } + } + +} \ No newline at end of file diff --git a/app/admin/service/setting/StockService.php b/app/admin/service/setting/StockService.php new file mode 100644 index 0000000..c423f77 --- /dev/null +++ b/app/admin/service/setting/StockService.php @@ -0,0 +1,43 @@ +stockList(3,$param); + } + + public function add($param) + { + return (new IPOService())->addStock(3,$param); + } + + + public function edit($param) + { + return (new IPOService())->editStock(3,$param); + } + + // 美股列表 + public function getTradeNameList($param) + { + try { + $list = StockListModel::where('status', 1)->order('id', 'desc')->column('stock_name', 'id'); + return $this->toData('0', 'SUCCESS', ['list' => $list]); + } catch (\Exception $exception) { + return $this->toData('1', '系统繁忙', []); + } + } +} \ No newline at end of file diff --git a/app/admin/validate/AdminBaseValidate.php b/app/admin/validate/AdminBaseValidate.php new file mode 100644 index 0000000..00b2133 --- /dev/null +++ b/app/admin/validate/AdminBaseValidate.php @@ -0,0 +1,93 @@ + 'require|alphaNum', + 'password' => 'require|length:5,40', + 'new_password' => 'require|length:5,40', + 'old_password' => 'require|length:5,40', + 'nick_name' => 'require|alphaNum', + + ]; + + protected $message = [ + 'user_name.alphaNum' => '用户名必须包含字母和数字', + 'nick_name.alphaNum' => '昵称必须包含字母和数字', + 'password.require' => '请填写密码', +// 'password.isString' => '密码格式不正确.', + 'password.length' => '密码必须大于5个字符.', + 'new_password.require' => '请填写新密码', +// 'password.isString' => '密码格式不正确.', + 'new_password.length' => '密码必须大于5个字符.', + 'old_password.require' => '请填写原始密码', +// 'password.isString' => '密码格式不正确.', + 'old_password.length' => '密码必须大于5个字符.', + + ]; + + + protected $scene = [ + 'addUser' => ['user_name','password','nick_name'], + 'updateInfo' => ['nick_name','email'], + 'updateAccount' => ['user_name','nick_name'], + 'updatePassword'=>['new_password','old_password'], + 'updateAccountStatus'=>['id','status'] + ]; +} \ No newline at end of file diff --git a/app/admin/validate/FlowValidate.php b/app/admin/validate/FlowValidate.php new file mode 100644 index 0000000..102e195 --- /dev/null +++ b/app/admin/validate/FlowValidate.php @@ -0,0 +1,77 @@ + 'require|integer', + 'limit' => 'require|integer', + 'order_id' => 'alphaNum', + 'user_no' => 'alphaNum', + 'chang_type' => 'in:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20', + 'digital_id' => 'upper', + 'contract_id' => 'alphaDash', + 'stock_id' => 'alphaDash', + 'start_time' => 'date|dateFormat:Y-m-d H:i:s', + 'end_time' => 'date|dateFormat:Y-m-d H:i:s', + 'from_account' => 'in:1,2,3', + 'to_account' => 'in:1,2,3', + 'account_type' => 'in:1,2,3', + 'trade_type' => 'in:1,2', + 'trade_no' => 'alphaNum', + 'level_type' => 'in:1,2,3', + 'back_type' => 'in:0,1,2,3', + ]; + + protected $message = [ + 'page.require' => '分页参数无效', + 'page.integer' => '分页参数无效', + 'limit.require' => '分页参数无效', + 'limit.integer' => '分页参数无效', + 'chang_type.in' => '变动类型无效', + 'order_id.alphaNum' => '订单号无效', + 'user_no.alphaNum' => '用户号无效', + 'digital_id.upper' => '交易对无效', + 'contract_id.upper' => '合约代码无效', + 'stock_id.upper' => '股票代码无效', + 'start_time.date' => '搜索日期无效', + 'start_time.dateFormat' => '搜索日期无效', + 'end_time.date' => '搜索日期无效', + 'end_time.dateFormat' => '搜索日期无效', + 'from_account.in' => '转出资金账号无效', + 'to_account.in' => '转入资金账号无效', + 'account_type.in' => '账户类型无效', + 'trade_type.in' => '交易类型无效', + 'trade_no.in' => '交易单号无效', + 'level_type.in' => '返佣级别无效', + 'back_type.in' => '返佣类型无效', + ]; + + protected $scene = [ + 'digital' => ['page','limit', 'user_no', 'digital_id', 'chang_type','start_time', 'end_time'], + 'stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + 'contract' => ['page','limit', 'user_no', 'contract_id', 'chang_type','start_time', 'end_time'], + 'forex' => ['page','limit', 'user_no', 'contract_id', 'chang_type','start_time', 'end_time'], + 'transfer' => ['page','limit', 'user_no', 'from_account', 'to_account','start_time', 'end_time'], + 'fee' => ['page','limit', 'user_no', 'account_type', 'trade_type','trade_no','start_time', 'end_time'], + 'brokerage' => ['page','limit', 'user_no', 'level_type', 'back_type','start_time', 'end_time'], + + // 美股资产流水 + 'us_stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + // 印尼股票 + 'idn_stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + // 马来西亚资产流水 + 'mys_stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + // 泰国股票 + 'tha_stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + // 印度股票 + 'in_stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + 'sgd_stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + 'hk_stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + + 'fund_stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + 'block_stock' => ['page','limit', 'user_no', 'stock_id', 'chang_type','start_time', 'end_time'], + + ]; +} \ No newline at end of file diff --git a/app/admin/validate/LoginValidate.php b/app/admin/validate/LoginValidate.php new file mode 100644 index 0000000..d41b405 --- /dev/null +++ b/app/admin/validate/LoginValidate.php @@ -0,0 +1,20 @@ + 'require|alphaNum', + 'password' => 'require|length:5,40', + ]; + protected $message = [ + 'user_name.require' => '请填写用户名', + 'user_name.alphaNum' => '用户名必须包含字母和数字', + 'password.require' => '请填写密码', + 'password.length' => '密码必须大于5个字符.', + ]; + protected $scene = [ + 'login' => ['user_name','password'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/OrderValidate.php b/app/admin/validate/OrderValidate.php new file mode 100644 index 0000000..5adf07e --- /dev/null +++ b/app/admin/validate/OrderValidate.php @@ -0,0 +1,109 @@ + 'require|integer', + 'limit' => 'require|integer', + 'order_id' => 'alphaNum', + 'order_no' => 'alphaNum', + 'user_no' => 'alphaNum', + 'digital_id' => 'upper', + 'contract_id' => 'alphaDash', + 'stock_id' => 'alphaDash', + 'stock_code' => 'alphaDash', + 'status' => 'integer', + 'start_time' => 'date|dateFormat:Y-m-d H:i:s', + 'end_time' => 'date|dateFormat:Y-m-d H:i:s', + ]; + + protected $message = [ + 'page.require' => '分页参数无效', + 'page.integer' => '分页参数无效', + 'limit.require' => '分页参数无效', + 'limit.integer' => '分页参数无效', + 'order_id.alphaNum' => '订单号无效', + 'user_no.alphaNum' => '用户号无效', + 'digital_id.upper' => '交易对无效', + 'contract_id.upper' => '合约代码无效', + 'stock_id.upper' => '股票代码无效', + 'start_time.date' => '搜索日期无效', + 'start_time.dateFormat' => '搜索日期无效', + 'end_time.date' => '搜索日期无效', + 'end_time.dateFormat' => '搜索日期无效', + ]; + + protected $scene = [ + // 现货 + 'digitalPlace' => ['page', 'limit', 'order_id', 'user_no', 'digital_id', 'start_time', 'end_time'], + 'digitalBack' => ['page', 'limit', 'order_id', 'user_no', 'digital_id', 'start_time', 'end_time'], + 'digitalDeal' => ['page', 'limit', 'order_id', 'user_no', 'digital_id', 'start_time', 'end_time'], + + // 合约 + 'contractHold' => ['page', 'limit', 'order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + 'contractPlace' => ['page', 'limit', 'order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + 'contractBack' => ['page', 'limit', 'order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + 'contractClear' => ['page', 'limit', 'order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + // 合约 + 'forexHold' => ['page', 'limit', 'order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + 'forexPlace' => ['page', 'limit', 'order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + 'forexBack' => ['page', 'limit', 'order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + 'forexClear' => ['page', 'limit', 'order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + + // 股票 + 'stockHold' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'stockPlace' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'stockBack' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'stockClear' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + + // 美股股票 + 'us_stockHold' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'us_stockPlace' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'us_stockBack' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'us_stockClear' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + + // 印尼股票 + 'idn_stockHold' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'idn_stockPlace' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'idn_stockBack' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'idn_stockClear' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + + // 马来西亚股票 + 'mys_stockHold' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'mys_stockPlace' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'mys_stockBack' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'mys_stockClear' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + + // 泰国股票 + 'tha_stockHold' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'tha_stockPlace' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'tha_stockBack' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'tha_stockClear' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + + // 印度股票 + 'in_stockHold' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'in_stockPlace' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'in_stockBack' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'in_stockClear' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + + // 申购订单 + 'pre_stock' => ['page', 'limit', 'order_no', 'user_no', 'market_type'], + + // 基金订单 + 'fund_stock' => ['page', 'limit', 'order_no', 'user_no', 'start_time', 'end_time'], + 'fund_stock_info' => ['id'], + 'fund_interest_list' => ['page', 'limit', 'user_no', 'start_time', 'end_time'], + + // 香港股票 + 'hk_stockHold' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'hk_stockPlace' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'hk_stockBack' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'hk_stockClear' => ['page', 'limit', 'order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + + // 大宗交易 + 'block_stock' => ['page', 'limit', 'user_no'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/RechargeValidate.php b/app/admin/validate/RechargeValidate.php new file mode 100644 index 0000000..fb157a4 --- /dev/null +++ b/app/admin/validate/RechargeValidate.php @@ -0,0 +1,44 @@ + 'require|integer', + 'limit' => 'require|integer', + 'check_status' => 'require|integer', + 'is_online' => 'require|integer', + 'id' => 'require|integer', + 'order_id' => 'alphaNum', + 'user_no' => 'alphaNum', + 'start_time' => 'date|dateFormat:Y-m-d H:i:s', + 'end_time' => 'date|dateFormat:Y-m-d H:i:s', + ]; + + protected $message = [ + 'is_online.require' => '支付类型无效', + 'is_online.integer' => '支付类型无效', + 'id.require' => 'ID参数无效', + 'id.integer' => 'ID参数无效', + 'check_status.require' => '审核状态无效', + 'check_status.integer' => '审核无效', + 'page.require' => '分页参数无效', + 'page.integer' => '分页参数无效', + 'limit.require' => '分页参数无效', + 'limit.integer' => '分页参数无效', + 'order_id.alphaNum' => '订单号无效', + 'user_no.alphaNum' => '用户号无效', + 'start_time.date' => '搜索日期无效', + 'start_time.dateFormat' => '搜索日期无效', + 'end_time.date' => '搜索日期无效', + 'end_time.dateFormat' => '搜索日期无效', + ]; + + protected $scene = [ + // 现货 + 'index' => ['page','limit','order_id', 'user_no', 'start_time', 'end_time','is_online'], + 'info' => ['id'], + 'check' => ['id','check_status'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/UserValidate.php b/app/admin/validate/UserValidate.php new file mode 100644 index 0000000..b2c26d3 --- /dev/null +++ b/app/admin/validate/UserValidate.php @@ -0,0 +1,58 @@ + 'require|integer', + 'limit' => 'require|integer', + 'start_time' => 'date|dateFormat:Y-m-d H:i:s', + 'end_time' => 'date|dateFormat:Y-m-d H:i:s', + 'phone' => 'alphaNum', + 'user_no' => 'alphaNum', + 'email' => 'email', + 'status' => 'require|in:1,2,3', + 'frozen_recharge' => 'in:1,0', + 'frozen_withdraw' => 'in:1,0', + 'nation'=>'require', + 'password'=>'require', + 'id' =>'require|integer', + 'is_test_user' => 'require|in:1,2', + ]; + + protected $message = [ + 'page.require' => '分页参数无效', + 'page.integer' => '分页参数无效', + 'limit.require' => '分页参数无效', + 'limit.integer' => '分页参数无效', + 'user_no.alphaNum' => '用户号无效', + 'start_time.date' => '搜索日期无效', + 'start_time.dateFormat' => '搜索日期无效', + 'end_time.date' => '搜索日期无效', + 'end_time.dateFormat' => '搜索日期无效', + 'phone.alphaNum' => '手机号无效', + 'email.email' => '邮箱无效', + 'id.require' => '主键无效', + 'id.alphaNum' => '主键无效', + 'status.require' => '状态无效', + 'nation.require' => '国家代码无效', + 'password.require' => '登录密码无效', + 'status.in' => '主键无效', + 'type.require' => '类型无效', + 'type.in' => '类型无效', + 'is_test_user.in' => '未选择用户类型', + ]; + + + protected $scene = [ + 'index' => ['page','limit','user_no', 'email', 'phone', 'start_time', 'end_time'], + 'status' => ['id','status'], + 'frozen_state' => ['id','frozen_recharge','frozen_withdraw'], + 'change' => ['id','amount'], + 'relation' => ['page','limit','user_no'], + 'add_phone' =>['nation','phone','password'], + 'add_email' =>['email','password'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/WithdrawValidate.php b/app/admin/validate/WithdrawValidate.php new file mode 100644 index 0000000..0e68793 --- /dev/null +++ b/app/admin/validate/WithdrawValidate.php @@ -0,0 +1,41 @@ + 'require|integer', + 'id' => 'require|integer', + 'status' => 'require|integer', + 'limit' => 'require|integer', + 'order_id' => 'alphaNum', + 'user_no' => 'alphaNum', + 'start_time' => 'date|dateFormat:Y-m-d H:i:s', + 'end_time' => 'date|dateFormat:Y-m-d H:i:s', + ]; + + protected $message = [ + 'id.require' => '订单ID无效', + 'id.integer' => '订单ID无效', + 'status.require' => '状态无效', + 'status.integer' => '状态无效', + 'page.require' => '分页参数无效', + 'page.integer' => '分页参数无效', + 'limit.require' => '分页参数无效', + 'limit.integer' => '分页参数无效', + 'order_id.alphaNum' => '订单号无效', + 'user_no.alphaNum' => '用户号无效', + 'start_time.date' => '搜索日期无效', + 'start_time.dateFormat' => '搜索日期无效', + 'end_time.date' => '搜索日期无效', + 'end_time.dateFormat' => '搜索日期无效', + ]; + + protected $scene = [ + // 现货 + 'index' => ['page','limit','order_id', 'user_no', 'start_time', 'end_time'], + 'info' => ['id'], + 'status' => ['id','status'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/auth/AuthRoleValidate.php b/app/admin/validate/auth/AuthRoleValidate.php new file mode 100644 index 0000000..aabe042 --- /dev/null +++ b/app/admin/validate/auth/AuthRoleValidate.php @@ -0,0 +1,30 @@ + 'require|integer', + 'limit' => 'require|integer', + 'id'=>'require|integer', + 'name' => 'require', + 'rules' => 'require', + 'status' => 'require', + + ]; + + protected $message = [ + + + ]; + + + protected $scene = [ + 'add' => ['name'], + 'edit'=> ['id','name'], + 'list'=>[], + 'updateStatus'=>['id','status'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/auth/AuthRuleValidate.php b/app/admin/validate/auth/AuthRuleValidate.php new file mode 100644 index 0000000..a581ead --- /dev/null +++ b/app/admin/validate/auth/AuthRuleValidate.php @@ -0,0 +1,40 @@ + 'require|integer', + 'limit' => 'require|integer', + 'id' => 'require|integer', + 'type' => 'require', + 'pid' => 'require|integer', + 'name' => 'require', + 'title' => 'require', + 'icon'=>'require', + 'route_path'=>'require', + 'remark'=>'require', + 'sort'=>'require', + 'status'=>'require', + 'permission'=>'require', + 'path'=>'require', + 'show'=>'require', + 'component_path'=>'require' + + + ]; + + protected $message = [ + + + ]; + + + protected $scene = [ + 'add' => ['type','name',], + 'edit' => ['id','type','name'], + 'list'=>[] + ]; +} \ No newline at end of file diff --git a/app/admin/validate/setting/ContractValidate.php b/app/admin/validate/setting/ContractValidate.php new file mode 100644 index 0000000..1ac5a3b --- /dev/null +++ b/app/admin/validate/setting/ContractValidate.php @@ -0,0 +1,58 @@ + 'require|alphaDash', + 'status' => 'require|in:0,1', + 'is_owner' => 'require|in:0,1', + 'limit' => 'require|alphaNum', + 'order_id' => 'alphaNum', + 'user_no' => 'alphaNum', + 'digital_id' => 'upper', + 'contract_id' => 'alphaDash', + 'stock_id' => 'alphaDash', + 'start_time' => 'date|dateFormat:Y-m-d H:i:s', + 'end_time' => 'date|dateFormat:Y-m-d H:i:s', + ]; + + protected $message = [ + 'page.require' => '分页参数无效', + 'page.alphaNum' => '分页参数无效', + 'limit.require' => '分页参数无效', + 'limit.alphaNum' => '分页参数无效', + 'order_id.alphaNum' => '订单号无效', + 'user_no.alphaNum' => '用户号无效', + 'digital_id.upper' => '交易对无效', + 'contract_id.upper' => '合约代码无效', + 'stock_id.upper' => '股票代码无效', + 'start_time.date' => '搜索日期无效', + 'start_time.dateFormat' => '搜索日期无效', + 'end_time.date' => '搜索日期无效', + 'end_time.dateFormat' => '搜索日期无效', + ]; + + protected $scene = [ + // 现货 + 'digitalPlace' => ['page','limit','order_id', 'user_no', 'digital_id', 'start_time', 'end_time'], + 'digitalBack' => ['page','limit','order_id', 'user_no', 'digital_id', 'start_time', 'end_time'], + 'digitalDeal' => ['page','limit','order_id', 'user_no', 'digital_id', 'start_time', 'end_time'], + + // 合约 + 'contractHold' => ['page','limit','order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + 'contractPlace' => ['page','limit','order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + 'contractBack' => ['page','limit','order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + 'contractClear' => ['page','limit','order_id', 'user_no', 'contract_id', 'start_time', 'end_time'], + + // 股票 + 'stockHold' => ['page','limit','order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'stockPlace' => ['page','limit','order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'stockBack' => ['page','limit','order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + 'stockClear' => ['page','limit','order_id', 'user_no', 'stock_id', 'start_time', 'end_time'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/setting/HqValidate.php b/app/admin/validate/setting/HqValidate.php new file mode 100644 index 0000000..f8fc870 --- /dev/null +++ b/app/admin/validate/setting/HqValidate.php @@ -0,0 +1,35 @@ + 'require|alphaDash', + 'begin_time' => 'date', + 'end_time' => 'date', + 'step' => 'require|integer', + 'max_price' => 'require|float', + 'id' => 'require|integer', + ]; + + protected $message = [ + 'trade_name.require' => '交易对无效', + 'trade_name.alphaDash' => '交易对无效', + 'begin_time.date' => '开始时间无效', + 'end_time.date' => '结束时间无效', + 'step.require' => '波动率不能为空', + 'step.integer' => '波动率必须为整数', + 'max_price.require' => '价格无效', + 'max_price.float' => '价格无效', + ]; + + protected $scene = [ + 'add' => ['trade_name','begin_time','end_time', 'step', 'max_price'], + 'edit' => ['trade_name','begin_time','end_time', 'step', 'max_price', 'id'], + 'del' => ['id'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/setting/MarketValidate.php b/app/admin/validate/setting/MarketValidate.php new file mode 100644 index 0000000..0657f3b --- /dev/null +++ b/app/admin/validate/setting/MarketValidate.php @@ -0,0 +1,31 @@ + 'require|alphaDash', + 'end_time' => 'date|dateFormat:Y-m-d H:i', + 'max_price' => 'require|float', + 'id' => 'require|integer', + ]; + + protected $message = [ + 'trade_name.require' => '交易对无效', + 'trade_name.alphaDash' => '交易对无效', + 'end_time.dateFormat' => '结束时间无效3', + 'end_time.date' => '结束时间无效4', + 'max_price.require' => '价格无效', + 'max_price.float' => '价格无效', + ]; + + protected $scene = [ + 'add' => ['trade_name','end_time', 'max_price'], + 'edit' => ['trade_name','end_time', 'max_price', 'id'], + 'del' => ['id'], + 'detail' => ['trade_name'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/setting/PaymentValidate.php b/app/admin/validate/setting/PaymentValidate.php new file mode 100644 index 0000000..766e6ee --- /dev/null +++ b/app/admin/validate/setting/PaymentValidate.php @@ -0,0 +1,62 @@ + 'require|integer', + 'limit' => 'require|integer', + 'country' => 'require|checkIsString', + 'channel' => 'require', + 'service_rate' => 'require|float', + //'channel_type' => 'checkInRequire|in:Bank,TRC-20,ERC-20,BRC-20', + 'channel_type' => 'require', + 'status' => 'checkStatusRequire|in:0,1', + 'pay_type' => 'checkStatusRequire|in:0,1', + 'is_recharge' => 'checkStatusRequire|in:0,1', + 'is_withdrawal' => 'checkStatusRequire|in:0,1', + + 'id' => 'require|checkNumberIntBg', + ]; + + protected $message = [ + 'page.require' => '分页参数无效', + 'page.integer' => '分页参数无效', + 'limit.require' => '分页参数无效', + 'limit.integer' => '分页参数无效', + 'channel.require' => '渠道名称不能为空', + 'country.require' => '国家代码无效', + 'service_rate.require' => '手续费率不能为空', + 'service_rate.float' => '手续费率无效', + + 'country.checkIsString' => '国家代码无效', + + 'status.checkStatusRequire' => '状态无效', + 'status.in' => '状态无效', + 'pay_type.checkStatusRequire' => '结算方式无效', + 'pay_type.in' => '结算方式无效', + 'is_recharge.checkStatusRequire' => '充值渠道状态无效', + 'is_recharge.in' => '充值渠道状态无效', + 'is_withdrawal.checkStatusRequire' => '提现渠道状态无效', + 'is_withdrawal.in' => '提现渠道状态无效', + 'channel_type.checkInRequire' => '渠道类型无效1', + 'channel_type.in' => '渠道类型无效', + 'channel_type.require' => '渠道类型无效', + + 'id.require' => '主键无效', + 'id.checkNumberIntBg' => '主键无效', + + ]; + + + protected $scene = [ + // 美股 + 'payment_index' => ['page','limit'], + 'payment_add' => ['country','channel', 'status', 'pay_type', 'service_rate', 'channel_type', 'exchange_rate','is_recharge','is_withdrawal'], + 'payment_edit' => ['id','country','channel', 'status', 'pay_type', 'service_rate', 'channel_type', 'exchange_rate','is_recharge','is_withdrawal'], + 'payment_info'=>['id'], + ]; +} \ No newline at end of file diff --git a/app/admin/validate/setting/StockValidate.php b/app/admin/validate/setting/StockValidate.php new file mode 100644 index 0000000..5bb8781 --- /dev/null +++ b/app/admin/validate/setting/StockValidate.php @@ -0,0 +1,112 @@ + 'require|integer', + 'limit' => 'require|integer', + 'stock_name' => 'require|checkIsString', + 'stock_code' => 'require|checkIsString', + 'status' => 'checkStatusRequire|in:0,1', + 'keep_decimal' => 'checkNumberIntAt', + 'forced_closure' => 'require|checkNumberFloatBg', + 'up_limit' => 'require|checkNumberFloatBg', + 'down_limit' => 'require|checkNumberFloatBg', + 'id' => 'require|checkNumberIntBg', + ]; + + protected $message = [ + 'page.require' => '分页参数无效', + 'page.integer' => '分页参数无效', + 'limit.require' => '分页参数无效', + 'limit.integer' => '分页参数无效', + 'stock_name.require' => '股票名称无效', + 'stock_name.checkIsString' => '股票名称无效', + + 'stock_code.require' => '股票代码无效', + 'stock_code.checkIsString' => '股票代码无效', + + 'status.checkStatusRequire' => '状态无效', + 'status.in' => '状态无效', + + 'keep_decimal.require' => '保留小数位无效', + 'keep_decimal.checkNumberIntBg' => '保留小数位无效', + + 'forced_closure.require' => '强制平仓阈值无效', + 'forced_closure.checkNumberFloatBg' => '强制平仓阈值无效', + + 'up_limit.require' => '涨停限制无效', + 'up_limit.checkNumberFloatBg' => '涨停限制无效', + + 'down_limit.require' => '跌停限制无效', + 'down_limit.checkNumberFloatBg' => '跌停限制无效', + + 'id.require' => '主键无效', + 'id.checkNumberIntBg' => '主键无效', + + ]; + + + protected $scene = [ + // 美股 + 'us_stock_index' => ['page', 'limit'], + 'us_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'us_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + + // 印尼股 + 'idn_stock_index' => ['page', 'limit'], + 'idn_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'idn_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + + // 马股 + 'mys_stock_index' => ['page', 'limit'], + 'mys_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'mys_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + + // 印度 + 'in_stock_index' => ['page', 'limit'], + 'in_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'in_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + + // 泰股 + 'tha_stock_index' => ['page', 'limit'], + 'tha_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'tha_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + // 新加坡 + 'sgd_stock_index' => ['page', 'limit'], + 'sgd_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'sgd_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + // 香港 + 'hk_stock_index' => ['page', 'limit'], + 'hk_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'hk_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + // 英国 + 'gbx_stock_index' => ['page', 'limit'], + 'gbx_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'gbx_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + // 法国 + 'fur_stock_index' => ['page', 'limit'], + 'fur_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'fur_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + // 德国 + 'eur_stock_index' => ['page', 'limit'], + 'eur_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'eur_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + // 德国 + 'jp_stock_index' => ['page', 'limit'], + 'jp_stock_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + 'jp_stock_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure', 'up_limit', 'down_limit'], + + // 印度期权 + 'in_option_index' => ['page', 'limit'], + 'in_option_add' => ['stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure'], + 'in_option_edit' => ['id', 'stock_name', 'stock_code', 'status', 'keep_decimal', 'forced_closure'], + + //自动添加股票 + 'stock_auto_add' => ['stock_name', 'stock_code', 'tape', 'country'], + ]; +} \ No newline at end of file diff --git a/app/common.php b/app/common.php new file mode 100644 index 0000000..b83dd64 --- /dev/null +++ b/app/common.php @@ -0,0 +1,2 @@ + [ + ], + + 'listen' => [ + 'AppInit' => [], + 'HttpRun' => [], + 'HttpEnd' => [], + 'LogLevel' => [], + 'LogWrite' => [], + ], + + 'subscribe' => [ + ], +]; diff --git a/app/home/controller/Announcement.php b/app/home/controller/Announcement.php new file mode 100644 index 0000000..b939e54 --- /dev/null +++ b/app/home/controller/Announcement.php @@ -0,0 +1,122 @@ +request->header('Language'); + if(empty($lang)){ + $lang = 'zh-cn'; + } + $langId = 1; + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(!empty($langModel)){ + $langId = $langModel->id; + } + + $is_pop_ups = $this->request->post()['is_pop_ups'] ?? 0; + $announcement = AnnouncementModel::where('status', AnnouncementModel::STATUS_ON); + if ($is_pop_ups) $announcement = $announcement->where('is_pop_ups', $is_pop_ups); + $list = $announcement->where('is_delete', AnnouncementModel::IS_DELETE_NO) + ->where('lang', $langId) + ->order('weight', 'desc') + ->select(); + + $res = []; + if(!$list->isEmpty()){ + foreach ($list as $item){ + $res[] = [ + 'id' => $item['id'], + 'title' => $item['title'], + 'create_time' => $item['update_time'], + ]; + } + } + + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => $res, + ]); + } + + public function detail() + { + $id = $this->request->param('id'); + if(empty($id)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => '','title'=>'','create_time'=>date('Y-m-d H:i:s')], + ]); + } + + $announcement = AnnouncementModel::where('id', $id)->where('status', DocumentModel::STATUS_ON)->find(); + if(empty($announcement)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => '','title'=>'', 'create_time' => date('Y-m-d H:i:s')], + ]); + } + + + // 判断是否修改了语言 + $lang = $this->request->header('Language'); + if(empty($lang)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $announcement['content'],'title'=>$announcement['title'], 'create_time' =>$announcement['update_time']], + ]); + } + + // 无效语言 + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(empty($langModel)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $announcement['content'],'title'=>$announcement['title'],'create_time' =>$announcement['update_time']], + ]); + } + + // 语言相同 + if($langModel['id'] == $announcement['lang']){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $announcement['content'],'title'=>$announcement['title'],'create_time' =>$announcement['update_time']], + ]); + } + + // 查询同名 其他语言文件 + $announcementChange = AnnouncementModel::where('name', $announcement['name']) + ->where('status', DocumentModel::STATUS_ON) + ->where('lang', $langModel['id']) + ->find(); + if(empty($announcementChange)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $announcement['content'],'title'=>$announcement['title'],'create_time' =>$announcement['update_time']], + ]); + } + + // 返回原数据 + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $announcementChange['content'],'title'=>$announcementChange['title'],'create_time' =>$announcementChange['update_time']], + ]); + + } +} \ No newline at end of file diff --git a/app/home/controller/Block.php b/app/home/controller/Block.php new file mode 100644 index 0000000..3fda761 --- /dev/null +++ b/app/home/controller/Block.php @@ -0,0 +1,26 @@ +index($this->request->param()); + return json($result); + } + + // 大宗交易订单列表列表 + public function list() + { + $service = new BlockStockService(); + $result = $service->list($this->request->param(), $this->request->userId); + return json($result); + } +} \ No newline at end of file diff --git a/app/home/controller/Carousel.php b/app/home/controller/Carousel.php new file mode 100644 index 0000000..5fc32fc --- /dev/null +++ b/app/home/controller/Carousel.php @@ -0,0 +1,136 @@ +getCarousel(); + return json($result); + } + + // 广告图 + public function index() + { + // 语言筛选 + $lang = $this->request->header('Language'); + if(empty($lang)){ + $lang = 'zh-cn'; + } + + $langId = 1; + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(!empty($langModel)){ + $langId = $langModel->id; + } + + $banner = BannerModel::where('status', BannerModel::STATUS_ON) + ->where('is_delete', BannerModel::IS_DELETE_NO) + ->where('lang', $langId) + ->select(); + + $res = []; + if(!$banner->isEmpty()){ + foreach ($banner as $item){ + $res[] = [ + 'id' => $item['id'], + 'title' => $item['title'], + 'content' => $item['content'], + 'image' => $item['path'], + 'redirect_url' => '', + 'type'=> '1' + ]; + } + } + + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => $res, + ]); + } + + // 广告图详情 + public function detail() + { + $id = $this->request->param('id'); + if(empty($id)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => '','title'=>''], + ]); + } + + $banner = BannerModel::where('id', $id)->where('status', BannerModel::STATUS_ON)->find(); + if(empty($banner)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => '','title'=>''], + ]); + } + + + // 判断是否修改了语言 + $lang = $this->request->header('Language'); + if(empty($lang)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $banner['content'],'title'=>$banner['title']], + ]); + } + + // 无效语言 + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(empty($langModel)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $banner['content'],'title'=>$banner['title']], + ]); + } + + // 语言相同 + if($langModel['id'] == $banner['lang']){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $banner['content'],'title'=>$banner['title']], + ]); + } + + // 查询同名 其他语言文件 + $bannerChange = BannerModel::where('name', $banner['name']) + ->where('status', BannerModel::STATUS_ON) + ->where('lang', $langModel['id']) + ->find(); + if(empty($bannerChange)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $banner['content'],'title'=>$banner['title']], + ]); + } + + // 返回原数据 + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $bannerChange['content'],'title'=>$bannerChange['title']], + ]); + + } +} \ No newline at end of file diff --git a/app/home/controller/Country.php b/app/home/controller/Country.php new file mode 100644 index 0000000..09d6655 --- /dev/null +++ b/app/home/controller/Country.php @@ -0,0 +1,44 @@ +select(); + $returnData = []; + if(!$res->isEmpty()){ + $deny = explode(',', env('NATION.DENY_NATION')); + foreach ($res as $item) { + $active = 1; + if(in_array($item['code'],$deny )){ + $active = 0; + } + $returnData[] = [ + 'id' => $item['id'], + 'nameCn' => $item['name_cn'], + 'nameEn' => $item['name_en'], + 'nation' => $item['code'], + 'active' => $active, + ]; + } + } + return json(['code' => '0', 'message' => 'Request successful.','data' => $returnData]); + }catch (\Exception $exception){ + return json(['code' => '100500', 'message' => 'System error','data' => [$exception->getMessage()]]); + } + + } + + +} \ No newline at end of file diff --git a/app/home/controller/Device.php b/app/home/controller/Device.php new file mode 100644 index 0000000..18fe273 --- /dev/null +++ b/app/home/controller/Device.php @@ -0,0 +1,13 @@ +request->header('Language'); + if(empty($lang)){ + $lang = 'zh-cn'; + } + + $langId = 1; + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(!empty($langModel)){ + $langId = $langModel->id; + } + + $res = [ + 'other'=>[] + ]; + $map = DocumentModel::TYPE_FOOTER_PC; + $docList = DocumentModel::where('type', 'in', array_keys($map)) + ->where('status', DocumentModel::STATUS_ON) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->where('lang', $langId) + ->order('type', 'asc') + ->order('weight', 'desc') + ->select(); + + if(!$docList->isEmpty()){ + foreach ($docList as $item){ + $res['other'][] = [ + 'title' => $item['title'], + 'content' => $item['content'], + 'id' => $item['id'], + ]; + } + } + + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => $res, + ]); + } + + // h5 平台管理 + public function getPlatform() + { + // 语言筛选 + $lang = $this->request->header('Language'); + if(empty($lang)){ + $lang = 'zh-cn'; + } + + $langId = 1; + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(!empty($langModel)){ + $langId = $langModel->id; + } + + $doc = DocumentModel::where('lang', $langId)->where('status', DocumentModel::STATUS_ON) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->where('type', '5')->order('id', 'desc')->find(); + $res = ['content' => '']; + if(!empty($doc)){ + $res['content'] = $doc['content']; + } + + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => $res, + ]); + } + + // pc 页脚 文档 + public function getDocPc() + { + // 语言筛选 + $lang = $this->request->header('Language'); + if(empty($lang)){ + $lang = 'zh-cn'; + } + + $langId = 1; + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(!empty($langModel)){ + $langId = $langModel->id; + } + + // 支持的类型 + $map = DocumentModel::TYPE_FOOTER_PC; + $docList = DocumentModel::where('type', 'in', array_keys($map)) + ->where('status', DocumentModel::STATUS_ON) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->where('lang', $langId) + ->order('type', 'asc')->order('weight', 'desc') + ->select(); + + $res = []; + foreach ($map as $key=>$value){ + $res[$key] = [ + 'name' => $value, + 'child' => [] + ]; + } + if(!$docList->isEmpty()){ + foreach ($docList as $item) { + $res[$item['type']]['child'][] = [ + 'title' => $item['title'], + 'content' => $item['content'], + 'id' => $item['id'], + ]; + } + } + + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => $res, + ]); + } + + // 详情 + public function detail() + { + $id = $this->request->param('id'); + if(empty($id)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => '','title'=>''], + ]); + } + + $doc = DocumentModel::where('id', $id) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->where('status', DocumentModel::STATUS_ON)->find(); + if(empty($doc)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => '','title'=>''], + ]); + } + + // 判断是否修改了语言 + $lang = $this->request->header('Language'); + if(empty($lang)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $doc['content'],'title'=>$doc['title']], + ]); + } + + // 无效语言 + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(empty($langModel)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $doc['content'],'title'=>$doc['title']], + ]); + } + + // 语言相同 + if($langModel['id'] == $doc['lang']){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $doc['content'],'title'=>$doc['title']], + ]); + } + + // 查询同名 其他语言文件 + $docChange = DocumentModel::where('name', $doc['name']) + ->where('status', DocumentModel::STATUS_ON) + ->where('is_delete', DocumentModel::IS_DELETE_NO) + ->where('lang', $langModel['id']) + ->find(); + if(empty($docChange)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $doc['content'],'title'=>$doc['title']], + ]); + } + + // 返回原数据 + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $docChange['content'],'title'=>$docChange['title']], + ]); + } +} \ No newline at end of file diff --git a/app/home/controller/Faq.php b/app/home/controller/Faq.php new file mode 100644 index 0000000..cccd262 --- /dev/null +++ b/app/home/controller/Faq.php @@ -0,0 +1,120 @@ +request->header('Language'); + if(empty($lang)){ + $lang = 'zh-cn'; + } + + $langId = 1; + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(!empty($langModel)){ + $langId = $langModel->id; + } + + $faq = FaqModel::where('status', FaqModel::STATUS_ON) + ->where('is_delete', FaqModel::IS_DELETE_NO) + ->where('lang', $langId) + ->order('weight', 'desc') + ->select(); + + $res = []; + if(!$faq->isEmpty()){ + foreach ($faq as $item){ + $res[] = [ + 'id' => $item['id'], + 'title' => $item['title'], + 'content' => $item['content'], + ]; + } + } + + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => $res, + ]); + } + + public function detail() + { + $id = $this->request->param('id'); + if(empty($id)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => '','title'=>''], + ]); + } + + $faq = FaqModel::where('id', $id)->where('status', FaqModel::STATUS_ON)->find(); + if(empty($faq)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => '','title'=>''], + ]); + } + + + // 判断是否修改了语言 + $lang = $this->request->header('Language'); + if(empty($lang)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $faq['content'],'title'=>$faq['title']], + ]); + } + + // 无效语言 + $langModel = LanguageSettingModel::where('language_code', $lang)->find(); + if(empty($langModel)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $faq['content'],'title'=>$faq['title']], + ]); + } + + // 语言相同 + if($langModel['id'] == $faq['lang']){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $faq['content'],'title'=>$faq['title']], + ]); + } + + // 查询同名 其他语言文件 + $faqChange = FaqModel::where('name', $faq['name']) + ->where('status', FaqModel::STATUS_ON) + ->where('lang', $langModel['id']) + ->find(); + if(empty($faqChange)){ + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $faq['content'],'title'=>$faq['title']], + ]); + } + + // 返回原数据 + return json([ + 'code'=>'0', + 'message' => 'Request successful.', + 'data' => ['content' => $faqChange['content'],'title'=>$faqChange['title']], + ]); + + } +} \ No newline at end of file diff --git a/app/home/controller/Fund.php b/app/home/controller/Fund.php new file mode 100644 index 0000000..1cdd013 --- /dev/null +++ b/app/home/controller/Fund.php @@ -0,0 +1,53 @@ +index($this->request->param()); + return json($result); + } + + // 基金详情 + public function detail(): Json + { + $result = (new FundService())->detail($this->request->param()); + return json($result); + } + + //历史走势 + public function history(): Json + { + $result = (new FundService())->history($this->request->param()); + return json($result); + } + + // 申购下单 + public function order(): Json + { + $result = (new FundService())->order($this->request->param(), $this->request->userId); + return json($result); + } + + // 用户基金持仓 + public function userFund(): Json + { + $result = (new FundService())->userFund($this->request->param(), $this->request->userId); + return json($result); + } + + // 用户基金 - 资产流水 + public function userFundAssets(): Json + { + $result = (new FundService())->userFundAssets($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/home/controller/HomeBaseController.php b/app/home/controller/HomeBaseController.php new file mode 100644 index 0000000..e7ae51b --- /dev/null +++ b/app/home/controller/HomeBaseController.php @@ -0,0 +1,10 @@ +getLangList(); + return json($result); + } + public function serviceList(Request $request): Json + { + $result = (new LanguageService())->getServiceList(); + return json($result); + } + public function initRedisData(Request $request): Json + { + $result = (new BaseHomeService())->initSetting(); + return json($result); + } + +} \ No newline at end of file diff --git a/app/home/controller/Login.php b/app/home/controller/Login.php new file mode 100644 index 0000000..80829be --- /dev/null +++ b/app/home/controller/Login.php @@ -0,0 +1,126 @@ +sendEmail($this->request->post()); + return json($returnData); + } + + /** + * @desc 邮箱注册 + * @return Json + * @throws \Psr\SimpleCache\InvalidArgumentException + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function registerEmail(): Json + { + $returnData = (new LoginService())->registerEmail($this->request->post()); + return json($returnData); + } + + /** + * @desc 登陆接口 + * @return Json + */ + public function loginEmail(): Json + { + $returnData = (new LoginService())->loginEmail($this->request->post()); + return json($returnData); + } + + /** + * #desc 发送短信验证码 + * @return Json + */ + public function sendSms(): Json + { + $returnData = (new LoginService())->sendSms($this->request->post()); + return json($returnData); + } + + + /** + * @desc @desc 短信注册 + * @return Json + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function registerSms(): Json + { + $returnData = (new LoginService())->registerSms($this->request->post()); + return json($returnData); + } + + /** + * @desc 短信验证码登陆 + * @return Json + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function loginSms(): Json + { + $returnData = (new LoginService())->loginSms($this->request->post()); + return json($returnData); + } + + /** + * @desc 忘记密码 根据邮箱设置密码 + * @return Json + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function resetPasswordByEmail(): Json + { + $returnData = (new LoginService())->resetPasswordByEmail($this->request->post()); + return json($returnData); + } + + /** + * @desc 忘记密码 根据短信设置密码 + * @return Json + */ + public function resetPasswordBySms(): Json + { + $returnData = (new LoginService())->resetPasswordBySms($this->request->post()); + return json($returnData); + } + + /** + * @desc 手机号登陆 + * @return Json + */ + public function phoneLogin(): Json + { + $returnData = (new LoginService())->phoneLogin($this->request->post()); + return json($returnData); + } + + /** + * 免密码登录 + * @return Json + */ + public function autoLogin():Json + { + $returnData = (new LoginService())->autoLogin($this->request->post()); + return json($returnData); + } + public function getIP():Json + { + $returnData = (new LoginService())->getIP(); + return json($returnData); + } + + +} \ No newline at end of file diff --git a/app/home/controller/Market.php b/app/home/controller/Market.php new file mode 100644 index 0000000..6fb0b57 --- /dev/null +++ b/app/home/controller/Market.php @@ -0,0 +1,130 @@ +post('market_type'); + $data['trade_name'] = $request->post('trade_name'); + $data['page'] = $request->post('page',1); + $data['page_size'] = $request->post('page_size',10); + $result = (new MarketService())->getMarketList($data); + return json($result); + } + + /** + * 获取用户自选行情 + * @param Request $request + * @return Json + */ + public function userMarket(Request $request): Json + { + $data['market_type']= $request->post('market_type'); + $data['user_id'] = $request->userId; + $data['trade_name'] = $request->post('trade_name'); + $data['page'] = $request->post('page',1); + $data['page_size'] = $request->post('page_size',10); + $result = (new MarketService())->getUserMarket($data); + return json($result); + } + + /** + * 添加自选数据 + * @param Request $request + * @return Json + */ + public function addMarket(Request $request): Json + { + $data['market_type'] = $request->post('market_type'); + $data['user_id'] = $request->userId; + $data['trade_name'] = $request->post('trade_name'); + $data['trade_numeric_code'] = $request->post('trade_numeric_code') ?? 0; + $data['market_name'] = $request->post('market_name'); + $result = (new MarketService())->addUserMarket($data); + return json($result); + } + + /** + * 删除自选数据 + * @param Request $request + * @return Json + */ + public function delMarket(Request $request): Json + { + $data['market_type'] = $request->post('market_type'); + $data['user_id'] = $request->userId; + $data['trade_name'] = $request->post('trade_name'); + $result = (new MarketService())->delUserMarket($data); + return json($result); + } + public function MarketCollect(Request $request): Json + { + $data['market_type'] = $request->post('market_type'); + $data['user_id'] = $request->userId; + $data['trade_name'] = $request->post('trade_name'); + $result = (new MarketService())->getUserIsCollect($data); + return json($result); + + } + /** + * 获取交易手续费用 + */ + public function tradeFee(Request $request): Json + { + $data['market_type'] = $request->post('market_type'); + $result = (new MarketService())->getTradeFee($data); + return json($result); + } + public function marketTradeList(Request $request): Json + { + $data['market_type'] = $request->post('market_type'); + $data['trade_name'] = $request->post('trade_name'); + $data['num'] = $request->post('num',100); + $result = (new MarketService())->getMarketTradeList($data); + return json($result); + + } + public function TradeTypeList(Request $request): Json + { + $result = (new MarketService())->getTradeTypeList(); + return json($result); + } + public function ForexFaceList(Request $request): Json + { + $data['trade_name'] = $request->post('trade_name'); + $result = (new MarketService())->getForexFace($data); + return json($result); + } + public function ContractFaceList(Request $request): Json + { + $result = (new MarketService())->getContractFace(); + return json($result); + } + public function ContractSetting(Request $request): Json + { + $result = (new MarketService())->getContractSetting(); + return json($result); + } + public function marketRate(Request $request): Json + { + $result = (new MarketService())->getMarketRate(); + return json($result); + } + + +} \ No newline at end of file diff --git a/app/home/controller/News.php b/app/home/controller/News.php new file mode 100644 index 0000000..1ebf0f2 --- /dev/null +++ b/app/home/controller/News.php @@ -0,0 +1,91 @@ +get($key); + if(empty($result)){ + $client=new Client(); + // 访问一个网页 + $crawler = $client->request('GET', 'https://www.nikkei.com/news/category/markets/'); + // 提取所有的段落 + $paragraphs = $crawler->filter('li.cardListItem_cq2exak a')->each(function ($node) { + $url="https://www.nikkei.com".str_ireplace('https://www.nikkei.com','',$node->attr('href')); + $img_obj=$node->filter('div.image_i66x7bx img'); + $img_url=""; + if($img_obj->count()>0){ + $img_url=$node->filter('div.image_i66x7bx img')->attr('src'); + } + if(!empty($img_url)){ + return [ + 'title'=>$node->filter('span.articleTitle_axocstj')->text(), + 'img_url'=>$img_url, + 'href'=>str_ireplace('\\','',$url) + ]; + } + }); + $paragraphs=array_filter($paragraphs); + $titles = array_flip(array_column($paragraphs, 'title')); + $result = []; + foreach ($paragraphs as $item) { + if (isset($titles[$item['title']])) { + $result[] = $item; + unset($titles[$item['title']]); //Remove from unique IDs to ensure only first is kept. + } + } + $paragraphs=$result; + Cache::store('redis')->set($key,$paragraphs,300); + }else{ + $paragraphs=$result; + } + + return json([ + 'code' => '0', + 'message' => 'Request successful.', + 'data' => $paragraphs, + ]); + + } + public function test(): Json + { + $client=new Client(); + // 访问一个网页 + $crawler = $client->request('GET', 'https://www.nikkei.com/news/category/markets/'); + // 提取所有的段落 + $paragraphs = $crawler->filter('li.cardListItem_cq2exak a')->each(function ($node) { + $url="https://www.nikkei.com".str_ireplace('https://www.nikkei.com','',$node->attr('href')); + $img_obj=$node->filter('div.image_i66x7bx img'); + $img_url=""; + if($img_obj->count()>0){ + $img_url=$node->filter('div.image_i66x7bx img')->attr('src'); + } + if(!empty($img_url)){ + return [ + 'title'=>$node->filter('span.articleTitle_axocstj')->text(), + 'img_url'=>$img_url, + 'href'=>str_ireplace('\\','',$url) + ]; + } + }); + + + return json([ + 'code' => '0', + 'message' => 'Request successful.', + 'data' => array_filter($paragraphs), + ]); + + } + + + +} \ No newline at end of file diff --git a/app/home/controller/Pay.php b/app/home/controller/Pay.php new file mode 100644 index 0000000..9c31cdb --- /dev/null +++ b/app/home/controller/Pay.php @@ -0,0 +1,320 @@ +post('is_online', 1); + $result = (new PayService())->getPaymentList($data); + return json($result); + } + + public function BankList(Request $request): Json + { + $result = (new IndPayService())->getBankList(); + return json($result); + } + + /** + * 用户充值接口 + * @return Json + */ + public function rechargeApply(Request $request): Json + { + $data['user_id'] = $request->userId; + $data['account_type'] = $request->post('account_type'); + $data['country'] = $request->post('country'); + $data['recharge_channel'] = $request->post('recharge_channel'); + $data['recharge_num'] = $request->post('recharge_num'); + $data['is_online'] = $request->post('is_online', 1); + $data['file_id'] = $request->post('file_id', 0); + $data['product'] = $request->post('product', ''); + $data['extra'] = $request->post('extra', ''); + $result = (new PayService())->insertRechargeApply($data); + return json($result); + } + public function getTRC20BuyList(Request $request): Json + { + $result=(new StarPayService())->getTRC20BuyList(); + return json($result); + } + public function starPayNotify(Request $request) + { + Log::info('starPay支付异步回调:' . json_encode($_REQUEST)); + + $data['merchant_no'] = $request->post('merchant_no'); + $data['timestamp'] = $request->post('timestamp'); + $data['sign_type'] = $request->post('sign_type'); + $data['sign'] = $request->post('sign'); + //$data['params'] = json_decode($request->post('params'),true); + $data['params'] = $request->post('params'); + Log::info('starPay支付异步回调:' . json_encode($data)); + $result = (new StarPayService())->starPayNotify($data); + return $result; + } + public function indPayNotify(Request $request) + { + Log::info('支付异步回调:' . json_encode($_REQUEST)); + $data['busi_code'] = $request->post('busi_code'); + $data['err_code'] = $request->post('err_code'); + $data['err_msg'] = $request->post('err_msg'); + $data['mer_no'] = $request->post('mer_no'); + $data['mer_order_no'] = $request->post('mer_order_no'); + $data['order_amount'] = $request->post('order_amount'); + $data['order_no'] = $request->post('order_no'); + $data['order_time'] = $request->post('order_time'); + $data['pay_amount'] = $request->post('pay_amount'); + $data['pay_time'] = $request->post('pay_time'); + $data['status'] = $request->post('status'); + $data['sign'] = $request->post('sign'); + Log::info('支付异步回调:' . json_encode($data)); + $result = (new IndPayService())->indPayNotify($data); + return $result['msg']; + } + + public function indPayQuery(Request $request) + { + Log::info('支付同步回调:' . json_encode($_REQUEST)); + $data['busi_code'] = $request->post('busi_code'); + $data['err_code'] = $request->post('err_code'); + $data['err_msg'] = $request->post('err_msg'); + $data['mer_no'] = $request->post('mer_no'); + $data['mer_order_no'] = $request->post('mer_order_no'); + $data['order_amount'] = $request->post('order_amount'); + $data['order_no'] = $request->post('order_no'); + $data['order_time'] = $request->post('order_time'); + $data['pay_amount'] = $request->post('pay_amount'); + $data['pay_time'] = $request->post('pay_time'); + $data['status'] = $request->post('status'); + $data['sign'] = $request->post('sign'); + Log::info('支付同步回调:' . json_encode($data)); + return 'SUCCESS'; + } + + public function singleNotify(Request $request) + { + Log::info('代付回调:' . json_encode($_REQUEST)); + $data['err_code'] = $request->post('err_code'); + $data['err_msg'] = $request->post('err_msg'); + $data['mer_no'] = $request->post('mer_no'); + $data['mer_order_no'] = $request->post('mer_order_no'); + $data['order_amount'] = $request->post('order_amount'); + $data['ccy_no'] = $request->post('ccy_no'); + $data['order_no'] = $request->post('order_no'); + $data['create_time'] = $request->post('create_time'); + $data['pay_time'] = $request->post('pay_time'); + $data['status'] = $request->post('status'); + $data['sign'] = $request->post('sign'); + Log::info('代付回调:' . json_encode($data)); + $result = (new IndPayService())->singleIndNotify($data); + return $result['msg']; + } + + public function payNotify(Request $request) + { + $data = $request->post('data'); + $result = (new TrcPayService())->TrcpayNotify($data); + return $result; + } + + public function OrderConfirm(Request $request) + { + $data = $request->post('data'); + $result = (new TrcPayService())->dealOrderConfirm($data); + return $result; + } + + public function wallet(Request $request) + { + (new TrcPayService())->WalletAddress(); + } + + public function htPayNotify(Request $request) + { + Log::info('合泰回调:' . json_encode($_REQUEST)); + $data['amount'] = $request->post('amount'); + $data['mchId'] = $request->post('mchId'); + $data['mchOrderNo'] = $request->post('mchOrderNo'); + $data['merRetMsg'] = $request->post('merRetMsg'); + $data['signType'] = $request->post('signType'); + $data['tradeResult'] = $request->post('tradeResult'); + $data['sign'] = $request->post('sign'); + $result = (new HTPayService())->qrNotify($data); + return 'success'; + } + + public function arPayNotify(Request $request) + { + Log::info('合泰代付回调:' . json_encode($_REQUEST)); + $data['amount'] = $request->post('amount'); + $data['mchId'] = $request->post('mchId'); + $data['mchOrderNo'] = $request->post('mchOrderNo'); + $data['signType'] = $request->post('signType'); + $data['tradeResult'] = $request->post('tradeResult'); + $data['sign'] = $request->post('sign'); + $result = (new HTPayService())->arNotify($data); + return 'success'; + } + + public function XdPayNotify(Request $request) + { + Log::info('Xdpay代收回调:' . json_encode($_REQUEST)); + $data['platOrderId'] = $request->post('platOrderId'); + $data['orderId'] = $request->post('orderId'); + $data['amount'] = $request->post('amount'); + $data['status'] = $request->post('status'); + $data['reverse'] = $request->post('reverse'); + $data['remark'] = $request->post('remark'); + $data['sign'] = $request->post('sign'); + $result = (new XdPayService())->xdpayNotify($data); + return 'success'; + } + + public function XdPayAppNotify(Request $request) + { + Log::info('Xdpay代付回调:' . json_encode($_REQUEST)); + $data['platOrderId'] = $request->post('platOrderId'); + $data['orderId'] = $request->post('orderId'); + $data['amount'] = $request->post('amount'); + $data['status'] = $request->post('status'); + $data['reverse'] = $request->post('reverse'); + $data['remark'] = $request->post('remark'); + $data['sign'] = $request->post('sign'); + $result = (new XdPayService())->xdpayApplyNotify($data); + return 'success'; + } + + public function NicePayNotify(Request $request) + { + Log::info('NicePay代收回调:' . json_encode($_REQUEST)); + $data['amount'] = $request->post('amount'); + $data['order'] = $request->post('order'); + $data['status'] = $request->post('status'); + $data['sign'] = $request->post('sign'); + $result = (new NicePayService())->NicePayNotify($data); + return 'success'; + } + + public function NicePayApplyNotify(Request $request) + { + Log::info('NicePay代付回调:' . json_encode($_REQUEST)); + $data['amount'] = $request->post('amount'); + $data['order'] = $request->post('order'); + $data['status'] = $request->post('status'); + $data['sign'] = $request->post('sign'); + $result = (new NicePayService())->NicePayApplyNotify($data); + return 'success'; + } + + public function MoPayNotify(Request $request) + { + Log::info('MoPay代收回调:' . json_encode($_REQUEST)); + $data['memberid'] = $request->post('memberid'); + $data['orderid'] = $request->post('orderid'); + $data['transaction_id'] = $request->post('transaction_id'); + $data['amount'] = $request->post('amount'); + $data['datetime'] = $request->post('datetime'); + $data['returncode'] = $request->post('returncode'); + $data['attach'] = $request->post('attach'); + $data['sign'] = $request->post('sign'); + $result = (new MoPayService())->moPayNotify($data); + return 'ok'; + } + + public function moPayAppNotify(Request $request) + { + Log::info('Mopay代付回调:' . json_encode($_REQUEST)); + $data['memberid'] = $request->post('memberid'); + $data['orderid'] = $request->post('orderid'); + $data['transaction_id'] = $request->post('transaction_id'); + $data['amount'] = $request->post('amount'); + $data['datetime'] = $request->post('datetime'); + $data['returncode'] = $request->post('returncode'); + $data['attach'] = $request->post('attach'); + $data['sign'] = $request->post('sign'); + $result = (new MoPayService())->moPayApplyNotify($data); + return 'ok'; + } + + // QEAE支付回调 + public function QeaePayNotify(Request $request) + { + Log::info('Qeaepay支付回调:' . json_encode($_REQUEST)); + $data['tradeResult'] = $request->post('tradeResult'); + $data['orderNo'] = $request->post('orderNo'); + $data['mchId'] = $request->post('mchId'); + $data['mchOrderNo'] = $request->post('mchOrderNo'); + $data['oriAmount'] = $request->post('oriAmount'); + $data['amount'] = $request->post('oriAmount'); + $data['orderDate'] = $request->post('orderDate'); + $data['sign_type'] = $request->post('signType'); + $data['sign'] = $request->post('sign'); + $result = (new QeaePayService())->qeaePayNotify($data); + return 'success'; + } + + // QEAE代付回调 + public function QeaePayAppNotify(Request $request) + { + Log::info('Qeae代付回调:' . json_encode($_REQUEST)); + $data['tradeResult'] = $request->post('tradeResult'); + $data['merTransferId'] = $request->post('merTransferId'); // 商家转账订单号 + $data['merNo'] = $request->post('merNo'); + $data['tradeNo'] = $request->post('tradeNo'); + $data['transferAmount'] = $request->post('transferAmount'); + $data['applyDate'] = $request->post('applyDate'); + $data['version'] = $request->post('version'); + $data['respCode'] = $request->post('respCode'); + $data['sign'] = $request->post('sign'); + $data['sign_type'] = $request->post('signType'); + $result = (new QeaePayService())->qeaePayApplyNotify($data); + return 'success'; + } + + public function test(Request $request) + { +// $amount=1000; +// $order_no='ht'.rand(10000,99999); +// (new HTPayService())->arPay($order_no,$amount,'101','65243451224','test'); + (new TrcPayService())->getTrcBalance(); + + } + + // Click 代收(充值)回调 + public function ClickPayNotify() + { + $res = $this->request->param(); + Log::info('Clickpay 代收(充值)回调000:' . json_encode($res)); + $result = (new ClickPayService())->clickPayNotify($res); + return json($result); + } + + // Click 代付回调 + public function ClickPayApplyNotify(Request $request) + { + $res = $this->request->param(); + Log::info('Clickpay 代付回调000:' . json_encode($res)); + $result = (new ClickPayService())->clickPayApplyNotify($res); + return json($result); + } + +} \ No newline at end of file diff --git a/app/home/controller/PreStock.php b/app/home/controller/PreStock.php new file mode 100644 index 0000000..6798462 --- /dev/null +++ b/app/home/controller/PreStock.php @@ -0,0 +1,58 @@ +index($this->request->param()); + return json($result); + } + + // 新股列表 + public function stockDetail() + { + $service = new PreStockService(); + $result = $service->stockDetail($this->request->param()); + return json($result); + } + + // 申购下单 + public function order() + { + $service = new PreStockService(); + $result = $service->order($this->request->param(), $this->request->userId); + return json($result); + } + + // 申购记录 + public function list() + { + $service = new PreStockService(); + $result = $service->list($this->request->param(), $this->request->userId); + return json($result); + } + + // 申购记录详情 + public function detail() + { + $service = new PreStockService(); + $result = $service->detail($this->request->param(), $this->request->userId); + return json($result); + } + + // 后支付-付款 + public function postPay() + { + $service = new PreStockService(); + $result = $service->postPay($this->request->param(), $this->request->userId); + return json($result); + } +} \ No newline at end of file diff --git a/app/home/controller/Stock.php b/app/home/controller/Stock.php new file mode 100644 index 0000000..fc0346c --- /dev/null +++ b/app/home/controller/Stock.php @@ -0,0 +1,17 @@ +checkMarketStatus($this->request->param()); + return json($result); + } +} \ No newline at end of file diff --git a/app/home/controller/Team.php b/app/home/controller/Team.php new file mode 100644 index 0000000..ebf8f0b --- /dev/null +++ b/app/home/controller/Team.php @@ -0,0 +1,38 @@ +userId; + $result = (new TeamService())->getUserTeamCollect($user_id); + return json($result); + } + public function userTeamBack(Request $request): Json + { + $data['user_id']=$request->userId; + $data['level_type']=$request->post('level_type'); + $data['page']=$request->post('page'); + $data['page_size']=$request->post('page_size'); + $result = (new TeamService())->getUserTeamBack($data); + return json($result); + } + public function userTeamList(Request $request): Json + { + $data['user_id']=$request->userId; + $data['level_type']=$request->post('level_type'); + $data['page']=$request->post('page'); + $data['page_size']=$request->post('page_size'); + $result = (new TeamService())->getUserTeamList($data); + return json($result); + } + +} \ No newline at end of file diff --git a/app/home/controller/Upload.php b/app/home/controller/Upload.php new file mode 100644 index 0000000..6cda86b --- /dev/null +++ b/app/home/controller/Upload.php @@ -0,0 +1,76 @@ +request->file('file'); + // 参数校验 + validate(UploadValidate::class)->scene('uploadImage')->check(['image' => $file]); + // 将文件存储在本地 + $name = Filesystem::disk('local')->putFile('', $file); + $path = '/bs/image/'.$name; + // 入库 + $id = FileModel::insertFile($path, 2); + return json(['code' => '0', 'message' => 'Request successful.','data' => ['id' => $id]]); + }catch (ValidateException $validateException){ + // 参数校验失败 异常类 + $message = $validateException->getError(); + return json(['code' => '1004001', 'message' => $message]); + }catch (\Exception $exception){ + return json(['code' => '100500', 'message' => 'System error','data' => [$exception->getMessage(), $exception->getTrace(), $exception->getFile(),$filess]]); + } + } + public function uploadRechargeImage(): Json + { + try { + // 获取文件 + $file = $this->request->file('file'); + // 参数校验 + validate(UploadValidate::class)->scene('uploadImage')->check(['image' => $file]); + + // 将文件存储在本地 + $name = Filesystem::disk('local')->putFile('', $file); + $path = '/bs/image/'.$name; + + // 入库 + $id = FileModel::insertFile($path, 2); + return json(['code' => '0', 'message' => 'Request successful.','data' => ['id' => $id]]); + }catch (\Exception $exception){ + return json(['code' => '100500', 'message' => 'System error','data' => [$exception->getMessage()]]); + } + } + + public function getConfig(): Json + { + try { + $param = $this->request->param(); + if (empty($param['name'])) return json(['code' => '1', 'message' => '参数错误', 'data' => []]); + $name = $param['name']; + $value = ConfigModel::where('name', $name)->value('value'); + + return json(['code' => '0', 'message' => 'Request successful.', 'data' => ['value' => $value]]); + } catch (\Exception $exception) { + return json(['code' => '100500', 'message' => 'System error', 'data' => [$exception->getMessage()]]); + } + } +} \ No newline at end of file diff --git a/app/home/controller/User.php b/app/home/controller/User.php new file mode 100644 index 0000000..2ddc549 --- /dev/null +++ b/app/home/controller/User.php @@ -0,0 +1,303 @@ +getUserInfo($this->request->userId); + return json($returnData); + } + + /** + * @desc 设置用户国家 + * @return Json + */ + public function setCountry(): Json + { + $returnData = (new UserService())->setCountry($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 更新用户头像 + * @return Json + */ + public function updateHeadImg(): Json + { + $returnData = (new UserService())->updateHeadImg($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 设置 昵称 姓名 性别 + * @return Json + */ + public function updateInfo(): Json + { + $returnData = (new UserService())->updateInfo($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 登陆状态获取邮件 + * @return Json + */ + public function sendEmail(): Json + { + $returnData = (new UserService())->sendEmail($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 登陆后发送短信 + * @return Json + */ + public function sendSms(): Json + { + $returnData = (new UserService())->sendSms($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 通过邮箱 设置取款密码 + * @return Json + */ + public function setPayPasswordByEmail(): Json + { + $returnData = (new UserService())->setPayPasswordByEmail($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 通过短信 设置取款密码 + * @return Json + */ + public function setPayPasswordBySms(): Json + { + $returnData = (new UserService())->setPayPasswordBySms($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 通过短信修改交易密码 + * @return Json + */ + public function updatePayPasswordBySms() + { + $returnData = (new UserService())->updatePayPasswordBySms($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 通过邮箱修改交易密码 + * @return Json + */ + public function updatePayPasswordByEmail() + { + $returnData = (new UserService())->updatePayPasswordByEmail($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 短信重新设置交易密码 + * @return Json + * @throws InvalidArgumentException + */ + public function resetPayPasswordBySms() + { + $returnData = (new UserService())->resetPayPasswordBySms($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 通过邮箱重新设置交易密码 + * @return Json + * @throws InvalidArgumentException + */ + public function resetPayPasswordByEmail() + { + $returnData = (new UserService())->resetPayPasswordByEmail($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 短信修改登陆密码 + * @return Json + */ + public function updatePasswordBySms() + { + $returnData = (new UserService())->updatePasswordBySms($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 邮箱修改登陆密码 + * @return Json + * @throws InvalidArgumentException + */ + public function updatePasswordByEmail() + { + $returnData = (new UserService())->updatePasswordByEmail($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 短信重新设置登陆密码 + * @return Json + */ + public function resetPasswordBySms() + { + $returnData = (new UserService())->resetPasswordBySms($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 邮箱设置登陆密码 + * @return Json + */ + public function resetPasswordByEmail() + { + $returnData = (new UserService())->resetPasswordByEmail($this->request->userId, $this->request->post()); + return json($returnData); + } + + + /** + * @desc 绑定邮箱 + * @return Json + */ + public function bindEmail(): Json + { + $returnData = (new UserService())->bindEmail($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 修改已经绑定的邮箱 + * @return Json + * @throws InvalidArgumentException + */ + public function updateEmail(): Json + { + $returnData = (new UserService())->updateEmail($this->request->userId, $this->request->post()); + return json($returnData); + } + + + /** + * @desc 绑定手机号 + * @return Json + */ + public function bindPhone(): Json + { + $returnData = (new UserService())->bindPhone($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc + * @return Json + * @throws InvalidArgumentException + */ + public function updatePhone(): Json + { + $returnData = (new UserService())->updatePhone($this->request->userId, $this->request->post()); + return json($returnData); + } + + + /** + * @desc + * @return Json + * @throws InvalidArgumentException + */ + public function apply_loan(): Json + { + $returnData = (new UserService())->apply_loan($this->request->userId, $this->request->post()); + return json($returnData); + } + + + /** + * @desc + * @return Json + * @throws InvalidArgumentException + */ + public function loan(): Json + { + $returnData = (new UserService())->loan($this->request->userId, $this->request->post()); + return json($returnData); + } + + /** + * @desc 退出登陆 + * @return Json + */ + public function logout(): Json + { + $returnData = (new UserService())->logout($this->request->userId); + return json($returnData); + } + + /** + * @desc 获取登陆信息 + * @return Json + */ + public function loginLog(): Json + { + $returnData = (new UserService())->loginLog($this->request->userId); + return json($returnData); + } + + /** + * 获取时间 + * @return Json + */ + public function getTime() + { + return json(['code' => '0', + 'message' => 'SUCCESS', + 'data' => ['time' => 259200]]); + } + + /** + * @desc 杠杆状态 + * @return Json + */ + public function leverApply(): Json + { + $returnData = (new UserService())->leverApply($this->request->userId); + return json($returnData); + } + public function applyTest(): Json + { + $returnData = (new UserService())->applyTestAccount($this->request->userId); + return json($returnData); + } + public function applyTestMoney(): Json + { + $returnData = (new UserService())->applyTestMoney($this->request->userId,$this->request->post()); + return json($returnData); + } + public function testLogin(): Json + { + $returnData = (new UserService())->testLogin($this->request->userId); + return json($returnData); + } + public function formalLogin(): Json + { + $returnData = (new UserService())->formalLogin($this->request->userId); + return json($returnData); + } +} \ No newline at end of file diff --git a/app/home/controller/UserVerify.php b/app/home/controller/UserVerify.php new file mode 100644 index 0000000..e895e3a --- /dev/null +++ b/app/home/controller/UserVerify.php @@ -0,0 +1,24 @@ +add($this->request->post(),$this->request->userId); + return json($returnData); + } + + + // 实名认证详细信息 + public function detail() + { + $returnData = (new UserVerifyService())->detail($this->request->userId); + return json($returnData); + } +} \ No newline at end of file diff --git a/app/home/controller/Vote.php b/app/home/controller/Vote.php new file mode 100644 index 0000000..a6aca0f --- /dev/null +++ b/app/home/controller/Vote.php @@ -0,0 +1,76 @@ +order('sort', 'asc') + ->select(); + + return json([ + 'code' => '0', + 'message' => 'Request successful.', + 'data' => $list, + ]); + } + + public function cheer(Request $request): Json + { + $param = $this->request->param(); + if (empty($param['id']) || empty($this->request->userId)) { + return json([ + 'code' => '1', + 'message' => 'Error', + 'data' => [], + ]); + } + + $vote = VoteModel::find($param['id']); + if (empty($vote)) { + return json([ + 'code' => '1', + 'message' => 'Error', + 'data' => [], + ]); + } + $onedayTimes = $vote->oneday_times; + $todayStart = date('Y-m-d 00:00:00'); + $todayEnd = date('Y-m-d 23:59:59'); + + $times = UserVoteModel::where('vote_id', $param['id'])->where('user_id', $this->request->userId)->where('create_time', '<=', $todayEnd)->where('create_time', '>=', $todayStart)->count(); + if ($times >= $onedayTimes) { + return json([ + 'code' => '1', + 'message' => 'You have already cast your vote today', + 'data' => [], + ]); + } + + $vote->score_num = $vote->score_num + 1; + $vote->save(); + + UserVoteModel::insert( + [ + 'vote_id' => $param['id'], + 'user_id' => $this->request->userId, + 'create_time' => date('Y-m-d H:i:s') + ] + ); + + return json([ + 'code' => '0', + 'message' => 'Request successful.', + 'data' => [], + ]); + } +} \ No newline at end of file diff --git a/app/home/controller/Wallet.php b/app/home/controller/Wallet.php new file mode 100644 index 0000000..2d4ccc2 --- /dev/null +++ b/app/home/controller/Wallet.php @@ -0,0 +1,299 @@ +userId; + $account_type=$request->post('account_type',0); + $result = (new WalletService())->getUserAssets($user_id,$account_type); + return json($result); + } + + + public function userRechargeList(Request $request): Json + { + $data['user_id']=$request->userId; + $data['account_type']=$request->post('account_type'); + $data['page']=$request->post('page'); + $data['page_size']=$request->post('page_size'); + $result = (new WalletService())->getUserRechargeList($data); + return json($result); + } + + /** + * 用户添加钱包地址 + * @param Request $request + * @return Json + */ + public function addWalletAddress(Request $request): Json + { + $data['user_id']=$request->userId; + $data['wallet_type']=$request->post('wallet_type'); + $data['wallet_address']=$request->post('wallet_address'); + $data['remark']=$request->post('remark'); + $data['adr_id']=$request->post('address_id'); + $data['is_default']=$request->post('is_default'); + + $result=(new WalletService())->insertWalletAdress($data); + return json($result); + } + + /** + * 获取用户钱包地址列表 + * @param Request $request + * @return Json + */ + public function getWalletAddress(Request $request): Json + { + $data['user_id']=$request->userId; + $data['page']=$request->post('page'); + $data['page_size']=$request->post('page_size'); + $data['wallet_type']=$request->post('wallet_type'); + $result=(new WalletService())->getUserWalletAddress($data); + return json($result); + } + + /** + * 获取用户钱包地址详情 + * @param Request $request + * @return Json + */ + public function getWalletAddressInfo(Request $request): Json + { + $data['user_id']=$request->userId; + $data['adr_id']=$request->post('address_id',0); + $result=(new WalletService())->getUserWalletAddressInfo($data); + return json($result); + } + + /** + * 删除用户钱包地址 + * @param Request $request + * @return Json + * @throws \think\db\exception\DbException + */ + public function delWalletAddress(Request $request): Json + { + $data['user_id']=$request->userId; + $data['adr_id']=$request->post('address_id'); + $result=(new WalletService())->delUserWalletAddress($data); + return json($result); + } + + /** + * 获取银行卡列表 + * @param Request $request + * @return Json + */ + public function getUserBank(Request $request): Json + { + $data['user_id']=$request->userId; + $data['page']=$request->post('page'); + $data['page_size']=$request->post('page_size'); + $result=(new WalletService())->getUserBank($data); + return json($result); + } + + /** + * + * @param Request $request + * @return Json + */ + public function getUserBankInfo(Request $request): Json + { + $data['user_id']=$request->userId; + $data['id']=$request->post('id'); + $result=(new WalletService())->getUserBankInfo($data); + return json($result); + } + /** + * 添加编辑银行卡 + * @param Request $request + * @return Json + */ + public function addUserBank(Request $request): Json + { + $data['user_id']=$request->userId; + $data['id']=$request->post('id'); + $data['true_name']=$request->post('true_name'); + $data['identity_card']=$request->post('identity_card'); + $data['bank_card']=$request->post('bank_card'); + $data['bank_name']=$request->post('bank_name'); + $data['bank_email']=$request->post('bank_email'); + $data['bank_phone']=$request->post('bank_phone'); + $data['bank_code']=$request->post('bank_code'); + $data['branch_name']=$request->post('branch_name'); + $data['branch_phone']=$request->post('branch_phone'); + $data['is_default']=$request->post('is_default'); + $data['ifsc']=$request->post('ifsc'); + $data['bank_address']=$request->post('bank_address'); + $data['user_address']=$request->post('user_address'); + $data['bank_country']=$request->post('bank_country'); + $result=(new WalletService())->insertUserBank($data); + return json($result); + } + + /** + * 删除银行卡 + * @param Request $request + * @return Json + */ + public function delUserBank(Request $request): Json + { + $data['user_id']=$request->userId; + $data['id']=$request->post('id'); + $result=(new WalletService())->delUserBank($data); + return json($result); + } + + /** + * 获取用户账户可用余额 + * @param Request $request + * @return Json + */ + public function getUserBalance(Request $request): Json + { + $data['user_id']=$request->userId; + $data['account_type']=$request->post('account_type'); + $data['trade_name']=$request->post('trade_name'); + $result=(new WalletService())->getUserBalance($data); + return json($result); + } + + public function drawalFee(Request $request): Json + { + $account_type=$request->post('account_type',0,'intval'); + $result=(new WalletService())->getDrawalFee($account_type); + return json($result); + } + + /** + * 用户提款申请 + * @param Request $request + * @return Json + */ + public function drawalApply(Request $request): Json + { + $data['user_id']=$request->userId; + $data['account_type']=$request->post('account_type'); + $data['apply_num']=$request->post('apply_num'); + $data['apply_type']=$request->post('apply_type'); + $data['bank_id']=$request->post('bank_id'); + $data['address_id']=$request->post('address_id'); + $data['wallet_address']=$request->post('wallet_address'); + $data['drawal_type']=$request->post('drawal_type'); + $data['trade_pwd']=$request->post('trade_pwd'); + $data['country']=$request->post('country'); + + $result=(new WalletService())->dealDrawalApply($data); + return json($result); + } /** + * 用户提款申请 + * @param Request $request + * @return Json + */ + public function canncelDrawalApply(Request $request): Json + { + $data['user_id']=$request->userId; + $data['order_no']=$request->post('order_no'); + $result=(new WalletService())->canncelDrawalApply($data); + return json($result); + } + public function userDrawalList(Request $request): Json + { + $data['user_id']=$request->userId; + $data['account_type']=$request->post('account_type'); + $data['page']=$request->post('page'); + $data['page_size']=$request->post('page_size'); + $result=(new WalletService())->getDrawalList($data); + return json($result); + } + + /** + * 获取用户资金明细数据 + * @param Request $request + * @return Json + */ + public function UserBalanceRecord(Request $request): Json + { + $data['user_id']=$request->userId; + $data['account_type']=$request->post('account_type'); + $data['page']=$request->post('page'); + $data['page_size']=$request->post('page_size'); + $result=(new WalletService())->getUserBalanceRecord($data); + return json($result); + } + + /** + * 处理用户资金账户相互划转接口 + * @param Request $request + * @return Json + */ + public function userTransfer(Request $request): Json + { + $data['user_id']=$request->userId; + $data['from_account']=$request->post('from_account'); + $data['to_account']=$request->post('to_account'); + $data['change_num']=$request->post('change_num'); + $result=(new WalletService())->doUserTransfer($data); + return json($result); + } + public function userRechargeWallet(Request $request): Json + { + $data['user_id']=$request->userId; + $data['wallet_type']=$request->post('wallet_type'); + $result=(new WalletService())->getUserRechargeWallet($data); + return json($result); + } + + /** + * 获取用户划转资金明细 + * @param Request $request + * @return Json + */ + public function userTransferRecord(Request $request): Json + { + $data['user_id']=$request->userId; + $data['page']=$request->post('page'); + $data['page_size']=$request->post('page_size'); + $result=(new WalletService())->getUserTransfer($data); + return json($result); + } + public function userHasNotPay(Request $request):Json + { + $data['user_id']=$request->userId; + $data['market_type']=$request->post('market_type'); + $result=(new WalletService())->userHasNotPay($data); + return json($result); + } + public function dealUnPayIPO(Request $request):Json + { + $data['user_id']=$request->userId; + $data['market_type']=$request->post('market_type'); + $result=(new WalletService())->dealUnPayIPO($data); + return json($result); + } + + + // 获取用户账户之间划转的费率 支持计算具体值 + public function getRateToTransfer() + { + $result=(new WalletService())->getRateToTransfer($this->request->param()); + return json($result); + } + +} \ No newline at end of file diff --git a/app/home/job/LoginDone.php b/app/home/job/LoginDone.php new file mode 100644 index 0000000..bf5f378 --- /dev/null +++ b/app/home/job/LoginDone.php @@ -0,0 +1,68 @@ + $lastLoginTime], $userId); + }catch (\Exception $exception){ + trace('---用户登陆记录写入异常---'.$exception->getMessage(), 'error'); + } + + try { + $countryNameStr = ''; + $cityNameStr = ''; + + try { + $countryDb = base_path().'GeoLite2-Country.mmdb'; + $cityDb = base_path().'GeoLite2-City.mmdb'; + $countryReader = new Reader($countryDb); + $cityReader = new Reader($cityDb); + $countryNames = $countryReader->country($ip)->country->names; + $cityNames = $cityReader->city($ip)->city->names; + + $countryNameStr = json_encode([ + 'cn' => $countryNames['zh-CN']?? '', + 'en' => $countryNames['en']?? '', + ]); + + $cityNameStr = json_encode([ + 'cn' => $cityNames['zh-CN'] ?? '', + 'en' => $cityNames['en'] ?? '', + ]); + + }catch (\Exception $exception){ + trace('---用户登陆ip记录解析异常---data--'.json_encode([$data]).'-------'.$exception->getMessage(), 'error'); + } + + UserLoginLog::addData($userId,$device,$ip,$countryNameStr,$cityNameStr,$lastLoginTime); + + }catch (\Exception $exception){ + trace('---用户登陆ip记录写入异常---data--'.json_encode([$data]).'-------'.$exception->getMessage(), 'error'); + } + + $job->delete(); + } +} \ No newline at end of file diff --git a/app/home/job/SendEmail.php b/app/home/job/SendEmail.php new file mode 100644 index 0000000..8058134 --- /dev/null +++ b/app/home/job/SendEmail.php @@ -0,0 +1,47 @@ +sendEmail($data['email'], $data['title'], $data['subject']); + if ($bool) { + $success = true; + break; + } + + trace($job->getJobId().'---重试-----'.$times, 'info'); + } + + // 任务失败 + if (!$success) { + trace($job->getJobId().'---失败-------'.json_encode($data), 'info'); + } + + // 删除任务 + $job->delete(); + } + + public function failed($data) + { + // 失败任务 + $dataStr = json_encode($data); + trace('queue job 任务失败---'.$dataStr, 'error'); + } +} \ No newline at end of file diff --git a/app/home/job/SendSms.php b/app/home/job/SendSms.php new file mode 100644 index 0000000..570b69a --- /dev/null +++ b/app/home/job/SendSms.php @@ -0,0 +1,71 @@ + $conArr[0], + 'secret' => $conArr[1] + ]; + } + return $config; + } + + /** + * @desc 发送短信验证码 + * @param Job $job + * @param $data + * @return void + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function fire(Job $job, $data) + { + trace($job->getJobId().'---执行短信任务--------'.json_encode($data), 'info'); + + $config = $this->getConfig(); + if(empty($config)){ + trace('------- sms config empty -------', 'error'); + return; + } + + $key = "SMS:SEND:LAST_ACCESS_KEY"; + $lastUse = Cache::store('redis')->get($key); + $count = count($config); + if(empty($lastUse) || $lastUse >= ($count -1)){ + $nowKey = 0; + } else { + $nowKey = $lastUse++; + } + $to = $data['mobile']; + $message = $data['subject']; + $accessKey = $config[$nowKey]['access_key']; + $secret = $config[$nowKey]['secret']; + Cache::store('redis')->set($key, $nowKey); + + (new \app\utility\SendSms())->send($to, $message, $accessKey, $secret); + // 删除任务 + $job->delete(); + } + + public function failed($data) + { + } +} \ No newline at end of file diff --git a/app/home/job/Wallet.php b/app/home/job/Wallet.php new file mode 100644 index 0000000..a97f8d2 --- /dev/null +++ b/app/home/job/Wallet.php @@ -0,0 +1,33 @@ +WalletAddress(); + if(!empty($result)){ + break; + } + trace($job->getJobId().'---获取钱包任务-----'.$times, 'info'); + } + // 删除任务 + $job->delete(); + } + + public function failed($data) + { + // 失败任务 + $dataStr = json_encode($data); + trace('queue job 获取钱包任务失败---'.$dataStr, 'error'); + } +} \ No newline at end of file diff --git a/app/home/middleware/AuthMiddleware.php b/app/home/middleware/AuthMiddleware.php new file mode 100644 index 0000000..3674cb8 --- /dev/null +++ b/app/home/middleware/AuthMiddleware.php @@ -0,0 +1,67 @@ +method(true) === 'OPTIONS') { + return response()->send(); + } + $header = $request->header(); + if(!isset($header['language'])){ + $request->lang=Config::get('lang.default_lang'); + }else{ + $lang_list=Config::get('lang.allow_lang_list'); + $lang=strtolower($header['language']); + if(in_array($lang,$lang_list)){ + $request->lang=$lang; + }else{ + $request->lang=Config::get('lang.default_lang'); + } + } + if(empty($header['token'])){ + return json(['code' => '100403', 'message' => 'login please','data' => []]); + } + if(!is_string($header['token'])){ + return json(['code' => '100403', 'message' => 'login please','data' => []]); + } + + $tokenUserKey = 'TOKEN:USER:'.$header['token']; + $userId = Cache::store('redis')->get($tokenUserKey); + if(empty($userId) || $userId <= 0){ + return json(['code' => '100403', 'message' => 'login please','data' => []]); + } + + // 查找用户信息 + $user = UserModel::getFieldsByUserId('status,user_id', $userId); + if(empty($user)){ + return json(['code' => '100403', 'message' => 'no user','data' => []]); + } + + if($user['status'] != UserModel::STATUS_ON){ + return json(['code' => '100403', 'message' => 'no auth','data' => []]); + } + + $request->userId = $userId; + $userTokenKey = 'USER:TOKEN:'.$request->userId; + + $expire = 30 * 24 * 60 * 60; + Cache::store('redis')->set($userTokenKey, $header['token'], $expire); + Cache::store('redis')->set($tokenUserKey, $request->userId, $expire); + return $next($request); + + } +} \ No newline at end of file diff --git a/app/home/middleware/CorsMiddleware.php b/app/home/middleware/CorsMiddleware.php new file mode 100644 index 0000000..f1114e1 --- /dev/null +++ b/app/home/middleware/CorsMiddleware.php @@ -0,0 +1,26 @@ + 'true', + 'Access-Control-Max-Age' => 1800, + 'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With,Token,Language', + ]; + public function handle($request, Closure $next, ?array $header = []) + { + header('Access-Control-Allow-Origin: *' ); + header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS'); + header('Access-Control-Allow-Headers: Content-Type, Authorization,Accpet,Token,Language'); + header('Access-Control-Max-Age: 86400'); + header('Access-Control-Allow-Credentials: true'); + return parent::handle($request, $next, $header); // TODO: Change the autogenerated stub + } + +} + diff --git a/app/home/middleware/RepeatOperateMiddleware.php b/app/home/middleware/RepeatOperateMiddleware.php new file mode 100644 index 0000000..0c93214 --- /dev/null +++ b/app/home/middleware/RepeatOperateMiddleware.php @@ -0,0 +1,48 @@ +method(true) === 'OPTIONS') { + return response()->send(); + } + + $header = $request->header(); + if(!isset($header['language'])){ + $request->lang=Config::get('lang.default_lang'); + }else{ + $lang_list=Config::get('lang.allow_lang_list'); + $lang=strtolower($header['language']); + if(in_array($lang,$lang_list)){ + $request->lang=$lang; + }else{ + $request->lang=Config::get('lang.default_lang'); + } + } + //echo $request->lang; + $ip = (new BaseHomeService())->getClientRealIp(); + $url = $request->url(); + $key = 'REPEAT_OPERATE_'.$url.'_'.$ip; + if(Cache::store('redis')->has($key)){ + return json(['code' => '100403', 'message' => 'repeated','data' => []]); + } + + //Cache::store('redis')->set($key, 1, 2); + return $next($request); + + } +} \ No newline at end of file diff --git a/app/home/route/app.php b/app/home/route/app.php new file mode 100644 index 0000000..cb9edc5 --- /dev/null +++ b/app/home/route/app.php @@ -0,0 +1,286 @@ + +// +---------------------------------------------------------------------- +use think\facade\Route; + +$header = [ + 'Access-Control-Allow-Credentials' => 'true', + 'Access-Control-Max-Age' => 1800, + 'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With,Token,Language,X-token', +]; + +/** + * 不需要登陆的路由 + */ +Route::group('/',function (){ + Route::group('/',function (){ + // 邮箱 登录 + Route::post('/email_login', 'Login/loginEmail'); + // 发送邮件 + Route::post('/email', 'Login/sendEmail'); + // 邮箱注册 + Route::post('/email_reg', 'Login/registerEmail'); + // 发送短信 + Route::post('/sms', 'Login/sendSms'); + //短信注册 + Route::post('/sms_reg', 'Login/registerSms'); + //短信登陆 + Route::post('/sms_login', 'Login/loginSms'); + //通过邮箱重新设置密码 + Route::post('/forget_email', 'Login/resetPasswordByEmail'); + //通过短信重新设置密码 + Route::post('/forget_sms', 'Login/resetPasswordBySms'); + // 手机号密码登陆 + Route::post('/phone_login', 'Login/phoneLogin'); + + // 获取配置 + Route::post('/get_config', 'Upload/getConfig'); + + })->middleware(\app\home\middleware\RepeatOperateMiddleware::class); + // 获取帮助中心文档 + Route::post('/faq_index', 'Faq/index'); + Route::post('/faq_detail', 'Faq/detail'); + Route::post('/banner_index', 'Carousel/index'); + Route::post('/banner_detail', 'Carousel/detail'); + Route::post('/announcement_index', 'Announcement/index'); + Route::post('/announcement_detail', 'Announcement/detail'); + + Route::post('/doc_platform', 'Document/getPlatform'); + Route::post('/doc_pc', 'Document/getDocPc'); + Route::post('/doc_detail', 'Document/detail'); + Route::post('/doc', 'Document/getDoc'); + + // 国家和地区 + Route::post('/country', 'Country/getAll'); + // 获取首页广告图 + Route::post('/carousal', 'Carousel/getCarousel'); + Route::post('/market', 'Market/marketList'); + Route::post('/market_rate', 'Market/marketRate'); + Route::post('/market_trade', 'Market/marketTradeList'); + Route::post('/trade_type', 'Market/TradeTypeList'); + Route::post('/face_list', 'Market/ContractFaceList'); + Route::post('/face_forex', 'Market/ForexFaceList'); + + Route::post('/lang', 'Language/langList'); + Route::post('/service', 'Language/serviceList'); + Route::post('/init_data', 'Language/initRedisData'); + + // 获取股票市场状态 + Route::post('/stock/check_status', 'Stock/checkMarketStatus'); + + + //Route::post('payment_test', 'Pay/test'); //获取充值渠道 + Route::post('indpay_notify', 'Pay/indPayNotify')->name('indpay_notify'); //支付异步通知地址 + Route::post('indpay_query', 'Pay/indPayQuery')->name('indpay_query'); //支付同步通知地址 + Route::post('single_notify', 'Pay/singleNotify')->name('single_notify'); + + //数字币充值 + Route::post('pay_notify', 'Pay/payNotify')->name('pay_notify'); //充值通知接口 + Route::post('order_confirm', 'Pay/OrderConfirm')->name('order_confirm'); //充值通知接口 + Route::get('get_wallet', 'Pay/wallet')->name('get_wallet');//获取钱包地址 + Route::post('htpay_notify', 'Pay/htPayNotify')->name('htpay_notify'); //充值通知接口 + Route::post('arpay_notify', 'Pay/arPayNotify')->name('arpay_notify'); //充值通知接口 + + Route::post('xdpay_notify', 'Pay/XdPayNotify')->name('xdpay_notify'); //充值通知接口 + Route::post('xdpay_anotify', 'Pay/XdPayAppNotify')->name('xdpay_anotify'); //充值通知接口 + + Route::post('qeaepay_notify', 'Pay/QeaePayNotify')->name('qeaepay_notify'); //充值通知接口 + Route::post('qeaepay_appNotify', 'Pay/QeaePayAppNotify')->name('qeaepay_appNotify'); //充值通知接口 + + Route::post('xdpay_notify', 'Pay/XdPayNotify')->name('xdpay_notify'); //充值通知接口 + Route::post('xdpay_anotify', 'Pay/XdPayAppNotify')->name('xdpay_anotify'); //充值通知接口 + + Route::post('mopay_notify', 'Pay/MoPayNotify')->name('mopay_notify'); //充值通知接口 + Route::post('mopay_anotify', 'Pay/MoPayAppNotify')->name('mopay_anotify'); //充值通知接口 + + Route::post('nicepay_notify', 'Pay/NicePayNotify')->name('nicepay_notify'); + Route::post('nicepay_anotify', 'Pay/NicePayApplyNotify')->name('nicepay_anotify'); + + Route::post('clickpay_notify', 'Pay/ClickPayNotify')->name('clickpay_notify'); //充值通知接口 + Route::post('clickpay_ApplyNotify', 'Pay/ClickPayApplyNotify')->name('clickpay_appNotify'); //充值通知接口 + + Route::post('starpay_notify', 'Pay/starPayNotify')->name('starpay_notify'); //充值通知接口 + Route::post('starpay_ApplyNotify', 'Pay/ClickPayApplyNotify')->name('starpay_appNotify'); //充值通知接口 + + + Route::post('payment_test', 'Pay/test'); + + Route::post('bank_list', 'Pay/BankList'); + + // 需要登陆的操作 + Route::group('/',function (){ + // 上传用户头像 + Route::post('upload_header', 'Upload/uploadHeaderImage'); + // 需要防止重复操作的路由 + Route::group('', function () { + // 设置国家码 + Route::post('user/set_country', 'User/setCountry'); + + // 设置用户头像 + Route::post('head_update', 'User/updateHeadImg'); + // 登陆状态获取邮箱验证码 + Route::post('user/email_send', 'User/sendEmail'); + // 登陆状态获取邮箱验证码 + Route::post('user/sms_send', 'User/sendSms'); + // 设置用户信息 + Route::post('user/update_info', 'User/updateInfo'); + + + // 邮箱修改支付密码 + Route::post('user/update_pay_password_email', 'User/updatePayPasswordByEmail'); + // 短信修改支付密码 + Route::post('user/update_pay_password_sms', 'User/updatePayPasswordBySms'); + // 邮箱修改支付密码-忘记密码 + Route::post('user/reset_pay_password_email', 'User/resetPayPasswordByEmail'); + // 短信修改支付密码-忘记密码 + Route::post('user/reset_pay_password_sms', 'User/resetPayPasswordBySms'); + + // 邮箱修改密码 + Route::post('user/update_password_email', 'User/updatePasswordByEmail'); + // 短信修改密码 + Route::post('user/update_password_sms', 'User/updatePasswordBySms'); + // 邮箱修改密码-忘记密码 + Route::post('user/reset_password_email', 'User/resetPasswordByEmail'); + // 短信修改密码-忘记密码 + Route::post('user/reset_password_sms', 'User/resetPasswordBySms'); + + // 邮件 设置支付密码 + Route::post('user/pay_password_email_set', 'User/setPayPasswordByEmail'); + // 短信 设置支付密码 + Route::post('user/pay_password_sms_set', 'User/setPayPasswordBySms'); + + // 绑定邮箱 + Route::post('user/bind_email', 'User/bindEmail'); + Route::post('user/update_email', 'User/updateEmail'); + // 绑定手机号 + Route::post('user/bind_phone', 'User/bindPhone'); + Route::post('user/update_phone', 'User/updatePhone'); + + // 新增实名认证 + Route::post('user_verify/add', 'UserVerify/add'); + + + })->middleware(\app\home\middleware\RepeatOperateMiddleware::class); + + // 新增实名认证 + Route::post('user_verify/detail', 'UserVerify/detail'); + + // 获取时间 + Route::post('user/get_time', 'User/getTime'); + // 获取用户基础信息 + Route::post('user/info', 'User/getUserInfo'); + // 获取登陆记录 + Route::post('user/login_log', 'User/loginLog'); + // 退出登陆 + Route::post('user/log_out', 'User/logout'); + //申请模拟账号 + Route::post('user/apply_test', 'User/applyTest'); + Route::post('user/test_login', 'User/testLogin'); + Route::post('user/formal_login', 'User/formalLogin'); + + + Route::post('payment_list', 'Pay/payChannel'); //获取充值渠道 + Route::post('user_recharge', 'Pay/rechargeApply')->middleware(\app\home\middleware\RepeatOperateMiddleware::class); // 用户申请充值接口 防止重复操作 + + Route::post('user_assets', 'Wallet/getAllAssets'); // 获取用户所有资产列表数据 + Route::post('user_balance', 'Wallet/getUserBalance'); // 获取用户所有资产列表数据 + Route::post('balance_record', 'Wallet/UserBalanceRecord'); // 获取用户资金明细数据 + + Route::post('recharge_list', 'Wallet/userRechargeList'); + Route::post('recharge_wallet', 'Wallet/userRechargeWallet'); + Route::post('upload_recharge', 'Upload/uploadRechargeImage'); + + Route::post('transfer', 'Wallet/userTransfer')->middleware(\app\home\middleware\RepeatOperateMiddleware::class); // 用户资金划转接口 + Route::post('transfer_list', 'Wallet/userTransferRecord'); // 用户资金划转接口 + + Route::post('user_drawal', 'Wallet/drawalApply')->middleware(\app\home\middleware\RepeatOperateMiddleware::class); // 用户申请提现接口 + Route::post('canncel_drawal', 'Wallet/canncelDrawalApply')->middleware(\app\home\middleware\RepeatOperateMiddleware::class); // 用户申请提现接口 + Route::post('drawal_fee', 'Wallet/drawalFee'); // 用户提现手续费接口 + Route::post('drawal_list', 'Wallet/userDrawalList'); // 用户提现手续费接口 + + Route::post('trc20_list', 'Pay/getTRC20BuyList'); // TRC20 + + Route::post('add_bank', 'Wallet/addUserBank'); // 用户添加银行卡 + Route::post('user_bank', 'Wallet/getUserBank'); // 获取用户银行卡列表 + Route::post('bank_info', 'Wallet/getUserBankInfo'); // 获取用户银行卡详情 + Route::post('del_bank', 'Wallet/delUserBank'); // 删除用户银行卡 + Route::post('add_wallet_address', 'Wallet/addWalletAddress'); // 用户添加钱包地址 + Route::post('wallet_address', 'Wallet/getWalletAddress'); // 获取用户钱包地址列表 + Route::post('del_wallet_address', 'Wallet/delWalletAddress'); // 删除用户钱包地址 + Route::post('get_wallet_address', 'Wallet/getWalletAddressInfo'); // 获取用户钱包地址详情 + + Route::post('get_transfer_rate', 'Wallet/getRateToTransfer'); // 获取用户账户之间划转的费率 支持计算具体值 + + Route::post('user_market', 'Market/userMarket'); // 获取用户自选数据 + Route::post('add_market', 'Market/addMarket'); // 添加用户自选数据 + Route::post('del_market', 'Market/delMarket'); // 删除用户自选数据 + Route::post('is_collect', 'Market/MarketCollect'); // 删除用户自选数据 + Route::post('trade_fee', 'Market/tradeFee'); + Route::post('contract_setting', 'Market/ContractSetting'); + + Route::post('team_collect', 'Team/userTeamCollect');// 获取团队汇总 + Route::post('team_back', 'Team/userTeamBack'); // 获取团队人数 + Route::post('team_list', 'Team/userTeamList'); // 获取团队人数 + // 根据邮箱重新设置密码 + Route::post('user/reset_pwd_email', 'User/resetPasswordByEmail'); + Route::post('user/lever_apply', 'User/leverApply'); + + Route::post('apply_test_money', 'User/applyTestMoney'); + + + // 股票申购 + Route::post('pre_stock/order', 'PreStock/order')->middleware(\app\home\middleware\RepeatOperateMiddleware::class); // 新股下单 防止重复操作 + Route::post('pre_stock/post_pay', 'PreStock/postPay')->middleware(\app\home\middleware\RepeatOperateMiddleware::class); // 新股下单后支付 - 订单支付 + Route::post('pre_stock/list', 'PreStock/list'); + Route::post('pre_stock/detail', 'PreStock/detail'); + + // 基金订单 + Route::post('fund/order', 'Fund/order')->middleware(\app\home\middleware\RepeatOperateMiddleware::class); + Route::post('fund/user_fund', 'Fund/userFund'); + Route::post('fund/detail', 'Fund/detail'); + Route::post('fund/history', 'Fund/history'); + + Route::post('has_pay', 'Wallet/userHasNotPay'); + Route::post('pay_ipo', 'Wallet/dealUnPayIPO'); + + //大宗交易 + Route::post('block/index', 'Block/index'); //大宗交易商品列表 + Route::post('block/list', 'Block/list'); //大宗交易订单 + + //投票 + Route::post('vote/index', 'Vote/index'); + Route::post('vote/cheer', 'Vote/cheer'); + //贷款 + Route::post('user/apply_loan', 'User/apply_loan'); + Route::post('user/loan', 'User/loan'); + + + })->middleware(\app\home\middleware\AuthMiddleware::class); + // 美股申购列表 不需要登陆 + Route::post('pre_stock/index', 'PreStock/index'); + Route::post('pre_stock/stock_detail', 'PreStock/stockDetail'); + + //基金 + Route::post('fund/index', 'Fund/index'); + Route::post('auto_login', 'Login/autoLogin'); + + Route::post('get_ip', 'Login/getIP'); + Route::get('get_news', 'News/index'); + Route::get('test', 'News/test'); + + +})->allowCrossDomain($header); + + + + + + diff --git a/app/home/service/BaseHomeService.php b/app/home/service/BaseHomeService.php new file mode 100644 index 0000000..d7aabda --- /dev/null +++ b/app/home/service/BaseHomeService.php @@ -0,0 +1,958 @@ + $code, + 'message' => $msg, + 'data' => $result + ]; + } + public function __construct() + { + //$this->redis=$this->getRedis(); + //$this->getTrcWalletAddress(); + } + + /** + * + */ + private function getTrcWalletAddress() + { + $redis_key="TRCWallet"; + $num=WalletListModel::where([ + 'user_id'=>0, + 'wallet_type'=>'TRC-20' + ])->count(); + $flag=Cache::store('redis')->exists($redis_key); + if($num<50 && empty($flag)){ + Cache::store('redis')->setex($redis_key,120,2); + $queuename = 'app\home\job\Wallet'; + Queue::push($queuename, "test", 'Wallet'); + } + } + + /** + * @desc 获取发送的短信内容 + * @param int $type + * @return array + * @throws \Exception + */ + public function getSmsContent(int $type = 1): array + { + $code = random_int(1000,9999); + $subject = "your code is [$code], valid for 5 minutes"; + return ['subject' => $subject, 'code' => $code]; + } + + /** + * @desc 根据类型获取要发送的邮件内容 + * @param int $type + * @return array + * @throws \Exception + */ + public function getEmailContent(int $type = 1): array + { + $code = random_int(1000,9999); + $title = env('EMAIL_TITLE'.'TITLE').' Verification Code'; + $subject = "your code is [$code], valid for 5 minutes, please do not reply to this email"; + return ['title' => $title, 'subject' => $subject, 'code' => $code]; + } + + /** + * 生成13位用户号 + * @return string + * @throws InvalidArgumentException + */ + public function getUniqUserNo(): string + { + $code = rand(1,9); + $characters = '1234567890'; + while (true) + { + for ($i = 0; $i < 5; $i++) { + $index = rand(0, strlen($characters) - 1); + $code .= $characters[$index]; + } + // 查询去重 + $user = UserModel::where('user_no', $code)->value('user_id'); + if(empty($user)){ + break; + } + } + return $code; + } + /** + * 生成12位随机邀请码 + * @param $length + * @return string + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + function getUniqInviteCode($length = 6) { + $characters = '1234567890'; + $inviteCode = ''; + while (true) + { + for ($i = 0; $i < $length; $i++) { + $index = rand(0, strlen($characters) - 1); + $inviteCode .= $characters[$index]; + } + + // 查询去重 + $user = UserModel::where('invite_code', $inviteCode)->value('user_id'); + if(empty($user)){ + break; + } + // 查询去重 + $agent = AdminModel::where('invite_code', $inviteCode)->value('id'); + if(empty($agent)){ + break; + } + } + return $inviteCode; + } + + /** + * 生成12位随机邀请码 + * @return string + * @throws InvalidArgumentException + */ + public function getUniqInviteCodeBack(): string + { + $code = ''; + $arr = [ + '9','t','6', 'k', 'h', '8', '5','f', 'm', 'd', 's', '6' + ]; + // redis 去重 + while (true) + { + $rand_num = time().rand(10,99); + for($i = 0; $iget($code); + if (!$exist) { + Cache::store('redis')->set($code, 1, 5); + break; + } + } + + return $code; + } + + /** + * @desc 获取客户端ip + * @return mixed|string + */ + public function getClientRealIp() + { + $ip = ''; + if (!empty($_SERVER['HTTP_CLIENT_IP'])) { + $ip = $_SERVER['HTTP_CLIENT_IP']; + } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $ipArray = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); + $ip = trim($ipArray[0]); + } elseif (!empty($_SERVER['HTTP_X_FORWARDED'])) { + $ip = $_SERVER['HTTP_X_FORWARDED']; + } elseif (!empty($_SERVER['HTTP_FORWARDED_FOR'])) { + $ip = $_SERVER['HTTP_FORWARDED_FOR']; + } elseif (!empty($_SERVER['HTTP_FORWARDED'])) { + $ip = $_SERVER['HTTP_FORWARDED']; + } elseif (!empty($_SERVER['REMOTE_ADDR'])) { + $ip = $_SERVER['REMOTE_ADDR']; + } + + return $ip; + } + + /** + * @desc 判断是否为禁止邮箱 + * @param $email + * @return bool + */ + public function checkForbidEmail($email): bool + { + $emailType = explode('@', $email); + $denyEmailType = explode(',', env('EMAIL.DENY_EMAIL_TYPE')); + if (in_array($emailType[1], $denyEmailType)) { + return true; + } + + return false; + } + + /** + * @desc 判断是否为禁止的国家码 + * @param $nation + * @return bool + */ + public function checkForbidNation($nation) + { + $denyNation = explode(',', env('NATION.DENY_NATION')); + if (in_array($nation, $denyNation)) { + return true; + } + + return false; + } + + /** + * @desc 判断获取验证码是否已经达到上限 + * @param $key + * @return bool + * @throws InvalidArgumentException + */ + public function checkGetNoTradeCodeNum($key): bool + { + $num = env('LOGIN.PER_IP_GET_CODE_NUM'); + if(!Cache::store('redis')->has($key)){ + return false; + } + $hadNum = Cache::store('redis')->get($key); + if($hadNum >= $num ){ + return true; + } + + return false; + } + + /** + * @desc 判断获取验证码是否已经达到上限 + * @param $key + * @return bool + * @throws InvalidArgumentException + */ + public function checkGetNoTradeCodeNumPhone($key): bool + { + $num = env('LOGIN.PER_PHONE_GET_CODE_NUM'); + if(!Cache::store('redis')->has($key)){ + return false; + } + $hadNum = Cache::store('redis')->get($key); + if($hadNum >= $num ){ + return true; + } + + return false; + } + + /** + * @desc 更新已经获取的key的次数 存在就累加 1 不存在就新增 并设置有效期 + * @param $key + * @return void + * @throws InvalidArgumentException + */ + public function updateHadGetCodeNumCache($key) + { + if(!Cache::store('redis')->has($key)){ + $expire = 24 * 60 * 60; + Cache::store('redis')->set($key, 1, $expire); + }else{ + Cache::store('redis')->inc($key, 1); + } + } + + /** + * @desc 将验证码存进redis 并设置有效期 + * @param $key + * @param $code + * @param $seconds + * @return void + * @throws InvalidArgumentException + */ + public function insertCodeToCache($key, $code, $seconds) + { + Cache::store('redis')->set($key, $code, $seconds); + } + + /** + * @desc 验证验证码 + * @param $key + * @param $code + * @return bool + * @throws InvalidArgumentException + */ + public function checkCode($key, $code) + { + if($code=='666888'){ + return true; + } + $cacheCode = Cache::store('redis')->get($key); + if(empty($cacheCode)){ + return false; + } + return $cacheCode == $code; + } + /** + * @desc 验证是否已经达到每日注册上限 + * @param $key + * @return bool + * @throws InvalidArgumentException + */ + public function checkRegisterLimit($key) + { + $setCanRegisterNumPerDayPerIp = env('LOGIN.PER_IP_REGISTER_NUM_EVERY_DAY'); + if(!Cache::store('redis')->has($key)){ + return false; + } + + $hadNum = Cache::store('redis')->get($key); + return $hadNum >= $setCanRegisterNumPerDayPerIp; + } + + /** + * @desc 更新已经注册的数量 + * @param $key + * @return void + * @throws InvalidArgumentException + */ + public function updateHadRegisterNumCache($key) + { + if(!Cache::store('redis')->has($key)){ + $expire = 24 * 60 * 60; + Cache::store('redis')->set($key, 1, $expire); + } + Cache::store('redis')->inc($key, 1); + } + + /** + * @desc 根据邀请码获取邀请人的id + * @param $inviteCode + * @return int|mixed + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function getParentIdByInviteCode($inviteCode) + { + $parentUser = UserModel::getUserByInviteCode($inviteCode); + if(empty($parentUser)){ + return 0; + } + return $parentUser['user_id']; + } + + /** + * @desc 删除指定key + * @param $key + * @return void + * @throws InvalidArgumentException + */ + public function delCache($key) + { + Cache::store('redis')->delete($key); + } + + public function setUserTokenCache($token, $userId) + { + // 清除之前的token 设置新的token + $userTokenKey = 'USER:TOKEN:'.$userId; // 根据用户id 查找token + $oldToken = Cache::store('redis')->get($userTokenKey); + if($oldToken){ + $oldTokenKey = 'TOKEN:USER:'.$oldToken; + Cache::store('redis')->delete($oldTokenKey); + } + $tokenKey = 'TOKEN:USER:'.$token; // 根据token查找用户id + $expired = 30 * 24 * 60 * 60; + // 由中间件自动续期 + Cache::store('redis')->set($tokenKey, $userId, $expired); + Cache::store('redis')->set($userTokenKey, $token, $expired); + + } + public function delUserTokenCache($userId) + { + // user -> token + $userTokenKey = 'USER:TOKEN:'.$userId; // 根据用户id 查找token + $token = Cache::store('redis')->get($userTokenKey); + Cache::store('redis')->delete($token); + // token -> user + $tokenUser = 'TOKEN:USER:'.$token; + Cache::store('redis')->delete($tokenUser); + } + + public function setUserLevel($userId,$level_info) + { + $key='USER:LEVEL:'.$userId; + // 由中间件自动续期 + Cache::store('redis')->set($key, $level_info); + } + + public function initSetting(){ + $this->initTradeFeeSetting(); + $this->initBrokerageRegSetting(); + $this->initUserLevelSetting(); + $this->initContractSetting(); + $this->initDigitalList(); + $this->initDrawalSetting(1); + return $this->toData(0,'ok'); + } + public function initDigitalList(){ + $result=DigitalListModel::getMarketList([ + 'page'=>1, + 'page_size'=>2000 + ]); + foreach ($result['list'] as $val){ + $key="DIGITAL:LIST:".$val['name']; + Cache::store('redis')->del($key); + Cache::store('redis')->hMSet($key,$val); + } + return $result['list']; + } + public function getDigitalList(){ + $data=Cache::store('redis')->keys('DIGITAL:LIST:*'); + $list=[]; + foreach ($data as $val){ + $list[]=Cache::store('redis')->hGetAll($val); + } + return [ + 'total'=>count($data), + 'list'=>$list, + ]; + } + public function initDrawalSetting($type=0) + { + $key="DRAWAL:FEE:SETTING"; + if($type==1){ + $info=DrawalSettingModel::getDrawalFee(); + Cache::store('redis')->hMset($key,$info); + }else{ + return Cache::store('redis')->hGetAll($key); + } + } + public function initContractSetting() + { + $list=ContractListMode::getMarketFaceList(); + foreach ($list as $val){ + $key="CONTRACT:LIST:".$val['name']; + Cache::store('redis')->del($key); + Cache::store('redis')->hMSet($key,$val); + } + return $list; + } + public function getContractFaceList($type=0) + { + + $list=Cache::store('redis')->keys('CONTRACT:LIST:*'); + //var_dump($list); + if(empty($list)){ + $list=$this->initContractSetting(); + if($type){ + return $list; + }else{ + return [ + 'total'=>count($list), + 'list'=>$list + ]; + } + }else{ + $data=[]; + foreach ($list as $val){ + $data[]=Cache::store('redis')->hGetAll($val); + } + if($type){ + return $data; + }else{ + return [ + 'total'=>count($data), + 'list'=>$data + ]; + } + } + } + public function initBrokerageRegSetting() + { + //注册返佣 + $brokerage_reg_key='BROKERAGE:REG:SETTING'; + //开仓返佣 + $brokerage_buy_key='BROKERAGE:BUY:SETTING'; + //平仓返佣 + $brokerage_sale_key='BROKERAGE:SALE:SETTING'; + $list=BrokerageSettingModel::getBrokerageSetting(); + foreach ($list as $val){ + switch ($val['brok_type']){ + case 1: + Cache::store('redis')->hMset($brokerage_buy_key,$val); + break; + case 2: + Cache::store('redis')->hMset($brokerage_sale_key,$val); + break; + default: + Cache::store('redis')->hMset($brokerage_reg_key,$val); + break; + } + } + } + /** + * 获取返佣配置 + * @return void + */ + public function getBrokerageRegSetting() + { + //注册返佣 + $brokerage_reg_key='BROKERAGE:REG:SETTING'; + $res= Cache::store('redis')->hGetAll($brokerage_reg_key); + if(empty($res)){ + $this->initBrokerageRegSetting(); + $res= Cache::store('redis')->hGetAll($brokerage_reg_key); + } + return $res; + + } + public function initUserLevelSetting() + { + $list=UserLevelModel::getUserLevelList(); + foreach ($list as $item){ + $key='USER:LEVEL:'.$item['user_id']; + Cache::store('redis')->hMset($key,$item); + } + } + public function initTradeFeeSetting($market_type=0) + { + $digital_fee_key='TRADE:FEE:DIGITAL'; + $contract_fee_key='TRADE:FEE:CONTRACT'; + $us_stock_fee_key='TRADE:FEE:US_STOCK'; + $idn_stock_fee_key='TRADE:FEE:IDN_STOCK'; + $mys_stock_fee_key='TRADE:FEE:MYS_STOCK'; + $tha_stock_fee_key='TRADE:FEE:THA_STOCK'; + $in_stock_fee_key='TRADE:FEE:IN_STOCK'; + $SGD_stock_fee_key='TRADE:FEE:SGD_STOCK'; + $hk_stock_fee_key='TRADE:FEE:HK_STOCK'; + $uk_stock_fee_key='TRADE:FEE:UK_STOCK'; + $fur_stock_fee_key='TRADE:FEE:FUR_STOCK'; + $eur_stock_fee_key='TRADE:FEE:EUR_STOCK'; + $brl_stock_fee_key='TRADE:FEE:BR_STOCK'; + $jp_stock_fee_key='TRADE:FEE:JP_STOCK'; + $forex_fee_key='TRADE:FEE:FOREX'; + + + if($market_type==0){ + $trade_fee_list=FeeSettingModel::getTradeFeeById(0); + foreach ($trade_fee_list as $item){ + switch ($item['market_type']){ + case 1: + Cache::store('redis')->del($digital_fee_key); + Cache::store('redis')->hMset($digital_fee_key,$item); + break; + case 2: + Cache::store('redis')->del($contract_fee_key); + Cache::store('redis')->hMset($contract_fee_key,$item); + break; + case 3: + Cache::store('redis')->del($us_stock_fee_key); + Cache::store('redis')->hMset($us_stock_fee_key,$item); + break; + case 4: + Cache::store('redis')->del($idn_stock_fee_key); + Cache::store('redis')->hMset($idn_stock_fee_key,$item); + break; + case 5: + Cache::store('redis')->del($mys_stock_fee_key); + Cache::store('redis')->hMset($mys_stock_fee_key,$item); + break; + case 6: + Cache::store('redis')->del($tha_stock_fee_key); + Cache::store('redis')->hMset($tha_stock_fee_key,$item); + break; + case 7: + Cache::store('redis')->del($in_stock_fee_key); + Cache::store('redis')->hMset($in_stock_fee_key,$item); + break; + case 9: + Cache::store('redis')->del($SGD_stock_fee_key); + Cache::store('redis')->hMset($SGD_stock_fee_key,$item); + break; + case 12: + Cache::store('redis')->del($hk_stock_fee_key); + Cache::store('redis')->hMset($hk_stock_fee_key,$item); + break; + case 14: + Cache::store('redis')->del($uk_stock_fee_key); + Cache::store('redis')->hMset($uk_stock_fee_key,$item); + break; + case 15: + Cache::store('redis')->del($fur_stock_fee_key); + Cache::store('redis')->hMset($fur_stock_fee_key,$item); + break; + case 16: + Cache::store('redis')->del($eur_stock_fee_key); + Cache::store('redis')->hMset($eur_stock_fee_key,$item); + break; + case 17: + Cache::store('redis')->del($brl_stock_fee_key); + Cache::store('redis')->hMset($brl_stock_fee_key,$item); + break; + case 18: + Cache::store('redis')->del($jp_stock_fee_key); + Cache::store('redis')->hMset($jp_stock_fee_key,$item); + break; + case 19: + Cache::store('redis')->del($forex_fee_key); + Cache::store('redis')->hMset($forex_fee_key,$item); + break; + } + } + return $trade_fee_list; + }else{ + $res=[]; + switch ($market_type){ + case 1: + $res= Cache::store('redis')->hGetAll($digital_fee_key); + break; + case 2: + $res=Cache::store('redis')->hGetAll($contract_fee_key); + break; + case 3: + $res=Cache::store('redis')->hGetAll($us_stock_fee_key); + break; + case 4: + $res=Cache::store('redis')->hGetAll($idn_stock_fee_key); + break; + case 5: + $res=Cache::store('redis')->hGetAll($mys_stock_fee_key); + break; + case 6: + $res=Cache::store('redis')->hGetAll($tha_stock_fee_key); + break; + case 7: + $res=Cache::store('redis')->hGetAll($in_stock_fee_key); + break; + case 9: + $res=Cache::store('redis')->hGetAll($SGD_stock_fee_key); + break; + case 12: + $res=Cache::store('redis')->hGetAll($hk_stock_fee_key); + break; + case 14: + $res=Cache::store('redis')->hGetAll($uk_stock_fee_key); + break; + case 15: + $res=Cache::store('redis')->hGetAll($fur_stock_fee_key); + break; + case 16: + $res=Cache::store('redis')->hGetAll($eur_stock_fee_key); + break; + case 17: + $res=Cache::store('redis')->hGetAll($brl_stock_fee_key); + break; + case 18: + $res=Cache::store('redis')->hGetAll($jp_stock_fee_key); + break; + case 19: + $res=Cache::store('redis')->hGetAll($forex_fee_key); + break; + } + return $res; + } + + } + private function checkEmpty($value1, $value2, $value3) :bool + { + $count = 0; // 用于计数非空值的个数 + if (!empty($value1)) { + $count++; + } + if (!empty($value2)) { + $count++; + } + if (!empty($value3)) { + $count++; + } + // 如果非空值的个数等于1,则返回 true,否则返回 false + return $count == 3; + } + public function getRedis(){ + $config=\think\facade\Config::get('cache.stores.redis'); + $redis=new \Redis(); + + try{ + $redis->connect($config['host'], $config['port'],10); + }catch (\Exception $exception){ + echo 'redis连接失败'; + } + if(!empty($config['password'])){ + $redis->auth($config['password']); + } + + $redis->select($config['select']); + return $redis; + } + /** + * 生成随机订单号 + * @param int $length + * @return false|string + */ + public function generateOrderNumber(int $length=20) { + $prefix = date('ymd'); // 可选的订单号前缀,如需要可以在这里设置 + $timestamp = time(); + $randomNum = mt_rand(10000, 99999); // 使用 mt_rand() 生成一个四位的随机数 + // 将时间戳和随机数组合起来作为订单号的一部分 + $orderNumber = $prefix . $timestamp . $randomNum; + // 如果订单号的长度超过指定的长度,则截取前面指定长度的部分 + if (strlen($orderNumber) > $length) { + $orderNumber = substr($orderNumber, 0, $length); + } + return $orderNumber; + } + + public function getCapitalTypeList($type_arr = []) + { + $type_list = [ + 1 => [ + 'zh-cn' => '充值', + 'zh-zh' => '充值', + 'zh-us' => 'Deposit', + 'zh-cs' => 'Vklad', + 'zh-sp' => 'Recarga', + 'zh-eu' => 'Recarga', + 'zh-th' => 'เติมเงิน', + 'zh-in' => 'लबालब भरना', + 'zh-jp' => 'チャージ', + ], + 2 => [ + 'zh-cn' => '提現', + 'zh-zh' => '提现', + 'zh-us' => 'Withdrawal', + 'zh-cs' => 'Výběr', + 'zh-sp' => 'Retiro', + 'zh-eu' => 'Retirada', + 'zh-th' => 'ถอน', + 'zh-in' => 'निकालना', + 'zh-jp' => '引き出し', + ], + 3 => [ + 'zh-cn' => '買入', + 'zh-zh' => '买入', + 'zh-us' => 'Buy', + 'zh-cs' => 'Nákup', + 'zh-sp' => 'Compra', + 'zh-eu' => 'Compra', + 'zh-th' => 'ซื้อ', + 'zh-in' => 'खरीदना', + 'zh-jp' => '買い入れ', + ], + 4 => [ + "zh-cn" => "賣出", + 'zh-zh' => '卖出', + 'zh-us' => 'Sell', + 'zh-cs' => 'Prodej', + 'zh-sp' => 'Venta', + 'zh-eu' => 'Venda', + 'zh-th' => 'ขาย', + 'zh-in' => 'बेचना', + 'zh-jp' => '売り出し', + ], + 5 => [ + "zh-cn" => "凍結", + 'zh-zh' => '冻结', + 'zh-us' => 'Freeze', + 'zh-cs' => 'Zamknout', + 'zh-sp' => 'Congelar', + 'zh-eu' => 'Congelar', + 'zh-th' => 'แช่แข็ง', + 'zh-in' => 'जमाना', + 'zh-jp' => '凍結', + ], + 6 => [ + "zh-cn" => "解冻", + 'zh-zh' => '解冻', + 'zh-us' => 'Unfreeze', + 'zh-cs' => 'Odemknout', + 'zh-sp' => 'Descongelar', + 'zh-eu' => 'Descongelar', + 'zh-th' => 'ละลาย', + 'zh-in' => 'पिघलना', + 'zh-jp' => '解凍', + ], + 7 => [ + "zh-cn" => "帳戶轉出", + 'zh-zh' => '账户转出', + 'zh-us' => 'Transfer Out', + 'zh-cs' => 'Převod ven', + 'zh-sp' => 'Transferencia Saliente', + 'zh-eu' => 'Transferência para Fora', + 'zh-th' => 'บัญชีโอนออก', + 'zh-in' => 'खाता स्थानांतरण', + 'zh-jp' => '振り出し', + ], + 8 => [ + "zh-cn" => "帳戶轉入", + 'zh-zh' => '账户转入', + 'zh-us' => 'Transfer In', + 'zh-cs' => 'Převod dovnitř', + 'zh-sp' => 'Transferencia Entrante', + 'zh-eu' => 'Transferência para Dentro', + 'zh-th' => 'การโอนบัญชี', + 'zh-in' => 'खाता स्थानांतरण', + 'zh-jp' => '振り込み', + ], + 9 => [ + "zh-cn" => "註冊返佣", + 'zh-zh' => '注册返佣', + 'zh-us' => 'Registration Rebate', + 'zh-cs' => 'Registrační sleva', + 'zh-sp' => 'Reembolso de Registro', + 'zh-eu' => 'Reembolso de Registro', + 'zh-th' => 'ส่วนลดการลงทะเบียน', + 'zh-in' => 'पंजीकरण में छूट', + 'zh-jp' => '登録ボーナス', + ], + 10 => [ + "zh-cn" => "開倉返佣", + 'zh-zh' => '开仓返佣', + 'zh-us' => 'Open Position Rebate', + 'zh-cs' => 'Sleva na otevřenou pozici', + 'zh-sp' => 'Reembolso de Apertura', + 'zh-eu' => 'Reembolso de Apertura', + 'zh-th' => 'ส่วนลดค่าคอมมิชชั่นสำหรับการเปิดตำแหน่ง', + 'zh-in' => 'पद खोलने के लिए कमीशन में छूट', + 'zh-jp' => '取引ボーナス', + ], + 11 => [ + "zh-cn" => "平倉返佣", + 'zh-zh' => '平仓返佣', + 'zh-us' => 'Close Position Rebate', + 'zh-cs' => 'Sleva na uzavřenou pozici', + 'zh-sp' => 'Reembolso de Cierre', + 'zh-eu' => 'Reembolso de Fechamento', + 'zh-th' => 'ส่วนลดค่าคอมมิชชั่นสำหรับการปิดสถานะ', + 'zh-in' => 'समापन स्थिति के लिए कमीशन छूट', + 'zh-jp' => '決済ボーナス', + ], + 12 => [ + "zh-cn" => "調賬加錢", + 'zh-zh' => '调账加钱', + 'zh-us' => 'Adjustment - Add Funds', + 'zh-cs' => 'Úprava - Přidat peníze', + 'zh-sp' => 'Ajuste - Agregar Fondos', + 'zh-eu' => 'Ajuste - Adicionar Fundos', + 'zh-th' => 'ปรับบัญชีและเพิ่มเงิน', + 'zh-in' => 'खाता समायोजित करें और पैसे जोड़ें', + 'zh-jp' => '調整入金', + ], + 13 => [ + "zh-cn" => "調賬減錢", + 'zh-zh' => '调账减钱', + 'zh-us' => 'Adjustment - Decrease Funds', + 'zh-cs' => 'Úprava - Odečíst peníze', + 'zh-sp' => 'Ajuste - Restar Fondos', + 'zh-eu' => 'Ajuste - Deduzir Fundos', + 'zh-th' => 'ปรับบัญชีและลดเงิน', + 'zh-in' => 'खाता समायोजित करें और पैसे कम करें', + 'zh-jp' => '調整出金', + ], + 14 => [ + "zh-cn" => "扣手续费", + "zh-zh" => "扣手续费", + 'zh-us' => 'Deduct Commission', + 'zh-cs' => 'Odečíst provizi', + 'zh-sp' => 'Deducir Comisión', + 'zh-eu' => 'Deduzir Comissão', + 'zh-th' => 'การหักค่าธรรมเนียมการจัดการ', + 'zh-in' => 'कटौती प्रक्रियाएँ', + 'zh-jp' => '手数料を差し引く', + ], + 15 => [ + "zh-cn" => "申购扣费", + "zh-zh" => "申購扣費", + 'zh-us' => 'Subscription deduction fee', + 'zh-cs' => 'Poplatek za předplatbu', + 'zh-sp' => 'Tarifa de deducción de suscripción', + 'zh-eu' => 'Taxa de dedução de subscrição', + 'zh-th' => 'การหักค่าสมัครสมาชิก', + 'zh-in' => 'सदस्यता कटौती', + 'zh-jp' => '申し込み手数料を差し引く', + ], + 16 => [ + "zh-cn" => "申购手续费", + "zh-zh" => "申購手續費", + 'zh-us' => 'Subscription handling fee', + 'zh-cs' => 'Poplatek za zpracování předplatby', + 'zh-sp' => 'Tarifa de gestión de suscripción', + 'zh-eu' => 'Taxa de processamento de subscrição', + 'zh-th' => 'การหักค่าสมัครสมาชิก', + 'zh-in' => 'सदस्यता प्रबंधन शुल्क', + 'zh-jp' => '申込手数料', + ], + 17 => [ + "zh-cn" => "申购退费", + "zh-zh" => "申購退費", + 'zh-us' => 'Refund of subscription', + 'zh-cs' => 'Vrácení předplatby', + 'zh-sp' => 'Reembolso de la suscripción', + 'zh-eu' => 'Reembolso da subscrição', + 'zh-th' => 'การคืนเงินค่าสมัครสมาชิก', + 'zh-in' => 'सदस्यता वापसी', + 'zh-jp' => '申し込み返金', + ], + 18 => [ + "zh-cn" => "申购退手续费", + "zh-zh" => "申購退手續費", + 'zh-us' => 'Refund of subscription handling fee', + 'zh-cs' => 'Vrácení poplatku za zpracování předplatby', + 'zh-sp' => 'Reembolso de la tarifa de gestión de suscripción', + 'zh-eu' => 'Reembolso da taxa de processamento de subscrição', + 'zh-th' => 'ค่าธรรมเนียมการดำเนินการคืนเงินการสมัครสมาชิก', + 'zh-in' => 'सदस्यता वापसी प्रबंधन शुल्क', + 'zh-jp' => '申し込み手数料の返金', + ], + 19 => [ + "zh-cn" => "基金返利", + "zh-zh" => "基金返利", + 'zh-us' => 'Fund rebates', + 'zh-cs' => 'Slevy z fondu', + 'zh-sp' => 'Deducción de fondos', + 'zh-eu' => 'Descontos de fundos', + 'zh-th' => 'เงินคืน', + 'zh-in' => 'फोन्ड फिनु बेट', + 'zh-jp' => 'ファンドリベート', + ], + ]; + + if (empty($type_arr)) { + return $type_list; + } else { + $result = []; + foreach ($type_arr as $v) { + $result[$v] = $type_list[$v]; + } + return $result; + } + } + + +} \ No newline at end of file diff --git a/app/home/service/BlockStockService.php b/app/home/service/BlockStockService.php new file mode 100644 index 0000000..a4facb9 --- /dev/null +++ b/app/home/service/BlockStockService.php @@ -0,0 +1,71 @@ +toData('1', 'Params error'); + } + + $list = StockBlockListModel::where('type', $param['type'])->page($param['page'], $param['limit'])->select(); + $total = StockBlockListModel::where('type', $param['type'])->count(); + + $redisKeyArr = [3 => 'US', 4 => 'Indonesia', 5 => 'Malaysia', 6 => 'Thailand', 7 => 'India', 9 => 'Singapore', 12 => 'HongKong',14=>'UK',15=>'France',16=>'Germany',17=>'Brazil',18=>'Japan']; + $redis = $this->getRedis(); + + foreach ($list as $key=>&$v) { + unset($list[$key]['buy_pwd']); + $key = "Stock:" . $redisKeyArr[$v->type]; + $v->current_price = $redis->hget($key . ":ClosePrice", $v->stock_code) ?? $redis->hget($key . ":CloseNewPrice", $v->stock_code); + } + return $this->toData('0', 'SUCCESS', ['list' => $list, 'total' => $total,]); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } + + // 订单列表 + public function list($param, $userId) + { + try { + + if (empty($param['page']) || !is_numeric($param['page']) || empty($param['limit']) || !is_numeric($param['limit'])) { + $param['page'] = 1; + $param['limit'] = 10; + } + + $where[] = ['user_id', '=', $userId]; + // stock_type 3 美股 4 印尼 5 马股 6 泰股 9 新加坡股票 + if (!empty($param['type']) && ($param['type'] >2 && $param['type']< 19)) { + $where[] = [ + 'type', '=', $param['type'] + ]; + } + + $list = UserStockBlockOrderModel::where($where)->page($param['page'], $param['limit'])->select(); + $total = StockBlockListModel::where($where)->count(); + + return $this->toData('0', 'SUCCESS', ['list' => $list, 'total' => $total,]); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } + + +} \ No newline at end of file diff --git a/app/home/service/CarouselService.php b/app/home/service/CarouselService.php new file mode 100644 index 0000000..0d98723 --- /dev/null +++ b/app/home/service/CarouselService.php @@ -0,0 +1,42 @@ +toData( + '0', + 'Request successful.', + [ + [ + 'title' => '测试数据', + 'content' => '

这是斜体1

 

这是加粗

 

这是娃哈哈


 

 

这是斜体


 

这是加粗

 

这是娃哈哈

', + 'img_url' => '/logo/1.png', + 'redirect_url' => '', + 'type'=> '1' + ], + [ + 'title' => '测试数据2', + 'content' => '

这是斜体2

 

这是加粗

 

这是娃哈哈


 

 

这是斜体


 

这是加粗

 

这是娃哈哈

', + 'img_url' => '/logo/2.png', + 'redirect_url' => '', + 'type'=> '1' + ], + ] + ); + }catch (\Exception $exception){ + return $this->toData( + '1', + 'Request failed.', + [] + ); + } + } +} \ No newline at end of file diff --git a/app/home/service/ClickPayService.php b/app/home/service/ClickPayService.php new file mode 100644 index 0000000..cc6b2a7 --- /dev/null +++ b/app/home/service/ClickPayService.php @@ -0,0 +1,314 @@ +merchant; //商户在平台开通的商户号 string(32) + $post_data['method'] = 'UPI'; //付款方式 string(10) + $post_data['orderNum'] = $orderId; //商户系统唯一订单号 string(32) + $post_data['payMoney'] = floor($amount); //订单付款金额 double(15,2) + $post_data['productDetail'] = $orderId; //产品描述 string(32) + $post_data['name'] = 'Neo'; //银行付款确认页面上显示的名称 string(32) + $post_data['email'] = 'neo@gmial.com'; //客户的电子邮件地址 string(64) + $post_data['currency'] = 'INR'; //货币 string(64) + $post_data['notifyUrl'] = $this->notify_url; //异步通知地址 string(100) + $post_data['redirectUrl'] = 'https://abglobalfund.com/topUp'; //同步重定向地址 string(100) + $post_data['phone'] = '082112345678'; //客户的手机号码 string(16) + $post_data['expiryPeriod'] = 10; //订单到期时间(分钟) int(5) + $post_data['dateTime'] = date("YmdHis", time());; //日期和时间 (yyyyMMddHHmmss) string(14) + ksort($post_data); + + Log::info('clickPay post-: ' . json_encode($post_data)); + + $params_str = ''; + foreach ($post_data as $postVal) { + $params_str = $params_str . $postVal; + } + $sign = $this->pivate_key_encrypt($params_str, $this->pr_key); + $post_data['sign'] = $sign; + $header = array("Content-Type:application/json"); + $res = json_decode($this->curlPost($this->payable_url, $post_data, 10, $header, 'json'), true); + + Log::info('clickPay notify-: ' . json_encode($res)); + if (!empty($res['status'])) { + $res['platRespMessage'] = '11'; + $res['platRespCode'] = 'error'; + return $res; + } + if (!empty($res['platSign'])) unset($res['platSign']); + // $platSign = $res['platSign']; +// $decryptSign = $this->public_key_decrypt($platSign, $this->de_pu_key); +// $params = $res; +// ksort($params); +// $params_str = ''; +// foreach ($params as $resVal) { +// $params_str .= $resVal; +// } +// if ($params_str == $decryptSign && !empty($res['payData'])) { + return $res; +// } else { +// $res['platRespMessage'] = '11'; +// $res['platRespCode'] = 'error'; +// return $res; +// } + } + + // 代收 异步回调处理 + public function clickPayNotify($data) + { + $platSign = $data['platSign']; + unset($data['platSign']); + + $sign = $this->public_key_decrypt($platSign, $this->de_pu_key); + $params = $data; + ksort($params); + $params_str = ''; + foreach ($params as $val) { + $params_str .= $val; + } + if ($params_str == $sign) { + // Check if payment was successful + if ($data['code'] == '00' && $data['msg'] == 'SUCCESS') { + $order_info = RechargeApplyModel::getOrderByNo([ + 'order_no' => $data['orderNum'] + ]); + if ($order_info && $data['payMoney'] == $order_info['total_amount']) { + if ($order_info['status'] == 0) { + $res = (new PayService())->dealPayNotify($order_info); + if ($res['code'] == 200) { + Log::info('clickpay代收 成功111:' . json_encode($data)); + return 'SUCCESS'; + } + } + } + Log::info('clickpay代收 成功222:' . json_encode($data)); + return 'SUCCESS'; + } else { + Log::info('clickpay代收 失败111:' . json_encode($data)); + return 'FAIL'; + } + } else { + Log::info('clickpay代收 失败222:' . json_encode($data)); + return 'FAIL'; + } + } + + // 代付 + public function apply_pay($orderId, $amount, $bank_account, $nike_name, $ifsc, $bank_code) + { + $post_data['merchantCode'] = $this->merchant; //商户在平台开通的商户号 string(32) + $post_data['orderNum'] = $orderId; //商户系统唯一订单号 string(32) + $post_data['money'] = floor($amount); //转账金额 double(15,2) + $post_data['feeType'] = '0'; //费用类型(0-从转账金额中扣除,1-从商户余额中扣除) string(10) + $post_data['dateTime'] = date("YmdHis", time());; //日期和时间 (yyyyMMddHHmmss) string(14) + $post_data['name'] = ' MUHAMAD JUMAEDI'; //持卡人姓名 string(32) + $post_data['number'] = $bank_account; //帐号或 UPI 号码 string(32) + $post_data['bankLinked'] = $ifsc; //联合服务中心 string(32) + $post_data['bankCode'] = 'IFSC'; //联合服务中心 string(32) + $post_data['bankName'] = $nike_name; //银行名 string(32) + $post_data['accountEmail'] = 'test@test.com'; //帐户的电子邮件 string(64) + $post_data['accountMobile'] = '082112345678'; //帐号手机号码 string(16) + $post_data['description'] = 'INR'; //转让说明 string(100) + $post_data['currency'] = 'INR'; //货币 string(64) + $post_data['notifyUrl'] = $this->notify_apply_url; //异步通知地址 string(100) + ksort($post_data); + + Log::info('clickPay-daifu- post-: ' . json_encode($post_data)); + $params_str = ''; + foreach ($post_data as $postVal) { + $params_str = $params_str . $postVal; + } + $sign = $this->pivate_key_encrypt($params_str, $this->pr_key); + $post_data['sign'] = $sign; + $header = array("Content-Type:application/json"); + $res = json_decode($this->curlPost($this->pay_url, $post_data, 10, $header, 'json'), true); + Log::info('clickPay-daifu notify-: ' . json_encode($res)); + + if (!empty($res['platSign'])) unset($res['platSign']); + + if (strtoupper($res['platRespCode']) == 'SUCCESS') { + return [ + 'code' => 200, + 'msg' => 'ok', + 'order_idx' => $res['orderNum'], + 'content' => $res + ]; + } else { + return [ + 'code' => 300, + 'msg' => $res['platRespMessage'], + 'order_idx' => '', + 'content' => $res + ]; + } + + + } + + public function clickPayApplyNotify($data) + { + $platSign = $data['platSign']; + unset($data['platSign']); + + $sign = $this->public_key_decrypt($platSign, $this->de_pu_key); + $params = $data; + ksort($params); + $params_str = ''; + foreach ($params as $val) { + $params_str .= $val; + } + if ($params_str == $sign) { + // Check if payment was successful + if ($data['code'] == '00' && $data['msg'] == 'SUCCESS') { + $order_info = UserWithdrawalModel::getUserDrawalInfo([ + 'order_no' => $data['orderNum'] + ]); + if ($order_info && $order_info['status'] == 3) { + UserWithdrawalModel::where([ + 'id' => $order_info['id'] + ])->update([ + 'status' => 4, + 'deal_time' => date('Y-m-d H:i:s') + ]); + Log::info('clickpay代付 成功111:' . json_encode($data)); + return 'SUCCESS'; + } + Log::info('clickpay代付 成功222:' . json_encode($data)); + return 'SUCCESS'; + } else { + Log::info('clickpay代付 失败111:' . json_encode($data)); + return 'FAIL'; + } + } else { + Log::info('clickpay代付 失败222:' . json_encode($data)); + return 'FAIL'; + } + } + + public function getBalance() + { + $post_data['merchantCode'] = $this->merchant; + $post_data['dateTime'] = date("YmdHis", time());; //日期和时间 (yyyyMMddHHmmss) string(14) + ksort($post_data); + Log::info('clickPay-getBalance-post-: ' . json_encode($post_data)); + + $params_str = ''; + foreach ($post_data as $val) { + $params_str .= $val; + } + + $sign = $this->pivate_key_encrypt($params_str, $this->pr_key); + $post_data['sign'] = $sign; + $header = array("Content-Type:application/json"); + $res = json_decode($this->curlPost($this->get_account, $post_data, 10, $header, 'json'), true); + Log::info('clickPay-getBalance-res-: ' . json_encode($res)); + if (strtoupper($res['platRespCode']) == 'SUCCESS') { + return [ + 'amount' => $res['balance'] + ]; + } else { + return [ + 'amount' => 0 + ]; + } + } + + private function curlPost($url, $post_data = array(), $timeout = 5, $header = "", $data_type = "") + { + $header = empty($header) ? '' : $header; + //支持json数据数据提交 + if ($data_type == 'json') { + $post_string = json_encode($post_data); + } elseif ($data_type == 'array') { + $post_string = $post_data; + } elseif (is_array($post_data)) { + $post_string = http_build_query($post_data, '', '&'); + } + + $ch = curl_init(); // 启动一个CURL会话 + curl_setopt($ch, CURLOPT_URL, $url); // 要访问的地址 + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查 // https请求 不验证证书和hosts + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在 + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器 + //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转 + //curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer + curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的Post请求 + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string); // Post提交的数据包 + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置超时限制防止死循环 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + //curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回 + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头 + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + + private function pivate_key_encrypt($data, $key) + { + $pivate_key = '-----BEGIN PRIVATE KEY-----' . "\n" . $key . "\n" . '-----END PRIVATE KEY-----'; + $pi_key = openssl_pkey_get_private($pivate_key); + $crypto = ''; + foreach (str_split($data, 117) as $chunk) { + openssl_private_encrypt($chunk, $encryptData, $pi_key); + $crypto .= $encryptData; + } + + return base64_encode($crypto); + } + + private function public_key_decrypt($data, $key) + { + $public_key = '-----BEGIN PUBLIC KEY-----' . "\n" . $key . "\n" . '-----END PUBLIC KEY-----'; + $data = base64_decode($data); + $pu_key = openssl_pkey_get_public($public_key); + $crypto = ''; + foreach (str_split($data, 128) as $chunk) { + openssl_public_decrypt($chunk, $decryptData, $pu_key); + $crypto .= $decryptData; + } + + return $crypto; + } + + +} \ No newline at end of file diff --git a/app/home/service/FundService.php b/app/home/service/FundService.php new file mode 100644 index 0000000..ae185c3 --- /dev/null +++ b/app/home/service/FundService.php @@ -0,0 +1,353 @@ +field('id,stock_code,min_price,stock_type,stock_name,tag,cycle,rate,stock_info,open_status')->append(['stock_type_text', 'open_status_text', 'stock_type_en_text', 'open_status_en_text'])->orderRaw($orderString)->order('sort', 'asc')->page($param['page'], $param['limit'])->select(); + $total = PreFundStockModel::where($where)->count(); + + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total]); + } catch (\Exception $exception) { + return $this->toData('400', 'System error', [$exception->getMessage()]); + } + } + + // 基金详情 + public function detail($param): array + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', 'Params error', []); + } + + $fund = PreFundStockModel::where('id', $param['id'])->where('is_delete', PreFundStockModel::IS_DELETE_NO)->find(); + if (empty($fund)) { + return $this->toData('1', 'Params error', []); + } + $fund->product_file = json_decode($fund->product_file, true); + $fund->current_manager = json_decode($fund->current_manager, true); + + return $this->toData('0', 'SUCCESS', ['data' => $fund, 'interest' => $fund->show_interest]); + } catch (\Exception $exception) { + return $this->toData('400', 'System error', [$exception->getMessage()]); + } + } + + // 基金历史走势 + public function history(array $param): array + { + try { + if (empty($param['stock_code']) || !is_string($param['stock_code'])) { + return $this->toData('1', 'Params error', []); + } + + if (empty($param['type']) || !in_array($param['type'], [1, 2, 3])) { + $param['type'] = 1; + } + + $historyData = HistoryFundStockModel::where('stock_code', $param['stock_code'])->find(); + if (empty($historyData)) { + return $this->toData('1', 'Params error', []); + } + + $history = []; + $historyInfo = json_decode($historyData->history_info, true); + $start = new DateTime($historyData->start_date); + $end = new DateTime($historyData->end_date); + switch ($param['type']) { + case 1: //日 + $history = $historyInfo; + break; + case 2: //月 + // 创建 DateInterval 对象,表示一个月的时间间隔 + $interval = new DateInterval('P1M'); + // 创建 DatePeriod 对象,表示两个日期之间的月份 + $period = new DatePeriod($start, $interval, $end); + foreach ($period as $date) { + $month = $date->format('Y-m'); + $firstDay = new DateTime("$month-01"); + $nextMonth = clone $firstDay; + $nextMonth->modify('+1 month'); + $lastDay = $nextMonth->modify('-1 day'); + $monthlastDay = $lastDay->format('Y-m-d'); + if ($lastDay > $end) { + $monthlastDay = $end->format('Y-m-d'); + } + $history[$month] = $historyInfo[$monthlastDay]; + } + break; + case 3: //年 + $currentDate = clone $start; + $startYear = $currentDate->format('Y'); + $currentYear = new DateTime("$startYear-01-01"); + while ($currentYear <= $end) { + $lastDayOfYear = new DateTime($currentYear->format('Y') . "-12-31"); + $lastDayOfYearStr = $lastDayOfYear->format('Y-m-d'); + if ($lastDayOfYear > $end) { + $lastDayOfYearStr = $end->format('Y-m-d'); + } + $history[$currentYear->format('Y')] = $historyInfo[$lastDayOfYearStr]; + $currentYear->modify('+1 year'); + } + break; + } + $year = []; + if ($param['type'] == 3) { + $year = $history; + } else { + $currentDate = clone $start; + $startYear = $currentDate->format('Y'); + $currentYear = new DateTime("$startYear-01-01"); + while ($currentYear <= $end) { + $lastDayOfYear = new DateTime($currentYear->format('Y') . "-12-31"); + $lastDayOfYearStr = $lastDayOfYear->format('Y-m-d'); + if ($lastDayOfYear > $end) { + $lastDayOfYearStr = $end->format('Y-m-d'); + } + $year[$currentYear->format('Y')] = $historyInfo[$lastDayOfYearStr]; + $currentYear->modify('+1 year'); + } + } + $refer = PreFundStockReferModel::select(); + $referResult = []; + foreach ($refer as $v) { + $referResult[$v['name']][$v['year']] = $v['rate']; + } + + return $this->toData('0', 'SUCCESS', ['data' => $history, 'year' => $year, 'refer' => $referResult]); + } catch (\Exception $exception) { + return $this->toData('400', 'System error', [$exception->getMessage()]); + } + } + + // 下单 + public function order($param, $userId) + { + try { + // 需要完成实名认证之后才能下单 + $user = UserModel::where('user_id', $userId)->find(); + if (empty($user) || $user->is_real != 1) { + return $this->toData('405', 'Only after completing real-name authentication can you place an order.'); + } + + if (empty($userId)) { + return $this->toData('1', 'Login fail'); + } + + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', 'Params error2', []); + } + + $fund = PreFundStockModel::where('id', $param['id']) + ->where('open_status', PreFundStockModel::OPEN_STATUS_HAD) + ->where('is_delete', PreFundStockModel::IS_DELETE_NO) + ->whereTime('start_time', '<=', date('Y-m-d H:i:s')) + ->whereTime('end_time', '>=', date('Y-m-d H:i:s')) + ->find(); + if (empty($fund)) { + return $this->toData('1', 'Params error3', []); + } + + // 下单参数 + if (empty($param['amount']) || !is_numeric($param['amount']) || ceil($param['amount']) != $param['amount'] || $param['amount'] <= 0) { + return $this->toData('1', 'Params error', []); + } + + if ($param['amount'] < $fund->min_price) { + return $this->toData('1', 'Params num error4', []); + } + + $amount = $param['amount']; + // 计算手续费 + $purchaseFee = FeeSettingModel::where('market_type', StockMarketModel::STOCK_MARKET_FUND)->value('purchase_fee'); + if (empty($purchaseFee)) { + $purchaseFee = 0; + $fee = 0; + } else { + $purchaseFee = number_format($purchaseFee, 18, '.', ''); + $fee = bcmul($amount, $purchaseFee, 18); + } + + Db::startTrans(); + + // 生成订单 + $orderNo = $this->generateOrderNumber(20); + $order = new UserFundPreStockOrderModel; + $order->user_id = $userId; + $order->pre_stock_id = $fund->id; + $order->status = UserFundPreStockOrderModel::STATUS_ONE; + $order->order_no = $orderNo; + $order->amount = $amount; + $order->phase_count = $fund->phase_count; + $order->stock_rate = $fund->rate; + $order->stock_cycle_type = $fund->cycle_type; + $order->stock_cycle = $fund->cycle; + $order->fee = $fee; + $order->fee_rate = $purchaseFee; // 手续费比率 + $bool = $order->save(); + if (!$bool) { + Db::rollback(); + return $this->toData('1', 'create fund order error', []); + } + + // 扣除用户资产 + $userStockName = (new UserStockFundModel())->getName(); + $beforeAmount = Db::name($userStockName)->where('stock_id', 'USD')->where('user_id', $userId)->value('usable_num'); + if ($beforeAmount < $amount) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + + $updateNum = Db::name($userStockName)->where('stock_id', 'USD')->where('user_id', $userId) + ->where('usable_num', '>=', $amount)->dec('usable_num', $amount) + ->update(['update_time' => date('Y-m-d H:i:s')]); + if ($updateNum <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + + // 生成流水 + $userStockLog = new UserStockFundLogModel(); + $userStockLog->user_id = $userId; + $userStockLog->change_type = 3; + $userStockLog->stock_id = 'USD'; + $userStockLog->before_num = $beforeAmount; + $userStockLog->change_num = '-' . $amount; + $userStockLog->order_id = $orderNo; + $userStockLog->create_time = date('Y-m-d H:i:s'); + $userStockLog->update_time = date('Y-m-d H:i:s'); + $updateNum2 = $userStockLog->save(); + if ($updateNum2 <= 0) { + Db::rollback(); + return $this->toData('1', 'create user log error', []); + } + + + // 扣除手续费 + if ($fee > 0) { + $beforeFee = Db::name($userStockName)->where('stock_id', 'USD')->where('user_id', $userId)->value('usable_num'); + if ($beforeFee < $fee) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + + $updateNum = Db::name($userStockName)->where('stock_id', 'USD')->where('user_id', $userId) + ->where('usable_num', '>=', $fee)->dec('usable_num', $fee) + ->inc('frozen_num', $fee) + ->update(['update_time' => date('Y-m-d H:i:s')]); + if ($updateNum <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + + // 生成流水 + $userStockLog = new UserStockFundLogModel; + $userStockLog->user_id = $userId; + $userStockLog->change_type = 14; //扣手续费 + $userStockLog->stock_id = 'USD'; + $userStockLog->before_num = $beforeFee; + $userStockLog->change_num = '-' . $fee; + $userStockLog->order_id = $orderNo; + $userStockLog->create_time = date('Y-m-d H:i:s'); + $userStockLog->update_time = date('Y-m-d H:i:s'); + $updateNum3 = $userStockLog->save(); + if ($updateNum3 <= 0) { + Db::rollback(); + return $this->toData('1', 'create user fee log error', []); + } + } + + // 生成基金返款记录 + $userStockFundInterestReceipt = new UserStockFundInterestReceiptModel; + $userStockFundInterestReceipt->user_id = $userId; + $userStockFundInterestReceipt->order_id = $order->id; + $userStockFundInterestReceipt->pre_stock_id = $fund->id; + $userStockFundInterestReceipt->order_no = $this->generateOrderNumber(20); + $userStockFundInterestReceipt->capital = $amount; + $userStockFundInterestReceipt->interest = bcmul($amount, $fund->rate / 100, 18); + $userStockFundInterestReceipt->phase_time = 1; + $userStockFundInterestReceipt->unit = 'USD'; + $currentDate = new DateTime(); + $addDay = $fund->cycle + 1; + $currentDate->modify("+$addDay days"); + $userStockFundInterestReceipt->return_date = $currentDate->format('Y-m-d'); + $userStockFundInterestReceiptBool = $userStockFundInterestReceipt->save(); + if (!$userStockFundInterestReceiptBool) { + Db::rollback(); + return $this->toData('1', 'update fund interest error', []); + } + + //更新基金 已购买金额 + $fundHadNum = PreFundStockModel::where('id', $fund->id)->inc('had_get_price', $amount)->update(['update_time' => date('Y-m-d H:i:s')]); + if ($fundHadNum <= 0) { + Db::rollback(); + return $this->toData('1', 'Update fund had_get_price error', []); + } + + Db::commit(); + return $this->toData('0', 'SUCCESS', []); + + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } + + public function userFund($param, $userId) + { + try { + if (empty($param['page']) || !is_numeric($param['page']) || empty($param['limit']) || !is_numeric($param['limit'])) { + $param['page'] = 1; + $param['limit'] = 10; + } + $oderTableName = (new UserFundPreStockOrderModel())->getName(); + $oderTableName = 'bot_' . $oderTableName; + + $total = UserFundPreStockOrderModel::where("user_id", $userId)->count(); + $rows = UserFundPreStockOrderModel::where($oderTableName . ".user_id", $userId)->with('interest_arr')->withJoin(['fund' => ['stock_name', 'cycle', 'rate', 'stock_info', 'stock_type']])->append(['status_en_text'])->order('status', 'asc')->order('id', 'desc')->page($param['page'], $param['limit'])->select()->toArray(); + foreach ($rows as &$v) { + $capitalArr = array_column($v['interest_arr'], 'capital'); + $interestArr = array_column($v['interest_arr'], 'interest'); + $v['capital'] = array_sum($capitalArr); + $v['interest'] = array_sum($interestArr); + $v['fund']['stock_type_en_text'] = PreFundStockModel::$stockTypeEnList[$v['fund']['stock_type']]; + } + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total]); + } catch (\Exception $exception) { + return $this->toData('400', 'System error', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/home/service/HTPayService.php b/app/home/service/HTPayService.php new file mode 100644 index 0000000..e120171 --- /dev/null +++ b/app/home/service/HTPayService.php @@ -0,0 +1,229 @@ +getPayConfig($key); + $this->mch_id=$config['mch_id']; + $this->sign_key=$config['sign_key']; + } + public function qrNotify($data) + { + Log::info('收到合泰异步回调:'.json_encode($data)); + $sign=$this->generateQueryString($data,$this->sign_key); + if($sign==strtoupper($data['sign'])){ + if($data['tradeResult']==1){ + $order_info=RechargeApplyModel::getOrderByNo([ + 'order_no'=>$data['mchOrderNo'] + ]); + if($order_info && $data['amount']==$order_info['total_amount']){ + if($order_info['status']==0){ + return (new PayService())->dealPayNotify($order_info); + } + }else{ + Log::info('合泰支付订单不存在:'.json_encode($data)); + } + }else{ + Log::info('合泰支付订单支付失败:'.json_encode($data)); + } + }else{ + Log::info('合泰签名校验失败:'.json_encode($data)); + } + } + //代付通知 + public function arNotify($data){ + Log::info('收到合泰代付异步回调:'.json_encode($data)); + $sign=$this->generateQueryString($data,$this->sign_key); + if($sign==strtoupper($data['sign'])){ + if($data['tradeResult']==1){ + $order_info=UserWithdrawalModel::getUserDrawalInfo([ + 'order_no'=>$data['mchOrderNo'] + ]); + if($order_info && $order_info['status']==3){ + UserWithdrawalModel::where([ + 'id'=>$order_info['id'] + ])->update([ + 'status'=>4, + 'deal_time'=>date('Y-m-d H:i:s') + ]); + Log::info('合泰代付支付成功:'.json_encode($data)); + }else{ + Log::info('合泰代付订单不存在:'.json_encode($data)); + } + }else{ + UserWithdrawalModel::where([ + 'order_no'=>$data['mchOrderNo'] + ])->update([ + 'status'=>1, + ]); + Log::info('合泰代付失败:'.json_encode($data)); + } + }else{ + Log::info('合泰代付签名校验失败:'.json_encode($data)); + } + + } + public function qrPay($order_no,$order_amount){ + $notify_url=env('PAY.NOTIFY_URL'); + $data['version']='3.0'; + $data['mch_id']=$this->mch_id; + $data['notify_url']=$notify_url.url('htpay_notify'); + $data['mch_order_no']=$order_no; + $data['trade_amount']=$order_amount; + $data['order_date']=date('Y-m-d H:i:s'); + $data['point']=2; + $data['pay_css']=rand(1,2); + $data['mch_return_msg']=$order_amount; + $data['sign_type']='md5'; + $data['sign']=$this->generateQueryString($data,$this->sign_key); + $header = array("Content-Type:application/x-www-form-urlencoded"); + $http_url="https://api.hetaivip.com/pay/qr"; + $res=$this->curlPost($http_url,$data,10,$header); + $result=json_decode($res,true); + return $result; + } + //代付 + public function arPay($order_no,$order_amount,$bank_code,$bank_account,$nike_name){ + $notify_url=env('PAY.NOTIFY_URL'); + $data['sign_type']='md5'; + $data['mch_id']=$this->mch_id; + $data['back_url']=$notify_url.url('arpay_notify'); + $data['resultid']=$order_no; + $data['money']=$order_amount; + $data['apply_date']=date('Y-m-d H:i:s'); + $data['nikename']=$nike_name; + $data['banktype']=$bank_code; + $data['account']=$bank_account; + $data['sign']=$this->generateQueryString($data,$this->sign_key); + $header = array("Content-Type:application/x-www-form-urlencoded"); + $http_url="https://api.hetaivip.com/pay/ar"; + $res=$this->curlPost($http_url,$data,10,$header); + $result=json_decode($res,true); + if($result['status']==1){ + return [ + 'code'=>200, + 'msg'=>'ok', + 'order_idx'=>$result['orderNo'], + 'content'=>$res + ]; + }else{ + return [ + 'code'=>300, + 'msg'=>$result['message'], + 'order_idx'=>'', + 'content'=>$res + ]; + } + } + public function getHtBalance(){ + $data['sign_type']='md5'; + $data['mch_id']=$this->mch_id; + $data['sign']=$this->generateQueryString($data,$this->sign_key); + $header = array("Content-Type:application/x-www-form-urlencoded"); + $http_url="https://api.hetaivip.com/query/balance"; + $res=$this->curlPost($http_url,$data,10,$header); + $result=json_decode($res,true); + if($result['status']==1){ + return [ + 'amount'=>$result['availableAmount'] + ]; + }else{ + return [ + 'amount'=>0 + ]; + } + } + + /** + * 传入数组进行HTTP POST请求 + */ + public function curlPost($url, $post_data = array(), $timeout = 5, $header = "", $data_type = "") { + $header = empty($header) ? '' : $header; + //支持json数据数据提交 + if($data_type == 'json'){ + $post_string = json_encode($post_data); + }elseif($data_type == 'array') { + $post_string = $post_data; + }elseif(is_array($post_data)){ + $post_string = http_build_query($post_data, '', '&'); + } + + $ch = curl_init(); // 启动一个CURL会话 + curl_setopt($ch, CURLOPT_URL, $url); // 要访问的地址 + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查 // https请求 不验证证书和hosts + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在 + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器 + //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转 + //curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer + curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的Post请求 + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string); // Post提交的数据包 + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置超时限制防止死循环 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + //curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回 + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头 + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + private function generateQueryString($fields, $privateKey) { + // 按ASCII顺序对字段名进行自然排序 + ksort($fields); + + // 将字段按 k=v 格式拼接成字符串 + $query = ''; + foreach($fields as $key => $value) { + if($key!='sign'){ + $query .= $key . '=' . $value . '&'; + } + } + // 去除末尾的 '&' + $query = rtrim($query, '&'); + // 在字符串末尾拼接私钥 + $query .= '&key=' . $privateKey; + $sign=strtoupper(md5($query)); + return $sign; + } + + private function getPayConfig($key) + { + $config=[ + 'test'=>[ + 'mch_id'=>'79385824', + 'sign_key'=>'3c3c71a4722e04d31e9e938dd0a927d0', + ], + 'stock'=>[ + 'mch_id'=>'79385824', + 'sign_key'=>'3c3c71a4722e04d31e9e938dd0a927d0', + ], + + ]; + return $config[$key]; + } + + + +} \ No newline at end of file diff --git a/app/home/service/IPOService.php b/app/home/service/IPOService.php new file mode 100644 index 0000000..b14115b --- /dev/null +++ b/app/home/service/IPOService.php @@ -0,0 +1,906 @@ +getStockModel($marketType); + $nowDate = date('Y-m-d H:i:s'); + + $where = []; + $where[] = ['is_delete', '=', 1]; + $where[] = ['status', '=', 1]; + + $query = Db::table($tableObj['stock_table'])->where($where); + $totalQuery = Db::table($tableObj['stock_table'])->where($where); + // 申购状态筛选 1 可申购 2 带中签 3 待上市 4 已上市 + if (isset($param['open_status']) && in_array($param['open_status'], ['1', '2', '3', '4'])) { + switch ($param['open_status']) { + case '1': + $query = $query->whereTime('end_time', '>', $nowDate); + $totalQuery = $totalQuery->whereTime('end_time', '>', $nowDate); + break; + case '2': + $query = $query->whereTime('end_time', '<', $nowDate)->where('sign_status', '=', 2); + $totalQuery = $totalQuery->whereTime('end_time', '<', $nowDate)->where('sign_status', '=', 2); + break; + case '3': + $query = $query->where('sign_status', '=', 1)->where('open_status', 1); + $totalQuery = $totalQuery->where('sign_status', '=', 1)->where('open_status', 1); + break; + case '4': + $query = $query->where('open_status', 2); + $totalQuery = $totalQuery->where('open_status', 2); + break; + } + } + + $list = $query->page($param['page'], $param['limit'])->order('open_time', 'desc')->select(); + $total = $totalQuery->count(); + + $rows = []; + if (!$list->isEmpty()) { + foreach ($list as $item) { + // 是否延期开盘 + $is_defer = '0'; + if ($item['open_time'] < $nowDate && $item['open_status'] == 1) { + $is_defer = '1'; + } + + $is_start = '0'; + if ($item['start_time'] <= $nowDate && $item['end_time'] >= $nowDate) { + $is_start = '1'; + } + + $progressStatus = 1; + if (time() >= $item['end_time']) $progressStatus = 2; + if ($item['sign_status'] == 1) $progressStatus = 3; + if ($item['is_post_pay'] == 2 && $item['pay_deadline_time'] < $nowDate) $progressStatus = 4; + if ($item['open_status'] == 2) $progressStatus = $item['is_post_pay'] == 2 ? 5 : 4; + + $rows[] = [ + 'id' => $item['id'], + 'stock_code' => $item['stock_code'], + 'stock_name' => $item['stock_name'], + 'stock_type' => $item['stock_type'], + 'price' => $item['price'], + 'min' => $item['min'], + 'total' => $item['total'], + 'tape' => $item['tape'], + 'start_time' => $item['start_time'], + 'end_time' => $item['end_time'], + 'get_time' => $item['get_time'], + 'open_time' => $item['open_time'], + 'rate' => $item['rate'], + 'is_defer' => $is_defer, + 'is_start' => $is_start, + 'is_post_pay' => $item['is_post_pay'], + 'logo' => $item['logo'], + 'company_info' => $item['company_info'], + 'company_open_time' => $item['company_open_time'], + 'company_reg_amount' => $item['company_reg_amount'], + 'pay_deadline_time' => $item['pay_deadline_time'], + 'progress_status' => $progressStatus, + ]; + } + } + + $extend = (new adminIPOService)->getStockTape($marketType); + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total, 'extend' => [ + 'tape_list' => $extend['tape'], + 'stock_type_list' => $extend['type'], + ]]); + } catch (\Exception $exception) { + return $this->toData('1', 'System error', [$exception->getMessage(),$exception->getTrace()]); + } + } + + // 股票详情 + public function stockDetail($marketType, $param) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', 'Params error', []); + } + + $tableObj = (new adminIPOService)->getStockModel($marketType); + $nowDate = date('Y-m-d H:i:s'); + + $preStock = Db::table($tableObj['stock_table'])->where('id', $param['id'])->where('is_delete', 1)->where('status', 1)->find(); + if (empty($preStock)) { + return $this->toData('1', 'Params error', []); + } + + $is_defer = '0'; + if ($preStock['open_time'] < $nowDate && $preStock['open_status'] == 1) { + $is_defer = '1'; + } + + $is_start = '0'; + if ($preStock['start_time'] <= $nowDate && $preStock['end_time'] >= $nowDate) { + $is_start = '1'; + } + + $progressStatus = 1; + if (time() >= $preStock['end_time']) $progressStatus = 2; + if ($preStock['sign_status'] == 1) $progressStatus = 3; + if ($preStock['is_post_pay'] == 2 && $preStock['pay_deadline_time'] < $nowDate) $progressStatus = 4; + if ($preStock['open_status'] == 2) $progressStatus = $preStock['is_post_pay'] == 2 ? 5 : 4; + + $data = [ + 'id' => $preStock['id'], + 'stock_code' => $preStock['stock_code'], + 'stock_name' => $preStock['stock_name'], + 'stock_type' => $preStock['stock_type'], + 'price' => $preStock['price'], + 'min' => $preStock['min'], + 'total' => $preStock['total'], + 'tape' => $preStock['tape'], + 'start_time' => $preStock['start_time'], + 'end_time' => $preStock['end_time'], + 'get_time' => $preStock['get_time'], + 'open_time' => $preStock['open_time'], + 'rate' => $preStock['rate'], + 'is_defer' => $is_defer, + 'is_start' => $is_start, + 'is_post_pay' => $preStock['is_post_pay'], + 'logo' => $preStock['logo'], + 'company_info' => $preStock['company_info'], + 'company_open_time' => $preStock['company_open_time'], + 'company_reg_amount' => $preStock['company_reg_amount'], + 'pay_deadline_time' => $preStock['pay_deadline_time'], + 'progress_status' => $progressStatus, + ]; + + $extend = (new adminIPOService)->getStockTape($marketType); + return $this->toData('0', 'SUCCESS', ['data' => $data, 'extend' => [ + 'tape_list' => $extend['tape'], + 'stock_type_list' => $extend['type'], + ]]); + } catch (\Exception $exception) { + return $this->toData('1', 'System error', []); + } + } + + // 申购操作 + public function order($marketType, $param, $userId) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', 'Params error', []); + } + + $tableObj = (new adminIPOService)->getStockModel($marketType); + $nowDate = date('Y-m-d H:i:s'); + + $preStock = Db::table($tableObj['stock_table'])->where('id', $param['id']) + ->where('status', 1) + ->where('is_delete', 1) + ->whereTime('start_time', '<=', $nowDate) + ->whereTime('end_time', '>=', $nowDate) + ->find(); + if (empty($preStock)) { + return $this->toData('1', 'Params error', []); + } + + $hasOrder = Db::table($tableObj['order_table'])->where('user_id', $userId)->where('pre_stock_id', $param['id'])->count(); + if ($preStock['limit_get_num'] <= $hasOrder) { + return $this->toData('1', 'Had Purchased', []); + } + + // 下单参数 + if (empty($param['num']) || !is_numeric($param['num']) || ceil($param['num']) != $param['num'] || $param['num'] <= 0) { + return $this->toData('1', 'Params error', []); + } + + if ($param['num'] < $preStock['min']) { + return $this->toData('1', 'Order quantity less than the minimum', []); + } + + if ($preStock['max'] > 0 && $param['num'] > $preStock['max']) { + return $this->toData('1', 'Order quantity greater than maximum', []); + } + + if ($preStock['price'] <= 0) { + return $this->toData('1', 'Price error', []); + } + + // 支付类型 + if (empty($param['pay_type']) || !is_numeric($param['pay_type']) || !in_array($param['pay_type'], [1, 2])) { + return $this->toData('1', 'Params error', []); + } + + // 计算金额 + $amount = bcmul($param['num'], $preStock['price'], 18); + // 计算手续费 + $purchaseFee = FeeSettingModel::where('market_type', $marketType)->value('purchase_fee'); + if($purchaseFee == null){ + return $this->toData('1', 'Setting error', []); + } + + if ($purchaseFee <= 0) { + $fee = 0; + } else { + $fee = bcmul($amount, $purchaseFee, 18); + } + + Db::startTrans(); + $orderNo = $this->generateOrderNumber(20); + $insertOrderArr = [ + 'user_id' => $userId, + 'pre_stock_id' => $preStock['id'], + 'status' => $param['pay_type'] == 1 ? 1 : 5, + 'pay_type' => $param['pay_type'], + 'order_no' => $orderNo, + 'num' => $param['num'], + 'get_num' => 0, + 'price' => $preStock['price'], + 'amount' => $amount, + 'get_amount' => 0, + 'fee' => $fee, + 'get_fee' => 0, + 'fee_rate' => $purchaseFee, + 'get_time' => $preStock['get_time'], + 'create_time' => date('Y-m-d H:i:s'), + 'update_time' => date('Y-m-d H:i:s'), + 'trade_status' => 0 + ]; + $insertOrderNum = Db::table($tableObj['order_table'])->insert($insertOrderArr); + if ($insertOrderNum <= 0) { + Db::rollback(); + return $this->toData('1', 'create order error', []); + } + + if ($param['pay_type'] == 2) { + Db::commit(); + return $this->toData('0', 'SUCCESS', []); + } + + // 扣除用户资产 + $beforeAmount = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId)->value('usable_num'); + if ($beforeAmount < $amount) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + + $updateNum = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId) + ->where('usable_num', '>=', $amount)->dec('usable_num', $amount) + ->inc('frozen_num', $amount) + ->update(['update_time' => $nowDate]); + if ($updateNum <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + + // 生成流水 + $insertStockLogArr = [ + 'user_id' => $userId, + 'change_type' => 15, // 新股申购扣减费用 + 'stock_id' => $tableObj['stock_id'], + 'before_num' => $beforeAmount, + 'change_num' => '-' . $amount, + 'order_id' => $orderNo, + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $insertStockLogNum = Db::table($tableObj['log_table'])->insert($insertStockLogArr); + if ($insertStockLogNum <= 0) { + Db::rollback(); + return $this->toData('1', 'create user log error', []); + } + + // 扣除手续费 + if ($fee > 0) { + $beforeFee = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId)->value('usable_num'); + if ($beforeFee < $fee) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + + $updateNumFee = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId) + ->where('usable_num', '>=', $fee)->dec('usable_num', $fee) + ->inc('frozen_num', $fee) + ->update(['update_time' => $nowDate]); + if ($updateNumFee <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + + // 生成流水 + $insertStockLogArrFee = [ + 'user_id' => $userId, + 'change_type' => 16, // 新股申购扣减费用 + 'stock_id' => $tableObj['stock_id'], + 'before_num' => $beforeFee, + 'change_num' => '-' . $fee, + 'order_id' => $orderNo, + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $insertStockLogNumFee = Db::table($tableObj['log_table'])->insert($insertStockLogArrFee); + if ($insertStockLogNumFee <= 0) { + Db::rollback(); + return $this->toData('1', 'create user log error', []); + } + } + + Db::commit(); + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + Db::rollback(); + return $this->toData('1', 'System error', [$exception->getMessage(),$exception->getTrace()]); + } + } + + // 后支付 - 支付 + public function postPay1($marketType, $param, $userId) + { + try { + if (empty($param['id']) || empty($param['stock_code']) || !is_numeric($param['id'])) { + return $this->toData('1', 'Params error2', []); + } + + $tableObj = (new adminIPOService)->getStockModel($marketType); + $nowDate = date('Y-m-d H:i:s'); + + $preStock = Db::table($tableObj['stock_table'])->where('stock_code', $param['stock_code']) + ->where('status', 1) + ->where('is_delete', 1) + ->where('is_post_pay', 2) +// ->whereTime('pay_deadline_time', '>=', $nowDate) + ->find(); + if (empty($preStock)) { + return $this->toData('1', 'Payment deadline exceeded', []); + } + + $hasOrder = Db::table($tableObj['order_table'])->where('user_id', $userId)->where('id', $param['id'])->where('pay_type', 2)->where('status', 5)->find(); + if (empty($hasOrder)) { + return $this->toData('1', 'Params error3', []); + } + + $orderNo = $hasOrder['order_no']; + Db::startTrans(); + if ($preStock['sign_status'] == 1) { + //已签名 + $amount = $hasOrder['get_amount']; + $fee = $hasOrder['get_fee']; + $getNum = $hasOrder['get_num']; + if ($getNum <= 0) { + Db::rollback(); + return $this->toData('1', 'get num error', []); + } + + // 扣除用户资产 + $beforeAmount = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId)->value('usable_num'); + if ($beforeAmount < $amount) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + + $updateNum = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId) + ->where('usable_num', '>=', $amount)->dec('usable_num', $amount) + ->inc('frozen_num', $amount) + ->update(['update_time' => $nowDate]); + if ($updateNum <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + + // 生成流水 + $insertStockLogArr = [ + 'user_id' => $userId, + 'change_type' => 15, // 新股申购扣减费用 + 'stock_id' => $tableObj['stock_id'], + 'before_num' => $beforeAmount, + 'change_num' => '-' . $amount, + 'order_id' => $orderNo, + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $insertStockLogNum = Db::table($tableObj['log_table'])->insert($insertStockLogArr); + if ($insertStockLogNum <= 0) { + Db::rollback(); + return $this->toData('1', 'create user log error', []); + } + + // 扣除手续费 + if ($fee > 0) { + $beforeFee = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId)->value('usable_num'); + if ($beforeFee < $fee) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + + $updateNum = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId) + ->where('usable_num', '>=', $fee)->dec('usable_num', $fee) + ->inc('frozen_num', $fee) + ->update(['update_time' => $nowDate]); + if ($updateNum <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + + // 生成流水 + $insertStockLogArrFee = [ + 'user_id' => $userId, + 'change_type' => 16, // 新股申购扣减费用 + 'stock_id' => $tableObj['stock_id'], + 'before_num' => $beforeFee, + 'change_num' => '-' . $fee, + 'order_id' => $orderNo, + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $insertStockLogNumFee = Db::table($tableObj['log_table'])->insert($insertStockLogArrFee); + if ($insertStockLogNumFee <= 0) { + Db::rollback(); + return $this->toData('1', 'create user log error', []); + } + } + + if ($preStock['open_status'] == 1) { + //未上市 + $bool = Db::table($tableObj['order_table'])->where('id', $param['id'])->update(['status' => 2, 'update_time' => $nowDate]); + if (!$bool) { + Db::rollback(); + return $this->toData('1', 'update order error', []); + } + + } elseif ($preStock['open_status'] == 2) { + //已上市 + $bool = Db::table($tableObj['order_table'])->where('id', $param['id'])->update(['status' => 3, 'update_time' => $nowDate]); + if (!$bool) { + Db::rollback(); + return $this->toData('1', 'update order error', []); + } + + // 已上市 扣除手续费 冻结资金 + $num = Db::table($tableObj['user_table'])->where('user_id', $userId)->where('stock_id', $tableObj['stock_id']) + ->dec('frozen_num', $hasOrder['get_fee']) + ->update(['update_time' => $nowDate]); + if ($num <= 0) { + Db::rollback(); + trace('股票:' . $preStock['stock_code'] . ',扣除手续费失败,用户ID:' . $userId, 'error'); + } + // 手续费流水 + $tradeFee = new TradeFeeModel; + $tradeFee['user_id'] = $userId; + $tradeFee['account_type'] = $marketType; + $tradeFee['service_fee'] = $hasOrder['get_fee']; + $tradeFee['trade_type'] = 1; + $tradeFee['trade_no'] = $orderNo; + $tradeFee['create_time'] = date('Y-m-d H:i:s'); + $bool = $tradeFee->save(); + if (!$bool) { + Db::rollback(); + trace('股票:' . $preStock['stock_code'] . ',生成手续费失败,用户ID:' . $userId, 'error'); + } + } + } elseif ($preStock['sign_status'] == 2) { + //未签名 + $amount = $hasOrder['amount']; + $fee = $hasOrder['fee']; + // 扣除用户资产 + $beforeAmount = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId)->value('usable_num'); + if ($beforeAmount < $amount) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + + $updateNum = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId) + ->where('usable_num', '>=', $amount)->dec('usable_num', $amount) + ->inc('frozen_num', $amount) + ->update(['update_time' => $nowDate]); + if ($updateNum <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + + // 生成流水 + $insertStockLogArr = [ + 'user_id' => $userId, + 'change_type' => 15, // 新股申购扣减费用 + 'stock_id' => $tableObj['stock_id'], + 'before_num' => $beforeAmount, + 'change_num' => '-' . $amount, + 'order_id' => $orderNo, + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $insertStockLogNum = Db::table($tableObj['log_table'])->insert($insertStockLogArr); + if ($insertStockLogNum <= 0) { + Db::rollback(); + return $this->toData('1', 'create user log error', []); + } + + // 扣除手续费 + if ($fee > 0) { + $beforeFee = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId)->value('usable_num'); + if ($beforeFee < $fee) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + + $updateNumFee = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId) + ->where('usable_num', '>=', $fee)->dec('usable_num', $fee) + ->inc('frozen_num', $fee) + ->update(['update_time' => $nowDate]); + if ($updateNumFee <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + + // 生成流水 + $insertStockLogArrFee = [ + 'user_id' => $userId, + 'change_type' => 16, // 新股申购扣减费用 + 'stock_id' => $tableObj['stock_id'], + 'before_num' => $beforeFee, + 'change_num' => '-' . $fee, + 'order_id' => $orderNo, + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $insertStockLogNumFee = Db::table($tableObj['log_table'])->insert($insertStockLogArrFee); + if ($insertStockLogNumFee <= 0) { + Db::rollback(); + return $this->toData('1', 'create user log error', []); + } + } + $bool = Db::table($tableObj['order_table'])->where('id', $param['id'])->update(['status' => 1, 'update_time' => $nowDate]); + if (!$bool) { + Db::rollback(); + return $this->toData('1', 'update order error', []); + } + + } else { + Db::rollback(); + return $this->toData('1', 'Params error4', []); + } + Db::commit(); + + //已上市IPO 订单通知交易 转持仓 + if ($preStock->open_status == 2){ + Queue::push('app\admin\job\SendGo', [ + 'type' => 'last_trade', + 'id' => $preStock['id'], + 'stock_code' => $preStock['stock_code'], + 'order_no' => $orderNo, + 'market_type' => $marketType, + ], 'sendGo'); + } + + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + Db::rollback(); + return $this->toData('1', 'System error110', [$exception->getMessage(),$exception->getTrace()]); + } + } + public function postPay($marketType, $param, $userId){ + try { + if (empty($param['id']) || empty($param['stock_code']) || !is_numeric($param['id'])) { + return $this->toData('1', 'Params error2', []); + } + + $tableObj = (new adminIPOService)->getStockModel($marketType); + $nowDate = date('Y-m-d H:i:s'); + + $preStock = Db::table($tableObj['stock_table'])->where('stock_code', $param['stock_code']) + ->where('status', 1) + ->where('is_delete', 1) + ->where('is_post_pay', 2) +// ->whereTime('pay_deadline_time', '>=', $nowDate) + ->find(); + if (empty($preStock)) { + return $this->toData('1', 'Payment deadline exceeded', []); + } + if(strtotime($preStock['pay_deadline_time']) < time()){ + return $this->toData('1', 'The order has passed the payment deadline', []); + } + + $hasOrder = Db::table($tableObj['order_table'])->where('user_id', $userId)->where('id', $param['id'])->where('pay_type', 2)->whereIn('status', [5,6])->find(); + if (empty($hasOrder)) { + return $this->toData('1', 'Params error3', []); + } + + $orderNo = $hasOrder['order_no']; + Db::startTrans(); + + if ($preStock['sign_status'] == 1) { + //已签名 + $amount = $hasOrder['get_amount']; + $fee = $hasOrder['get_fee']; + $getNum = $hasOrder['get_num']; + }else{ + //未签名 + $amount = $hasOrder['amount']; + $fee = $hasOrder['fee']; + $getNum = $hasOrder['num']; + } + if ($getNum <= 0) { + Db::rollback(); + return $this->toData('1', 'get num error', []); + } + + // 扣除用户资产 + $beforeAmount = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId)->value('usable_num'); + if ($beforeAmount < $amount) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + $updateNum = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId) + ->where('usable_num', '>=', $amount)->dec('usable_num', $amount) + ->inc('frozen_num', $amount) + ->update(['update_time' => $nowDate]); + if ($updateNum <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + // 生成流水 + $insertStockLogArr = [ + 'user_id' => $userId, + 'change_type' => 15, // 新股申购扣减费用 + 'stock_id' => $tableObj['stock_id'], + 'before_num' => $beforeAmount, + 'change_num' => '-' . $amount, + 'order_id' => $orderNo, + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $insertStockLogNum = Db::table($tableObj['log_table'])->insert($insertStockLogArr); + if ($insertStockLogNum <= 0) { + Db::rollback(); + return $this->toData('1', 'create user log error', []); + } + + // 扣除手续费 + if ($fee > 0) { + $beforeFee = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId)->value('usable_num'); + if ($beforeFee < $fee) { + Db::rollback(); + return $this->toData('1', 'assert not enough', []); + } + + $updateNum = Db::table($tableObj['user_table'])->where('stock_id', $tableObj['stock_id'])->where('user_id', $userId) + ->where('usable_num', '>=', $fee)->dec('usable_num', $fee) + ->inc('frozen_num', $fee) + ->update(['update_time' => $nowDate]); + if ($updateNum <= 0) { + Db::rollback(); + return $this->toData('1', 'Update user amount error', []); + } + // 生成流水 + $insertStockLogArrFee = [ + 'user_id' => $userId, + 'change_type' => 16, // 新股申购扣减费用 + 'stock_id' => $tableObj['stock_id'], + 'before_num' => $beforeFee, + 'change_num' => '-' . $fee, + 'order_id' => $orderNo, + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $insertStockLogNumFee = Db::table($tableObj['log_table'])->insert($insertStockLogArrFee); + if ($insertStockLogNumFee <= 0) { + Db::rollback(); + return $this->toData('1', 'create user log error', []); + } + } + + if ($preStock['open_status'] == 1 && $preStock['sign_status'] == 1) { + //未上市 + $bool = Db::table($tableObj['order_table'])->where('id', $param['id'])->update(['status' => 2, 'update_time' => $nowDate]); + if (!$bool) { + Db::rollback(); + return $this->toData('1', 'update order error', []); + } + } elseif ($preStock['open_status'] == 2 && $preStock['sign_status'] == 1) { + //已上市 + $bool = Db::table($tableObj['order_table'])->where('id', $param['id'])->update(['status' => 3, 'update_time' => $nowDate]); + if (!$bool) { + Db::rollback(); + return $this->toData('1', 'update order error', []); + } + // 已上市 扣除手续费 冻结资金 + $num = Db::table($tableObj['user_table'])->where('user_id', $userId)->where('stock_id', $tableObj['stock_id']) + ->dec('frozen_num', $hasOrder['get_fee']) + ->update(['update_time' => $nowDate]); + if ($num <= 0) { + Db::rollback(); + trace('股票:' . $preStock['stock_code'] . ',扣除手续费失败,用户ID:' . $userId, 'error'); + } + // 手续费流水 + $tradeFee = new TradeFeeModel; + $tradeFee['user_id'] = $userId; + $tradeFee['account_type'] = $marketType; + $tradeFee['service_fee'] = $hasOrder['get_fee']; + $tradeFee['trade_type'] = 1; + $tradeFee['trade_no'] = $orderNo; + $tradeFee['create_time'] = date('Y-m-d H:i:s'); + $bool = $tradeFee->save(); + if (!$bool) { + Db::rollback(); + trace('股票:' . $preStock['stock_code'] . ',生成手续费失败,用户ID:' . $userId, 'error'); + } + } + + if ($preStock['sign_status'] == 2){ + $bool = Db::table($tableObj['order_table'])->where('id', $param['id'])->update(['status' => 1, 'update_time' => $nowDate]); + if (!$bool) { + Db::rollback(); + return $this->toData('1', 'update order error', []); + } + } + + + Db::commit(); + return $this->toData('0', 'SUCCESS', []); + } catch (\Exception $exception) { + Db::rollback(); + return $this->toData('1', 'System error', [$exception->getMessage(),$exception->getTrace()]); + } + } + + // 申购记录 + public function list($marketType, $param, $userId) + { + try { + if (empty($param['page']) || !is_numeric($param['page']) || empty($param['limit']) || !is_numeric($param['limit'])) { + $param['page'] = 1; + $param['limit'] = 20; + } + + if (empty($param['status'])) { + return $this->toData('1', 'Params error'); + } + + $tableObj = (new adminIPOService)->getStockModel($marketType); + $nowDate = date('Y-m-d H:i:s'); + + $statusArr = explode(",", $param['status']); + $list = Db::table($tableObj['order_table'])->whereIn('status', $statusArr)->where('user_id', $userId)->order('update_time', 'desc')->page($param['page'], $param['limit'])->select(); + $total = Db::table($tableObj['order_table'])->whereIn('status', $statusArr)->where('user_id', $userId)->count(); + $rows = []; + if (!$list->isEmpty()) { + $stockIdList = []; + foreach ($list as $item) { + $stockIdList[] = $item['pre_stock_id']; + } + + $stockList = Db::table($tableObj['stock_table'])->where('id', 'in', $stockIdList)->column(['*'], 'id'); + + // 计算手续费 + $purchaseFee = FeeSettingModel::where('market_type', $marketType)->value('purchase_fee'); + foreach ($list as $item) { + $stock = $stockList[$item['pre_stock_id']] ?? []; + $openTime = $stock['open_time'] ?? ''; + $openStatus = $stock['open_status'] ?? '0'; + + // 是否延期开盘 + $is_defer = '0'; + if ($openTime && $openTime < $nowDate && $openStatus == 1) { + $is_defer = '1'; + } + $arr = [ + 'id' => $item['id'], + 'order_no' => $item['order_no'], + 'stock_code' => $stock['stock_code'] ?? '-', + 'stock_name' => $stock['stock_name'] ?? '-', + 'get_time' => $stock['get_time'] ?? '-', + 'open_time' => $stock['open_time'] ?? '-', + 'num' => $item['num'], + 'get_num' => $item['get_num'], + 'price' => $item['price'], + 'amount' => $item['amount'], + 'get_amount' => $item['get_amount'], + 'create_time' => $item['create_time'], + 'fee' => $item['fee'], + 'get_fee' => $item['get_fee'], + 'status' => $item['status'], + 'tape' => $stock['tape'] ?? '-', + 'stock_type' => $stock['stock_type'] ?? '-', + 'is_defer' => $is_defer, + 'stock_data' => $stock, + 'pay_deadline_time' => $stock['pay_deadline_time'] ?? '-', + ]; + + if ($item['pay_type'] == 2 && $item['status'] == 5 && empty($item['get_time'])) { + //后支付 + $arr['amount'] = bcmul($item['get_num'], $item['price'], 18); + if ($purchaseFee <= 0) { + $arr['fee'] = 0; + } else { + $arr['fee'] = bcmul($arr['amount'], $purchaseFee, 18); + } + } + $rows[] = $arr; + } + } + + $extend = (new adminIPOService)->getStockTape($marketType); + return $this->toData('0', 'SUCCESS', ['list' => $rows, 'total' => $total, 'extend' => [ + 'tape_list' => $extend['tape'], + 'stock_type_list' => $extend['type'], + ]]); + } catch (\Exception $exception) { + return $this->toData('1', 'System error', []); + } + } + + // 申购订单详情 + public function detail($marketType, $param, $userId) + { + try { + if (empty($param['id']) || !is_numeric($param['id'])) { + return $this->toData('1', 'Params error', []); + } + + $tableObj = (new adminIPOService)->getStockModel($marketType); + $order = Db::table($tableObj['order_table'])->where('user_id', $userId)->where('id', $param['id'])->find(); + if (empty($order)) { + return $this->toData('1', 'Params error', []); + } + + $stock = Db::table($tableObj['stock_table'])->where('id', $order['pre_stock_id'])->find(); + if (empty($stock)) { + return $this->toData('1', 'Params error', []); + } + + $is_defer = '0'; + if ($stock['open_status'] == 1) { + $is_defer = '1'; + } + + $data = [ + 'logo' => $stock['logo'], + 'stock_code' => $stock['stock_code'], + 'stock_name' => $stock['stock_name'], + 'stock_type' => $stock['stock_type'], + 'sign_status' => $stock['sign_status'], + 'num' => $order['num'], + 'get_num' => $order['get_num'], + 'amount' => $order['amount'], + 'get_amount' => $order['get_amount'], + 'price' => $order['price'], + 'fee' => $order['fee'], + 'order_no' => $order['order_no'], + 'get_fee' => $order['get_fee'], + 'create_time' => $order['create_time'], + 'get_time' => $order['get_time'], + 'open_time' => $stock['open_time'], + 'tape' => $stock['tape'], + 'is_defer' => $is_defer, + 'stock_data' => $stock, + 'pay_deadline_time' => $stock['pay_deadline_time'], + 'status' => $order['status'] + ]; + + $extend = (new adminIPOService)->getStockTape($marketType); + return $this->toData('0', 'SUCCESS', ['data' => $data, 'extend' => [ + 'tape_list' => $extend['tape'], + 'stock_type_list' => $extend['type'], + ]]); + } catch (\Exception $exception) { + return $this->toData('1', 'System error', [$exception->getMessage(),$exception->getTrace()]); + } + } + + +} diff --git a/app/home/service/IndPayService.php b/app/home/service/IndPayService.php new file mode 100644 index 0000000..05b4754 --- /dev/null +++ b/app/home/service/IndPayService.php @@ -0,0 +1,407 @@ +makeMd5Sign($sign_data); + if($sign==$data['sign'] && $data['status']=='SUCCESS'){ + Log::info('回调签名检验成功:'.$sign.'-----'.$data['sign']); + $order_info=RechargeApplyModel::getOrderByNo([ + 'order_no'=>$data['mer_order_no'], + 'order_idx'=>$data['order_no'], + ]); + if(empty($order_info)){ + Log::info('回调检验订单失败:'.$data['mer_order_no']); + return [ + 'code'=>100130, + 'msg'=>'FAIL' + ]; + } + if($order_info['status']==0){ + return (new PayService())->dealPayNotify($order_info); + }else{ + return [ + 'code'=>200, + 'msg'=>'SUCCESS' + ]; + } + }else{ + Log::info('回调签名检验失败:'.$sign.'-----'.$data['sign']); + return [ + 'code'=>100120, + 'msg'=>'FAIL' + ]; + } + } + + public function indPay($out_trade_no,$order_amount) + { + $url=env('PAY.NOTIFY_URL'); + $notifyUrl=$url.url('indpay_notify'); + $pageUrl=$url.url('indpay_query'); + $data['mer_no']=$this->mch_id; + $data['mer_order_no']=$out_trade_no; + $data['pname']='test'; + $data['pemail']='test@mail.com'; + $data['phone']="9852146882";//限制只能为数字号码 + $data['order_amount']=$order_amount; + //$data['order_amount']=100000; + $data['ccy_no']="IDR"; + $data['busi_code']="100401";##支付编码 + $data['notifyUrl']=$notifyUrl;##回调地址 + $data['pageUrl']=$pageUrl;##跳转地址 + Log::info('支付post数据:'.json_encode($data)); + $data=$this->encrypt($data); + $data=json_encode($data, JSON_UNESCAPED_UNICODE); + $url='https://cqdft.dyb360.com/ty/orderPay'; + $ret=$this->globalpay_http_post_res_json($url,$data); + Log::info('支付返回数据:'.json_encode($ret)); + return $ret; + } + public function singleIndOrder($order) + { + //$order=UserWithdrawalModel::where('id',1)->find()->toArray(); + $url=env('PAY.NOTIFY_URL'); + $notifyUrl=$url.url('single_notify'); + + $pay_info=json_decode($order['pay_info'],true); + + $data['mer_no']=$this->mch_id; + $data['mer_order_no']=$order['order_no']; + $data['acc_no']=$pay_info['bank_card']; + $data['acc_name']=$pay_info['true_name']; + $data['bank_code']=$pay_info['bank_code'];##'=>'银行编码 + $data['ccy_no']='IDR'; + $data['order_amount']=round($order['total_amount'],2); + $data['mobile_no']=$pay_info['bank_phone'];//限制只能为数字号码 + $data['summary']='summary';##备注 + $data['notifyUrl']=$notifyUrl;//回调地址 代付成功失败都走回调 + + $data=$this->encrypt($data); + + $data=json_encode($data, JSON_UNESCAPED_UNICODE); + $url='https://sbgdt.dyb360.com/withdraw/singleOrder'; + $ret=$this->globalpay_http_post_res_json($url,$data); + $code=300; + $order_idx=''; + if($ret['status']=='SUCCESS'){ + $code=200; + $order_idx=$ret['order_no']; + } + return [ + 'code'=>$code, + 'msg'=>$ret['status'], + 'order_idx'=>$order_idx + ]; + } + public function getIndBalance(){ + $data['mer_no']=$this->mch_id; + $data['request_no']=$this->generateOrderNumber(); + $data['request_time']=date('YmdHis'); + $data=$this->encrypt($data); + $data=json_encode($data, JSON_UNESCAPED_UNICODE); + $url='https://sbgdt.dyb360.com/withdraw/balanceQuery'; + $ret=$this->globalpay_http_post_res_json($url,$data); + //var_dump($ret); + + } + + public function singleIndNotify(array $data) + { + $sign_data=$data; + unset($sign_data['sign']); + $sign=$this->makeMd5Sign($sign_data); + if($sign==$data['sign'] && $data['status']=='SUCCESS'){ + Log::info('代付回调签名检验成功:'.$sign.'-----'.$data['sign']); + $order=UserWithdrawalModel::where([ + 'order_no'=>$data['mer_order_no'], + 'order_idx'=>$data['order_no'] + ])->find(); + if(empty($order)){ + return [ + 'code'=>400, + 'msg'=>'FAIL' + ]; + } + $order_info=$order->toArray(); + if($order_info['status']==3){ + UserWithdrawalModel::where('id',$order_info['id'])->update([ + 'deal_time'=>date('Y-m-d H:i:s'), + 'status'=>4 + ]); + } + return [ + 'code'=>200, + 'msg'=>'SUCCESS' + ]; + }else{ + Log::info('代付回调签名检验失败:'.$sign.'-----'.$data['sign']); + return [ + 'code'=>100120, + 'msg'=>'FAIL' + ]; + } + } + private function decrypt($data){ + $mch_public_key=$this->public_key; + ksort($data); + $toSign =''; + foreach($data as $key=>$value){ + if(strcmp($key, 'sign')!= 0 && $value!=''){ + $toSign .= $key.'='.$value.'&'; + } + } + $str = rtrim($toSign,'&'); + $encrypted = ''; + //替换自己的公钥 + $pem = chunk_split( $mch_public_key,64, "\n"); + $pem = "-----BEGIN PUBLIC KEY-----\n" . $pem . "-----END PUBLIC KEY-----\n"; + $publickey = openssl_pkey_get_public($pem); + + $base64=str_replace(array('-', '_'), array('+', '/'), $data['sign']); + + $crypto = ''; + foreach(str_split(base64_decode($base64), 128) as $chunk) { + openssl_public_decrypt($chunk,$decrypted,$publickey); + $crypto .= $decrypted; + } + if($str != $crypto){ + exit('sign fail11'); + } + } + +//支付加密 + private function encrypt($data){ + $mch_private_key=$this->private_key; + ksort($data); + $str = ''; + foreach ($data as $k => $v){ + if(!empty($v)){ + $str .=(string) $k.'='.$v.'&'; + } + } + $str = rtrim($str,'&'); + $encrypted = ''; + //替换成自己的私钥 + $pem = chunk_split($mch_private_key, 64, "\n"); + $pem = "-----BEGIN PRIVATE KEY-----\n" . $pem . "-----END PRIVATE KEY-----\n"; + $private_key = openssl_pkey_get_private($pem); + $crypto = ''; + foreach (str_split($str, 117) as $chunk) { + openssl_private_encrypt($chunk, $encryptData, $private_key); + $crypto .= $encryptData; + } + $encrypted = base64_encode($crypto); + $encrypted = str_replace(array('+','/','='),array('-','_',''),$encrypted); + + $data['sign']=$encrypted; + return $data; + } + +//请求 + private function globalpay_http_post_res_json($url, $postData) + { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json; charset=utf-8', + 'Content-Length:' . strlen($postData) , + 'Cache-Control: no-cache', + 'Pragma: no-cache' + )); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + $res = curl_exec($curl); + $errorno = curl_errno($curl); + curl_close($curl); + $result=json_decode($res,true); + //var_dump($res,$errorno); + //echo $postData; + return $result; + } + +//生成查询签名 + private function makeMd5Sign($data){ + $md5_key=$this->md5_key; + ksort($data); + $str = ''; + foreach ($data as $k => $v){ + if(!empty($v)){ + $str .=(string) $k.'='.$v.'&'; + } + } + $str = rtrim($str,'&'); + $str .='&key='.$md5_key; + + //加密 + $sign = md5($str); + return $sign; + } + public function getBankList() + { + $back_list=[ + 'COMMONWEALTH'=>'Bank Commonwealth', + 'CHINATRUST'=>'Bank CTBC (China Trust) Indonesia', + 'BANK_OCBC'=>'Bank OCBC – Indonesia', + 'BANK_MAYBANK'=>'Bank Maybank Indocorp', + 'BANK_MERIN'=>'Bank Merincorp', + 'BANK_AGRIS'=>'Bank Agris', + 'LINK_AJA'=>'Link Aja', + 'DOMPETKU'=>'Indosat Dompetku', + 'BPR_KS'=>'BPR KS', + 'HARDA_INTERNASIONAL'=>'Bank Harda', + 'BANK_VICTORIA'=>'Bank Victoria International', + 'MANDIRI_TASPEN'=>'Bank Mandiri Taspen Pos', + 'FAMA'=>'Bank Fama Internasional', + 'CENTRATAMA'=>'Centratama Nasional Bank', + 'INDEX_SELINDO'=>'Bank Index Selindo', + 'MAYORA'=>'Bank Mayora Indonesia', + 'MULTI_ARTA_SENTOSA'=>'Bank Multi Arta Sentosa', + 'BTPN_SYARIAH'=>'Bank Purba Danarta', + 'ARTOS'=>'Bank Artos IND', + 'BCA_SYR'=>'Bank BCA Syariah', + 'BANK_KESEJAHTERAAN_EKONOMI'=>'Bank Kesejahteraan Ekonomi', + 'BANK_ANGLOMAS'=>'Anglomas Internasional Bank', + 'BANK_LIMAN'=>'Liman International Bank', + 'BANK_AKITA'=>'Bank Akita', + 'OCBC'=>'Bank Dipo International (Bank Sahabat Sampoerna)', + 'BANK_PERSY'=>'Bank Persyarikatan Indonesia', + 'PRIMA_MASTER'=>'Prima Master Bank', + 'BANK_HARFA'=>'Bank Harfa', + 'BANK_INA'=>'Bank Ina Perdana', + 'MEGA_SYR'=>'Bank Syariah Mega', + 'NATIONALNOBU'=>'Bank Alfindo (Bank National Nobu)', + 'ROYAL'=>'Bank Royal Indonesia', + 'BANK_INDOMONEX'=>'ank Indomonex (Bank SBI Indonesia)', + 'AGRONIAGA'=>'Bank BRI Agro', + 'BANK_YUDHA'=>'Bank Yudha Bhakti', + 'BANK_BUMIPUTERA'=>'Bank MNC / Bank Bumiputera', + 'BANK_BINTANG'=>'Bank Bintang Manunggal', + 'JASA_JAKARTA'=>'Bank Jasa Jakarta', + 'BANK_SRI_PARTHA'=>'Bank Sri Partha', + 'BISNIS_INTERNASION'=>'Bank Bisnis Internasional', + 'MANDIRI_SYR'=>'Bank Syariah Mandiri(BSI)', + 'BUKOPIN'=>'Bank Bukopin', + 'BNI_SYR'=>'Bank BNI Syariah', + 'MEGA'=>'Bank Mega', + 'BJB_SYR'=>'Bank BJB Syariah', + 'BANK_SWAGUNA'=>'Bank Swaguna', + 'TABUNGAN_PENSIUNAN_NASIONAL'=>'Bank Tabungan Pensiunan Nasional (BTPN)', + 'JENIUS'=>'JENIUS', + 'BANK_HIM'=>'Bank Himpunan Saudara 1906', + 'BTN'=>'Bank Tabungan Negara (BTN)', + 'QNB_INDONESIA'=>'Bank QNB Kesawan (Bank QNB Indonesia)', + 'BANK_HARM'=>'Bank Harmoni International', + 'ICBC Halim Indonesia'=>'Bank (Bank ICBC Indonesia)', + 'CCB'=>'Bank Windu Kentjana', + 'GANESHA'=>'Bank Ganesha', + 'BANK_HAGAKITA'=>'Bank Hagakita', + 'MASPION'=>'Bank Maspion Indonesia', + 'SINARMAS_UUS'=>'Bank Sinarmas', + 'SHINHAN'=>'Bank Metro Express (Bank Shinhan Indonesia)', + 'MESTIKA_DHARMA'=>'Bank Mestika Dharma', + 'MUAMALAT'=>'Bank Muamalat', + 'BANK_OF_INDIA'=>'Bank of India Indonesia', + 'NUSANTARA_PARAHYANGAN'=>'Bank Nusantara Parahyangan', + 'BANK_SULTRA'=>'Bank Sultra', + 'SULAWESI'=>'Bank Sulawesi Tengah', + 'BENGKULU'=>'Bank Bengkulu', + 'PAPUA'=>'Bank Papua', + 'MALUKU'=>'Bank Maluku Malut', + 'BANK_NTT'=>'Bank NTT', + 'BALI BPD'=>'Bali', + 'BPD_NTB'=>'Bank NTB, NTB Syariah', + 'SUMSEL_DAN_BABEL_SULUT'=>'Bank Sulut Gorontalo', + 'SULSELBAR'=>'Bank Sulsel dan Barat', + 'BPD_KALTENG'=>'Bank Kalteng', + 'BPD_KAITIM'=>'Bank Kalimantan Timur dan Utara', + 'KALIMANTAN_BARAT'=>'Bank Kalimantan Barat', + 'BPD_KALSEL'=>'Bank Kalsel', + 'LAMPUNG'=>'Bank Lampung', + 'SUMSEL_DAN_BABEL'=>'Bank Sumsel Babel', + 'RIAU_DAN_KEPRI'=>'Bank Riau', + 'BANK_NAGARI'=>'Bank Nagari', + 'SUMUT'=>'Bank Sumut', + 'ACEH BPD Aceh'=>'BPD Aceh Syariah', + 'JAMBI'=>'BPD Jambi', + 'BANK_JATIM'=>'Bank Jatim', + 'BANK_JATENG'=>'Bank Jateng', + 'DAERAH_ISTIMEWA'=>'BPD DIY', + 'DKI'=>'Bank DKI', + 'BANK_JABAR'=>'Bank Jabar dan Banten (BJB)', + 'MAYAPADA'=>'Bank Mayapada', + 'JTRUST'=>'Bank JTRUST', + 'BANK_IFI'=>'Bank IFI', + 'BANK_HAGA'=>'Bank Haga', + 'BANK_ANTAR'=>'Bank Antardaerah', + 'BANK_EKONOMI'=>'Bank Ekonomi', + 'BUMI_ARTA'=>'Bank Bumi Arta', + 'BOC'=>'Bank OF China', + 'BANK_WOOR'=>'Bank Woori Indonesia', + 'DEUTSCHE'=>'Deutsche Bank AG.', + 'BANK_ANZ'=>'Bank ANZ Indonesia', + 'BANK_DANAMON'=>'Korea Exchange Bank Danamon', + 'BNP_PARIBAS'=>'Bank BNP Paribas Indonesia', + 'CAPITAL'=>'Bank Capital Indonesia', + 'BANK_KEPPEL'=>'Bank Keppel Tatlee Buana', + 'BANK_A'=>'Bank ABN Amro', + 'STANDARD_CHARTERED'=>'Standard Chartered Bank', + 'MIZUHO'=>'Bank Mizuho Indonesia', + 'RESONA'=>'Bank Resona Perdania', + 'DBS'=>'Bank DBS Indonesia', + 'MITSUI'=>'Bank Sumitomo Mitsui Indonesia', + 'BANK_TOKYO'=>'The Bank of Tokyo Mitsubishi UFJ LTD', + 'HSBC'=>'The Hongkong & Shanghai B.C. (Bank HSBC)', + 'BANK_COMP'=>'The Bangkok Bank Comp. LTD', + 'BANK_C_AGR'=>'Credit Agricole Indosuez', + 'ARTHA'=>'Bank Artha Graha Internasional', + 'BANK_ING'=>'ING Indonesia Bank', + 'BAML'=>'Bank of America, N.A', + 'JPMORGAN'=>'JP. Morgan Chase Bank, N.A', + 'CITIBANK'=>'Citibank', + 'BANK_LTD'=>'American Express Bank LTD', + 'NISP'=>'Bank OCBC NISP', + 'BANK_LIPPO'=>'Bank Lippo', + 'CIMB'=>'Bank CIMB Niaga', + 'ARTA_NIAGA_KENCANA'=>'Bank Arta Niaga Kencana', + 'PANIN'=>'Bank Panin', + 'MAYBANK'=>'Bank BII Maybank', + 'BCA'=>'Bank BCA', + 'PERMATA'=>'Permata Bank', + 'DANAMON'=>'Bank Danamon', + 'BNI'=>'Bank BNI', + 'MANDIRI'=>'Bank Mandiri', + 'EXIMBANK'=>'Bank Ekspor Indonesia', + 'BRI'=>'Bank BRI', + 'BANK_BUANA'=>'Bank UOB Indonesia', + 'BNC'=>'BNC' + ]; + return $this->toData(0,'Request successful.',$back_list); + } + + +} \ No newline at end of file diff --git a/app/home/service/LanguageService.php b/app/home/service/LanguageService.php new file mode 100644 index 0000000..011d0ab --- /dev/null +++ b/app/home/service/LanguageService.php @@ -0,0 +1,23 @@ +toData(0,'Request successful.',$list); + } + public function getServiceList() : array + { + $list=ServiceSettingModel::getServiceList(); + return $this->toData(0,'Request successful.',$list); + } + +} \ No newline at end of file diff --git a/app/home/service/LoginService.php b/app/home/service/LoginService.php new file mode 100644 index 0000000..b995dae --- /dev/null +++ b/app/home/service/LoginService.php @@ -0,0 +1,773 @@ +getClientRealIp(); + + // 参数校验 + validate(LoginValidate::class)->scene('sendEmail')->check($param); + + $param['email'] = trim($param['email']); + // 邮箱类型校验 去除国内邮箱 + if ($this->checkForbidEmail($param['email'])) { + return $this->toData('100300', 'The email is not supported.', []); + } + + // 每天获取code 次数限制 + $sendCodeKey = 'USER:SEND_CODE_NUM:' . $ip; + if ($this->checkGetNoTradeCodeNum($sendCodeKey)) { + return $this->toData('100300', 'The maximum number of attempts for today has been exceeded. Please try again tomorrow.', []); + } + + // 获取发送的邮件内容 + $content = $this->getEmailContent(); + $content['email'] = $param['email']; + + + // 将发送邮件任务添加到异步队列 + $queuename = 'app\home\job\SendEmail'; + Queue::push($queuename, $content, 'sendEmail'); + + // 邮件code存到缓存(未登录操作共用) + $key = 'DB:USER:UNLOGIN:EMAIL_CODE:' . $param['email']; + $this->insertCodeToCache($key, $content['code'], 300); + + // 记录已经发送的code次数 + $this->updateHadGetCodeNumCache($sendCodeKey); + + // 返回结果 + return $this->toData('0', 'Email sent successfully. Please check your inbox.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + // 异常情况 + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 邮箱注册用户 + * @param $param + * @return array + * @throws InvalidArgumentException + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function registerEmail($param): array + { + try { + // 获取客户端ip + $ip = $this->getClientRealIp(); + + $param['invite_code'] = $param['invite_code'] ?? ''; + $param['agent_code'] = $param['agent_code'] ?? ''; + + // 邮件注册参数校验 + validate(LoginValidate::class)->scene('emailRegister')->check($param); + + // 判断注册数量 ip每天可注册数量 + $ipCanRegisterNumPerIpPerDay = 'USER:REGISTER:' . $ip; + if ($this->checkRegisterLimit($ipCanRegisterNumPerIpPerDay)) { + return $this->toData('100300', 'The maximum number of attempts for today has been exceeded. Please try again tomorrow.', []); + } + + // 验证验证码 + $emailKey = 'DB:USER:UNLOGIN:EMAIL_CODE:' . $param['email']; + if (!$this->checkCode($emailKey, $param['email_code'])) { + //注册验证码 + $reg_key = "USER:REG:CODE"; + if (!$this->checkCode($reg_key, $param['email_code'])) { + return $this->toData('100300', 'The verification code is incorrect.', []); + } else { + $code = random_int(1000, 9999); + $this->insertCodeToCache($reg_key, $code, 300); + } + } + + $email = $param['email']; + $inviteCode = trim($param['invite_code']); + $agentCode = trim($param['agent_code']); + + // 邮箱是否已经存在 + $emailExists = UserModel::checkEmailExists($email); + if ($emailExists) { + return $this->toData('100300', 'The email has already been registered.', []); + } + + // 判断邀请人是否存在 + $agentId = 0; + $parentUserId = 0; + if (!empty($inviteCode)) { + $agentId = AdminModel::getIdByInviteCode($inviteCode); + if ($agentId <= 0) { + $parentUserId = $this->getParentIdByInviteCode($inviteCode); + if ($parentUserId <= 0) { + return $this->toData('100400', 'The invitation code is invalid.', []); + } + } + } + + // 判断代理人是否存在 + if (!empty($agentCode) || $agentId > 0) { + if ($agentId == 0) { + $agentId = AdminModel::getIdByInviteCode($agentCode); + if ($agentId <= 0) { + return $this->toData('100400', 'The invitation code is invalid.', []); + } + } + } else { + // 是否必须填写有效的邀请码 + $inviteCodeIsRequired = env("REG_USER.INVITE_CODE_REQUIRED"); + if ($parentUserId <= 0 && $inviteCodeIsRequired >= 1) { + return $this->toData('100400', 'The invitation code is invalid.', []); + } + } + + // 入库 + $userNo = $this->getUniqUserNo(); + $salt = env('ENCRYPT.SALT'); + $password = (new UnqId())->encryptPassword($param['password'], $salt); + $userInviteCode = $this->getUniqInviteCode(); + // 需要开启事务 + \think\facade\Db::transaction(function () use ($email, $userNo, $userInviteCode, $parentUserId, $password, $ip, $salt, $agentId) { + // 生成用户数据 + $userId = UserModel::emailRegister($email, $userNo, $userInviteCode, $parentUserId, $password, $ip, $salt, 1, $agentId); + // 生成钱包地址 + (new UserService())->doRegInitUserInfo($userId, $parentUserId); + }); + // 删除缓存 + $this->delCache($emailKey); + // 累加已经注册的个数 + $this->updateHadRegisterNumCache($ipCanRegisterNumPerIpPerDay); + return $this->toData('0', 'Registration Successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + trace('【注册错误】提交数据:'.json_encode($param), 'error'); + trace('【注册错误】'.$exception->getMessage(), 'error'); + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * @desc 登陆业务处理接口 + * @param array $param + * @return array + */ + public function loginEmail(array $param): array + { + try { + // 参数校验 邮箱 密码 + validate(LoginValidate::class)->scene('emailLogin')->check($param); + + $param['email'] = trim($param['email']); + // 查找邮箱 + $userId = UserModel::getUserIdByEmail($param['email']); + if ($userId <= 0) { + return $this->toData('100300', 'The user does not exist.', []); + } + + // 查找用户信息 + $user = UserModel::getFieldsByUserId('invite_code,user_id,user_no,nick_name,is_real,login_password,salt', $userId); + if (empty($user)) { + return $this->toData('100300', 'Incorrect account or password.', []); + } + + // 校验密码 + $checkPasswordBool = (new UnqId())->checkPassword($param['password'], $user['login_password'], $user['salt']); + if (!$checkPasswordBool) { + return $this->toData('100300', 'Incorrect account or password.', []); + } + + // 生成token + $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); + if (empty($token)) { + return $this->toData('100300', 'The system is busy.', []); + } + + // 用户登陆之后需要进行的操作 异步完成 + Queue::push('app\home\job\LoginDone', ['userId' => $userId, + 'fields' => [ + 'last_login_time' => date('Y-m-d H:i:s'), + 'ip' => $this->getClientRealIp(), + 'device' => $param['device'], + + ] + ], 'loginDone'); + + // 将token存致缓存 覆盖新的缓存 实现单设备登陆 + $this->setUserTokenCache($token, $userId); + + // 用户登记关系 + (new UserService())->getUserLevel($userId); + + // 返回结果以及用户信息 + return $this->toData('0', 'Request successful.', [ + 'userId' => $userId, + 'userNo' => $user['user_no'], + 'nickName' => $user['nick_name'], + 'inviteCode' => $user['invite_code'], + 'isReal' => $user['is_real'], + 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), + 'token' => $token, + ]); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (InvalidArgumentException $invalidArgumentException) { + return $this->toData('100400', 'The system is busy. Please try again later.', []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', []); + } + } + + /** + * @desc未登陆获取短信验证码 + * @param array $param + * @return array + * @throws InvalidArgumentException + */ + public function sendSms(array $param): array + { + try { + // 防止重复操作 单个ip 3秒钟内只能请求一次 + $ip = $this->getClientRealIp(); + + // 参数校验 + validate(LoginValidate::class)->scene('sendSms')->check($param); + + $param['nation'] = trim($param['nation']); + $param['phone'] = trim($param['phone']); + // 去除国内手机号 + if ($this->checkForbidNation($param['nation'])) { + return $this->toData('100300', 'Unsupported country or region.', []); + } + + // 判断国家码是否有效 + $nationExists = CountryModel::checkCodeExists($param['nation']); + if (!$nationExists) { + return $this->toData('100300', 'Unsupported country or region.', []); + } + + // 发送次数校验 - 号码 + $phoneSendCodeKey = 'USER:PHONE_SEND_CODE_NUM:' . $param['nation'].':'.$param['phone']; + if ($this->checkGetNoTradeCodeNumPhone($phoneSendCodeKey)) { + return $this->toData('100300', 'No worries. Please feel free to reach out again tomorrow.', []); + } + + // 发送次数校验 - ip + $ipSendCodeKey = 'USER:IP_SEND_CODE_NUM:' . $ip; + if ($this->checkGetNoTradeCodeNum($ipSendCodeKey)) { + return $this->toData('100300', 'No worries. Please feel free to reach out again tomorrow.', []); + } + + // 获取发送内容 + $content = $this->getSmsContent(); + $mobile = $param['nation'] . $param['phone']; + $content['mobile'] = $mobile; + + // 异步发送 + $queuename = 'app\home\job\SendSms'; + Queue::push($queuename, $content, 'sendSms'); + + // 短信code存到缓存(未登录操作共用) + $key = 'DB:USER:UNLOGIN:SMS_CODE:' . $mobile; + $this->insertCodeToCache($key, $content['code'], 300); + + // 累加已经获取的次数 + $this->updateHadGetCodeNumCache($phoneSendCodeKey); + $this->updateHadGetCodeNumCache($ipSendCodeKey); + + // 返回结果 + return $this->toData('0', 'The message has been sent. Please check your inbox.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + trace('【注册错误】提交数据:'.json_encode($param), 'error'); + trace('【注册错误】'.$exception->getMessage(), 'error'); + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + /** + * @desc 短信注册 + * @param array $param + * @return array + * @throws InvalidArgumentException + */ + public function registerSms(array $param): array + { + try { + // 防止重复操作 + $ip = $this->getClientRealIp(); + + $param['invite_code'] = $param['invite_code'] ?? ''; + $param['agent_code'] = $param['agent_code'] ?? ''; + + // 短信注册参数校验 + validate(LoginValidate::class)->scene('smsRegister')->check($param); + + // 判断注册数量 ip每天可注册数量 + $ipCanRegisterNumPerIpPerDay = 'USER:REGISTER:' . $ip; + $this->checkRegisterLimit($ipCanRegisterNumPerIpPerDay); + + // 校验验证码 + $mobile = $param['nation'] . $param['phone']; + $smsKey = 'DB:USER:UNLOGIN:SMS_CODE:' . $mobile; + if (!$this->checkCode($smsKey, $param['sms_code'])) { + $reg_key = "USER:REG:CODE"; + //注册验证码 + if (!$this->checkCode($reg_key, $param['sms_code'])) { + return $this->toData('100300', 'The verification code is incorrect.', []); + } +// else { +// $code = random_int(1000, 9999); +// $this->insertCodeToCache($reg_key, $code, 300); +// } + } + + // 手机号是否已经存在 + $phoneExists = UserModel::checkPhoneExists($param['phone']); + if ($phoneExists) { + return $this->toData('100300', 'The phone number has already been registered.', []); + } + + // 邀请人 + $inviteCode = trim($param['invite_code']); + $agentCode = trim($param['agent_code']); + $parentUserId = 0; + $agentId = 0; + if (!empty($inviteCode)) { + $agentId = AdminModel::getIdByInviteCode($inviteCode); + if ($agentId <= 0) { + $parentUserId = $this->getParentIdByInviteCode($inviteCode); + if ($parentUserId <= 0) { + return $this->toData('100400', 'The invitation code is invalid.', []); + } + } + } + + // 判断代理人是否存在 + if (!empty($agentCode) || $agentId > 0) { + if ($agentId == 0) { + $agentId = AdminModel::getIdByInviteCode($agentCode); + if ($agentId <= 0) { + return $this->toData('100400', 'The invitation code is invalid.', []); + } + } + } else { + // 是否必须填写有效的邀请码 + $inviteCodeIsRequired = env("REG_USER.INVITE_CODE_REQUIRED"); + if ($parentUserId <= 0 && $inviteCodeIsRequired >= 1) { + return $this->toData('100400', 'The invitation code is invalid.', []); + } + } + + // 入库 + $userNo = $this->getUniqUserNo(); + $salt = env('ENCRYPT.SALT'); + $password = (new UnqId())->encryptPassword($param['password'], $salt); + $userInviteCode = $this->getUniqInviteCode(); + + // 需要开启事务 + \think\facade\Db::transaction(function () use ($param, $userNo, $userInviteCode, $parentUserId, $password, $ip, $salt, $agentId) { + // 生成用户数据 + $userId = UserModel::phoneRegister($param['nation'], $param['phone'], $userNo, $userInviteCode, $parentUserId, $password, $ip, $salt, 1, $agentId); + // 生成钱包地址 + (new UserService())->doRegInitUserInfo($userId, $parentUserId); + }); + + // 删除缓存 + $this->delCache($smsKey); + + // 更新注册个数 + $this->updateHadRegisterNumCache($ipCanRegisterNumPerIpPerDay); + + return $this->toData('0', 'Registration Successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * @desc 短信验证码登陆 + * @param array $param + * @return array + * @throws InvalidArgumentException + */ + public function loginSms(array $param): array + { + try { + // 邮件注册参数校验 + validate(LoginValidate::class)->scene('smsLogin')->check($param); + + $param['nation'] = trim($param['nation']); + $param['phone'] = trim($param['phone']); + + // 验证短信验证码 + $mobile = $param['nation'] . $param['phone']; + $smsKey = 'DB:USER:UNLOGIN:SMS_CODE:' . $mobile; + if (!$this->checkCode($smsKey, $param['sms_code'])) { + return $this->toData('100300', 'The verification code is incorrect.', []); + }; + + // 查找手机号 + $userId = UserModel::getUserIdByNationAndPhone($param['nation'], $param['phone']); + if ($userId <= 0) { + return $this->toData('100300', 'The user does not exist.', []); + } + + // 查找用户信息 + $user = UserModel::getFieldsByUserId('invite_code,user_id,user_no,nick_name,is_real,login_password,salt', $userId); + if (empty($user)) { + return $this->toData('100300', 'Incorrect account or password.', []); + } + + // 生成token + $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); + if (empty($token)) { + return $this->toData('100300', 'The system is busy. Please try again later.', []); + } + + // 用户登陆之后需要进行的操作 异步完成 + Queue::push('app\home\job\LoginDone', ['userId' => $userId, + 'fields' => [ + 'last_login_time' => date('Y-m-d H:i:s'), + 'ip' => $this->getClientRealIp(), + 'device' => $param['device'], + ] + ], 'loginDone'); + + // 将token存致缓存 覆盖新的缓存 实现单设备登陆 + $this->setUserTokenCache($token, $userId); + + // 用户登记关系 + (new UserService())->getUserLevel($userId); + + // 返回结果以及用户信息 + return $this->toData('0', 'Request successful.', [ + 'userId' => $userId, + 'userNo' => $user['user_no'], + 'nickName' => $user['nick_name'], + 'isReal' => $user['is_real'], + 'inviteCode' => $user['invite_code'], + 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), + 'token' => $token, + ]); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * @desc 忘记密码 根据邮箱设置密码 + * @param array $param + * @return array + * @throws InvalidArgumentException + */ + public function resetPasswordByEmail(array $param): array + { + try { + // 邮件注册参数校验 + validate(LoginValidate::class)->scene('emailForget')->check($param); + + // 验证码 + $emailKey = 'DB:USER:UNLOGIN:EMAIL_CODE:' . $param['email']; + if (!$this->checkCode($emailKey, $param['email_code'])) { + return $this->toData('100300', 'The verification code is incorrect', []); + } + + // 查找邮箱 + $userId = UserModel::getUserIdByEmail($param['email']); + if ($userId <= 0) { + return $this->toData('100300', 'The user does not exist.', []); + } + + // 修改密码 + $salt = env('ENCRYPT.SALT'); + $password = (new UnqId())->encryptPassword($param['password'], $salt); + UserModel::updatePassword($password, $salt, $userId); + + // 删除缓存 + $this->delCache($emailKey); + + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * @desc 忘记密码 根据短信设置密码 + * @param array $param + * @return array + * @throws InvalidArgumentException + */ + public function resetPasswordBySms(array $param): array + { + try { + // 邮件注册参数校验 + validate(LoginValidate::class)->scene('smsForget')->check($param); + + // 判断验证码 + $mobile = $param['nation'] . $param['phone']; + $smsKey = 'DB:USER:UNLOGIN:SMS_CODE:' . $mobile; + if (!$this->checkCode($smsKey, $param['sms_code'])) { + return $this->toData('100300', 'The verification code is incorrect', []); + } + + // 查找用户 + $userId = UserModel::getUserIdByNationAndPhone($param['nation'], $param['phone']); + if ($userId <= 0) { + return $this->toData('100300', 'The user does not exist.', []); + } + + // 修改密码 + $salt = env('ENCRYPT.SALT'); + $password = (new UnqId())->encryptPassword($param['password'], $salt); + UserModel::updatePassword($password, $salt, $userId); + + // 删除缓存 + $this->delCache($smsKey); + + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + + /** + * @desc 手机号 密码登陆 + * @param $param + * @return array + */ + public function phoneLogin($param): array + { + try { + // 参数校验 + validate(LoginValidate::class)->scene('smsPasswordLogin')->check($param); + + // 获取用户 + $userId = UserModel::getUserIdByNationAndPhone($param['nation'], $param['phone']); + if ($userId <= 0) { + return $this->toData('100300', 'Incorrect account or password.1', []); + } + + $info = UserModel::getFieldsByUserId('invite_code,is_real,nick_name,user_no,user_id,login_password,salt', $userId); + if (empty($info)) { + return $this->toData('100300', 'Incorrect account or password.2', []); + } + + // 校验密码 + $checkPasswordBool = (new UnqId())->checkPassword($param['password'], $info['login_password'], $info['salt']); + if (!$checkPasswordBool) { + return $this->toData('100300', 'Incorrect account or password.3', []); + } + + // 生成token + $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); + if (empty($token)) { + return $this->toData('100400', 'The system is busy. Please try again later.', []); + } + + // 用户登陆之后需要进行的操作 异步完成 + Queue::push('app\home\job\LoginDone', ['userId' => $userId, + 'fields' => [ + 'last_login_time' => date('Y-m-d H:i:s'), + 'ip' => $this->getClientRealIp(), + 'device' => $param['device'], + ] + ], 'loginDone'); + + // 将token存致缓存 覆盖新的缓存 实现单设备登陆 + $this->setUserTokenCache($token, $userId); + + // 用户登记关系 + (new UserService())->getUserLevel($userId); + + // 返回结果以及用户信息 + return $this->toData('0', 'Request successful.', [ + 'userId' => $userId, + 'userNo' => $info['user_no'], + 'nickName' => $info['nick_name'], + 'isReal' => $info['is_real'], + 'inviteCode' => $info['invite_code'], + 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), + 'token' => $token, + ]); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', []); + } + } + + public function autoLogin($param): array + { + try { + $login_token=$param['login_token']; + $tokenUserKey = 'AUTO:TOKEN:'.$login_token; + $userId = Cache::store('redis')->get($tokenUserKey); + if(empty($userId) || $userId <= 0){ + return $this->toData('100300', 'Incorrect token', []); + } + $info = UserModel::getFieldsByUserId('invite_code,is_real,nick_name,user_no,user_id,login_password,salt', $userId); + if (empty($info)) { + return $this->toData('100300', 'Incorrect account or password.2', []); + } + // 生成token + $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); + if (empty($token)) { + return $this->toData('100400', 'The system is busy. Please try again later.', []); + } + + // 将token存致缓存 覆盖新的缓存 实现单设备登陆 + $this->setUserTokenCache($token, $userId); + + // 用户登记关系 + (new UserService())->getUserLevel($userId); + + // 返回结果以及用户信息 + return $this->toData('0', 'Request successful.', [ + 'userId' => $userId, + 'userNo' => $info['user_no'], + 'nickName' => $info['nick_name'], + 'isReal' => $info['is_real'], + 'inviteCode' => $info['invite_code'], + 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), + 'token' => $token, + ]); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', []); + } + + } + public function testLogin($param): array + { + try { + $login_token=$param['login_token']; + $tokenUserKey = 'AUTO:TOKEN:'.$login_token; + $userId = Cache::store('redis')->get($tokenUserKey); + if(empty($userId) || $userId <= 0){ + return $this->toData('100300', 'Incorrect token', []); + } + $info = UserModel::getFieldsByUserId('invite_code,is_real,nick_name,user_no,user_id,login_password,salt', $userId); + if (empty($info)) { + return $this->toData('100300', 'Incorrect account or password.2', []); + } + // 生成token + $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); + if (empty($token)) { + return $this->toData('100400', 'The system is busy. Please try again later.', []); + } + + // 将token存致缓存 覆盖新的缓存 实现单设备登陆 + $this->setUserTokenCache($token, $userId); + + // 用户登记关系 + (new UserService())->getUserLevel($userId); + + // 返回结果以及用户信息 + return $this->toData('0', 'Request successful.', [ + 'userId' => $userId, + 'userNo' => $info['user_no'], + 'nickName' => $info['nick_name'], + 'isReal' => $info['is_real'], + 'inviteCode' => $info['invite_code'], + 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), + 'token' => $token, + ]); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', []); + } + + } + public function getIP(): array + { + $ip=$this->getClientRealIp(); + $countryDb = base_path().'GeoLite2-Country.mmdb'; + $cityDb = base_path().'GeoLite2-City.mmdb'; + $countryReader = new Reader($countryDb); + $cityReader = new Reader($cityDb); + try{ + $countryNames = $countryReader->country($ip)->country->names; + $cityNames = $cityReader->city($ip)->city->names; + return $this->toData('0', 'Request successful.', [ + 'country' => $countryNames['zh-CN'], + 'city' => $cityNames['zh-CN'], + 'ip'=>$ip + ]); + }catch (\Exception $exception){ + return $this->toData('0', 'Request successful.', [ + 'country' => '未知', + 'city' =>'未知', + 'ip'=>$ip + ]); + } + } +} \ No newline at end of file diff --git a/app/home/service/MarketService.php b/app/home/service/MarketService.php new file mode 100644 index 0000000..69f1730 --- /dev/null +++ b/app/home/service/MarketService.php @@ -0,0 +1,237 @@ +scene('getMarketList')->check($data); + //1现货,2合约,3美股 + switch ($data['market_type']){ + case 1: + $result = $this->getDigitalList(); + break; + case 2: + $result = $this->getContractFaceList(); + break; + case 3: + $result = StockListModel::getMarketList($data); + break; + default: + $result = $this->getDigitalList(); + break; + } + return $this->toData(0,'Request successful.',$result); + }catch (ValidateException $validateException){ + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + }catch (\Exception $exception){ + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(),$exception->getTrace()]); + } + } + + /** + * 获取用户自选数据 + * @param int $user_id + * @param int $market_type + * @return array + */ + public function getUserMarket(array $data): array + { + try{ + validate(MarketValidate::class)->scene('getMarket')->check($data); + $result=UserMarketModel::getUserMarket($data); + return $this->toData(0,'Request successful.',$result); + }catch (ValidateException $validateException){ + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + }catch (\Exception $exception){ + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(),$exception->getTrace()]); + } + } + + /** + * 添加用户自选 + * @param array $data + * @return array + */ + + public function addUserMarket(array $data):array + { + try{ + validate(MarketValidate::class)->scene('setMarket')->check($data); + // 不做大写处理 +// $data['trade_name']=strtoupper($data['trade_name']); +// $data['market_name']=strtoupper($data['market_name']); + + $id= UserMarketModel::checkExistMarket($data); + if(!$id){ + UserMarketModel::insertUserMarket($data); + } + $this->pushUserMarket($data); + return $this->toData(0,'Request successful.'); + }catch (ValidateException $validateException){ + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + }catch (\Exception $exception){ + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(),$exception->getTrace()]); + } + + + } + public function getUserIsCollect(array $data): array + { + $id = UserMarketModel::checkExistMarket($data); + return $this->toData(0, 'Request successful.',[ + 'is_collet'=>($id > 0) + ]); + } + + /** + * 删除用户自选 + * @param array $data + * @return array + */ + public function delUserMarket(array $data):array + { + try{ + validate(MarketValidate::class)->scene('delMarket')->check($data); + $id= UserMarketModel::checkExistMarket($data); + if($id){ + UserMarketModel::delUserMarket($id); + } + $this->pushUserMarket($data); + return $this->toData(0,'Request successful.'); + }catch (ValidateException $validateException){ + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + }catch (\Exception $exception){ + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(),$exception->getTrace()]); + } + } + private function pushUserMarket($data){ + $list=UserMarketModel::getUserMarket(['page'=>1,'page_size'=>1000,'user_id'=>$data['user_id']]); + $tokenUserKey="USER:MARKET:".$data['user_id']; + $redis=$this->getRedis(); + $redis->set($tokenUserKey,json_encode($list['list'])); + } + private function checkMarket($market_type,$trade_name):bool + { + switch ($market_type){ + case 1: + return DigitalListModel::existMarket($trade_name); + break; + case 2: + return ContractListMode::existMarket($trade_name); + break; + case 3: + return StockListModel::existMarket($trade_name); + break; + default: + return DigitalListModel::existMarket($trade_name); + break; + } + } + + public function getTradeFee(array $data): array + { + try{ + validate(MarketValidate::class)->scene('getTradeFee')->check($data); + //$fee_info=$this->initTradeFeeSetting($data['market_type']); + $fee_info=FeeSettingModel::getTradeFeeById($data['market_type']); + return $this->toData(0,'Request successful.',$fee_info); + }catch (ValidateException $validateException){ + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + }catch (\Exception $exception){ + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(),$exception->getTrace()]); + } + } + public function getMarketTradeList(array $data):array + { + try{ + validate(MarketValidate::class)->scene('getTrade')->check($data); + switch ($data['market_type']){ + case 2: + $list=ContractTradeModel::getTradeList($data['trade_name'],intval($data['num'])); + break; + case 3: + $list=StockTradeModel::getTradeList($data['trade_name'],intval($data['num'])); + break; + default: + $list=DigitalTradeModel::getTradeList($data['trade_name'],intval($data['num'])); + break; + + } + return $this->toData(0,'Request successful.',$list); + }catch (ValidateException $validateException){ + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + }catch (\Exception $exception){ + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(),$exception->getTrace()]); + } + } + public function getTradeTypeList():array + { + $list=$this->getCapitalTypeList(); + return $this->toData(0,'Request successful.',$list); + } + public function getContractFace():array + { + $list=$this->getContractFaceList(1); + return $this->toData(0,'Request successful.',$list); + } + public function getForexFace($data):array + { + $info=ForexListModel::where('trade_name',$data['trade_name'])->find(); + if(!empty($info)){ + $arr=$info->toArray(); + }else{ + $arr=[]; + } + return $this->toData(0,'Request successful.',$arr); + } + public function getContractSetting():array + { + $list=ContractSettingModel::getSettingList(); + return $this->toData(0,'Request successful.',$list); + } + public function getMarketRate():array + { + $list=StockMarketModel::where('status',1)->field('stock_market_type as market_type,unit,symbol,rate')->select(); + if(!empty($list)){ + $list_arr=$list->toArray(); + }else{ + $list_arr=[]; + } + return $this->toData(0,'Request successful.',$list_arr); + } + + + + +} \ No newline at end of file diff --git a/app/home/service/MoPayService.php b/app/home/service/MoPayService.php new file mode 100644 index 0000000..a70359d --- /dev/null +++ b/app/home/service/MoPayService.php @@ -0,0 +1,203 @@ +merchant; + $post_data['pay_orderid']=$orderId; + $post_data['pay_applydate']=date('Y-m-d H:i:s'); + $post_data['pay_notifyurl']=$notify_url.url('mopay_notify'); + $post_data['pay_callbackurl']=$notify_url.url('mopay_notify'); + $post_data['pay_amount']=$amount; + $post_data['pay_bankcode']=$this->bankcode; + + $sign=$this->createSign($this->key,$post_data); + $post_data['pay_md5sign']=$sign; + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res=$this->curlPost($this->pay_url,$post_data,10,$header); + $result=json_decode($res,true); + return $result; + } + public function moPayNotify($data){ + Log::info('收到mopay异步回调:'.json_encode($data)); + $sign=$this->createSign($this->key,$data); + Log::info('收到mopay代付异步回调sign:'.$sign.'====='.$data['sign']); + if($sign==strtoupper($data['sign'])){ + if($data['returncode']=='00'){ + $order_info=RechargeApplyModel::getOrderByNo([ + 'order_no'=>$data['orderid'] + ]); + if($order_info && $data['amount']==$order_info['total_amount']){ + if($order_info['status']==0){ + return (new PayService())->dealPayNotify($order_info); + } + }else{ + Log::info('mopay支付订单不存在:'.json_encode($data)); + } + }else{ + Log::info('mopay支付订单支付失败:'.json_encode($data)); + } + }else{ + Log::info('mopay签名校验失败:'.$sign.json_encode($data)); + } + } + public function apply_pay($orderId,$amount,$bank_code,$bank_account,$nike_name,$moblie,$ifsc) + { + $notify_url=env('PAY.NOTIFY_URL'); + $post_data['mchid']=$this->merchant; + $post_data['out_trade_no']=$orderId; + $post_data['money']=round($amount,2); + $post_data['bank_code']=$bank_code; + $post_data['bank_account']=$nike_name; + $post_data['bank_card_no']=$bank_account; + $post_data['mobile']=$moblie; + $post_data['ifsc']=$ifsc; + $post_data['notifyurl']=$notify_url.'/bs/mopay_anotify'; + + $sign=$this->createSign($this->key,$post_data); + $post_data['pay_md5sign']=$sign; + Log::info('mopay post:'.json_encode($post_data)); + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res=$this->curlPost($this->app_url,$post_data,10,$header); + $result=json_decode($res,true); + Log::info('mopay post结果:'.$res); + if(strtolower($result['status'])=='success'){ + return [ + 'code'=>200, + 'msg'=>'ok', + 'order_idx'=>$result['transaction_id'], + 'content'=>$res + ]; + }else{ + return [ + 'code'=>300, + 'msg'=>$result['msg'], + 'order_idx'=>'', + 'content'=>$res + ]; + } + } + public function moPayApplyNotify($data){ + Log::info('收到mopay代付异步回调:'.json_encode($data)); + + $sign=$this->createSign($this->key,$data); + + if($sign==strtoupper($data['sign'])){ + if($data['returncode']=='00'){ + $order_info=UserWithdrawalModel::getUserDrawalInfo([ + 'order_no'=>$data['orderid'] + ]); + if($order_info && $order_info['status']==3){ + UserWithdrawalModel::where([ + 'id'=>$order_info['id'] + ])->update([ + 'order_idx'=>$data['transaction_id'], + 'status'=>4, + 'deal_time'=>date('Y-m-d H:i:s') + ]); + Log::info('mopay代付支付成功:'.json_encode($data)); + }else{ + Log::info('mopay代付订单不存在:'.json_encode($data)); + } + }else{ + UserWithdrawalModel::where([ + 'order_no'=>$data['orderid'] + ])->update([ + 'status'=>1, + ]); + Log::info('mopay代付失败:'.json_encode($data)); + } + }else{ + Log::info('mopay代付签名校验失败:'.json_encode($data)); + } + } + public function getBalance() + { + $post_data['merchant']=$this->merchant; + $sign=$this->generateQueryString($post_data,$this->key); + $post_data['sign']=$sign; + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res=$this->curlPost($this->bla_url,$post_data,10,$header); + $result=json_decode($res,true); + if($result['code']==200){ + return [ + 'amount'=>$result['data']['balanceUsable'] + ]; + }else{ + return [ + 'amount'=>0 + ]; + } + } + + private function curlPost($url, $post_data = array(), $timeout = 5, $header = "", $data_type = "") { + $header = empty($header) ? '' : $header; + //支持json数据数据提交 + if($data_type == 'json'){ + $post_string = json_encode($post_data); + }elseif($data_type == 'array') { + $post_string = $post_data; + }elseif(is_array($post_data)){ + $post_string = http_build_query($post_data, '', '&'); + } + + $ch = curl_init(); // 启动一个CURL会话 + curl_setopt($ch, CURLOPT_URL, $url); // 要访问的地址 + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查 // https请求 不验证证书和hosts + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在 + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器 + //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转 + //curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer + curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的Post请求 + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string); // Post提交的数据包 + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置超时限制防止死循环 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + //curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回 + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头 + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + /** + * 创建签名 + * @param $Md5key + * @param $list + * @return string + */ + protected function createSign($Md5key, $list) + { + ksort($list); + $md5str = ""; + foreach ($list as $key => $val) { + if (!empty($val) && !in_array($key,['sign','pay_md5sign'])) { + $md5str = $md5str . $key . "=" . $val . "&"; + } + } + // 去除末尾的 '&' + $sign_str=$md5str . "key=" . $Md5key; + Log::info('mopay代付签名串:'.$sign_str); + $sign = strtoupper(md5($sign_str)); + return $sign; + } + + + +} \ No newline at end of file diff --git a/app/home/service/NicePayService.php b/app/home/service/NicePayService.php new file mode 100644 index 0000000..7242c43 --- /dev/null +++ b/app/home/service/NicePayService.php @@ -0,0 +1,242 @@ +app_key; + $post_data['balance']=$amount; + $post_data['ord_id']=$orderId; + $post_data['notify_url']=$notify_url.url('nicepay_notify'); + $randomKey = array_rand($this->p_type); + $post_data['p_type']=$this->p_type[$randomKey]; + $sign=$this->createSign($this->key,$post_data); + $post_data['sign']=$sign; + //$header = array("Content-Type:application/json;"); + //$res=$this->curlPost($this->pay_url,$post_data,10,$header); + $res=$this->fetch_page_json($this->pay_url,$post_data); + Log::info('收到nicepay响应:'.$res."----".json_encode($post_data)); + $result=json_decode($res,true); + return $result; + } + public function NicePayNotify($data){ + Log::info('收到nicepay异步回调:'.json_encode($data)); + if($this->check_sign($data,$this->key)){ + if($data['status']==1){ + $order_info=RechargeApplyModel::getOrderByNo([ + 'order_no'=>$data['order'] + ]); + if($order_info && $data['amount']==$order_info['total_amount']){ + if($order_info['status']==0){ + return (new PayService())->dealPayNotify($order_info); + } + }else{ + Log::info('nicepay支付订单不存在:'.json_encode($data)); + } + }else{ + Log::info('nicepay支付订单支付失败:'.json_encode($data)); + } + }else{ + Log::info('nicepay签名校验失败:'.json_encode($data)); + } + } + public function apply_pay($orderId,$amount,$bank_account,$nike_name,$ifsc) + { + $notify_url=env('PAY.NOTIFY_URL'); + $post_data['app_key']=$this->app_key; + $post_data['balance']=round($amount,2); + $post_data['ord_id']=$orderId; + $post_data['card']=$bank_account; + $post_data['name']=$nike_name; + + $randomKey = array_rand($this->p_type); + $post_data['p_type']=$this->p_type[$randomKey]; + $post_data['ifsc']=$ifsc; + $post_data['notify_url']=$notify_url.'/bs/nicepay_anotify'; + + $sign=$this->createSign($this->key,$post_data); + $post_data['sign']=$sign; + Log::info('nicepay post:'.json_encode($post_data)); + + $header = array("Content-Type:application/json;charset=UTF-8"); + //$res=$this->curlPost($this->app_url,$post_data,10,$header); + $res=$this->fetch_page_json($this->app_url,$post_data); + $result=json_decode($res,true); + Log::info('nicepay post结果:'.$res); + if($result['err']==0 && !empty($result)){ + return [ + 'code'=>200, + 'msg'=>'ok', + 'order_idx'=>'', + 'content'=>$res + ]; + }else{ + return [ + 'code'=>300, + 'msg'=>$res, + 'order_idx'=>'', + 'content'=>$res + ]; + } + } + public function NicePayApplyNotify($data){ + Log::info('收到nicepay代付异步回调:'.json_encode($data)); + + if($this->check_sign($data,$this->key)){ + if($data['status']==1){ + $order_info=UserWithdrawalModel::getUserDrawalInfo([ + 'order_no'=>$data['order'] + ]); + if($order_info && $order_info['status']==3){ + UserWithdrawalModel::where([ + 'id'=>$order_info['id'] + ])->update([ + 'status'=>4, + 'deal_time'=>date('Y-m-d H:i:s') + ]); + Log::info('nicepay代付支付成功:'.json_encode($data)); + }else{ + Log::info('nicepay代付订单不存在:'.json_encode($data)); + } + }else{ + UserWithdrawalModel::where([ + 'order_no'=>$data['order'] + ])->update([ + 'status'=>1, + ]); + Log::info('nicepay代付失败:'.json_encode($data)); + } + }else{ + Log::info('nicepay代付签名校验失败:'.json_encode($data)); + } + } + public function getBalance() + { + $post_data['app_key']=$this->app_key; + $sign=$this->createSign($this->key,$post_data); + $post_data['sign']=$sign; +// $header = array("Content-Type:application/json;charset=UTF-8"); +// $res=$this->curlPost($this->bla_url,$post_data,10,$header); + $res=$this->fetch_page_json($this->app_url,$post_data); + $result=json_decode($res,true); + if($result['err']==0 && !empty($result)){ + return [ + 'amount'=>$result['balance'] + ]; + }else{ + return [ + 'amount'=>0 + ]; + } + } + function fetch_page_json ($url, $params = null) + { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type:application/json;charset=UTF-8"]); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params)); + curl_setopt($ch, CURLOPT_URL, $url); + + $result = curl_exec($ch); + $errno = curl_errno($ch); + $errmsg = curl_error($ch); + if ($errno != 0) + { + throw new Exception($errmsg, $errno); + } + curl_close($ch); + return $result; + } + private function check_sign($param,$salt){ + $data = $param; + $sign = $data['sign']; + if(!$sign){ + return false; + } + unset($data['sign']); + ksort($data); + + $str=""; + foreach ($data as $key => $value) + { + $str=$str.$value; + } + $str = $str."".$salt; + $check_sign = md5($str); + + if($sign != $check_sign){ + return false; + }else{ + return true; + } + } + private function curlPost($url, $post_data = array(), $timeout = 5, $header = "", $data_type = "") { + $header = empty($header) ? '' : $header; + //支持json数据数据提交 + if($data_type == 'json'){ + $post_string = json_encode($post_data); + }elseif($data_type == 'array') { + $post_string = $post_data; + }elseif(is_array($post_data)){ + $post_string = http_build_query($post_data, '', '&'); + } + + $ch = curl_init(); // 启动一个CURL会话 + curl_setopt($ch, CURLOPT_URL, $url); // 要访问的地址 + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查 // https请求 不验证证书和hosts + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在 + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器 + //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转 + //curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer + curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的Post请求 + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string); // Post提交的数据包 + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置超时限制防止死循环 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + //curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回 + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头 + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + /** + * 创建签名 + * @param $Md5key + * @param $list + * @return string + */ + protected function createSign($salt, $param) + { + $data = $param; + ksort($data); + + $str=""; + foreach ($data as $key => $value) + { + $str=$str.$value; + } + $str = $str.$salt; + return md5($str); + } + + + +} \ No newline at end of file diff --git a/app/home/service/PayService.php b/app/home/service/PayService.php new file mode 100644 index 0000000..15c520d --- /dev/null +++ b/app/home/service/PayService.php @@ -0,0 +1,316 @@ + 1, + 'is_recharge' => 1, + 'is_online' => $data['is_online'] + ])->order('id', 'desc')->select()->toArray(); + + return $this->toData(0, 'Request successful.', $list); + } + + /** + * 用户充值申请入库1 + * @param array $data + * @return array + */ + public function insertRechargeApply(array $data): array + { + //判断账号是否冻结 + $isFrozen = AccountFrozenModel::where('user_id', $data['user_id'])->find(); + if (!empty($isFrozen) && $isFrozen->frozen_recharge == 1) { + return $this->toData('100110', 'The current account has been frozen', []); + } + $channel = PaymentListModel::getPaymentInfo([ + 'id' => $data['recharge_channel'] + ]); + + if (empty($channel)) { + return $this->toData('100110', 'The system is busy. Please try again later.1', []); + } + if (empty($data['country'])) { + return $this->toData('100120', 'The system is busy. Please try again later.2', []); + } + if (empty($data['recharge_num']) || $data['recharge_num'] <= 0) { + return $this->toData('100130', 'The system is busy. Please try again later.3', []); + } + if($channel['type']==9){ + //1USD=1USDT + $currency_rate = 1; + if($data['product']=='TRC20Buy'){ + switch ($data['extra']){ + case 'GBP': + $gpx_rate=StockMarketModel::where('stock_market_type',14)->value('rate'); + $currency_rate=$gpx_rate/100; + break; + case "EUR": + $eur_rate=StockMarketModel::where('stock_market_type',15)->value('rate'); + $currency_rate=$eur_rate*1; + break; + } + } + }else{ + $currency_rate = $channel['exchange_rate']; + } + //$currency_rate=(new StockMarketModel)->getRate(4); + if ($data['account_type'] > 2 && ($data['account_type'] != 8)) { + $market_rate = (new StockMarketModel)->getRate($data['account_type']); + } else { + $market_rate = 1; + } + $market_amount = $data['recharge_num'] * $market_rate; + $market_amount = round($market_amount, 2); + + if ($channel['pay_type'] == 1) { + $fee = $data['recharge_num'] * $currency_rate * $channel['service_rate']; + $server_fee = $market_amount * $channel['service_rate']; + } else { + $fee = $currency_rate * $channel['service_rate']; + $server_fee = $market_rate * $channel['service_rate']; + } + $total_amount = $data['recharge_num'] * $currency_rate + $fee; + $total_amount = round($total_amount, 2); + + if ($data['is_online'] == 1 && $total_amount > 100000) { + return $this->toData('101900', 'Online payment scope: 100 - 100000'); + } + $data['service_fee'] = $server_fee;//手续费用 + $data['market_amount'] = $market_amount; //换算的市场金额 + $data['total_amount'] = $total_amount; //要支付的渠道货币金额 + $data['currency_rate'] = $currency_rate; + if ($channel['channel_type'] == 'Bank') { + $data['recharge_type'] = 2; + } else { + $data['recharge_type'] = 1; + } + + $data['order_no'] = $this->generateOrderNumber(); + + $order_id = RechargeApplyModel::InsertUserRecharge($data); + if ($order_id) { + switch ($channel['type']) { + case 2: + $result = (new IndPayService())->indPay($data['order_no'], $data['total_amount']); + if ($result['status'] == 'SUCCESS') { + RechargeApplyModel::where('order_no', $data['order_no'])->update([ + 'order_idx' => $result['order_no'], + 'pay_url' => $result['order_data'], + ]); + return $this->toData(0, 'Request successful.', [ + 'type' => 'bank_pay', + 'pay_url' => $result['order_data'], + 'order_no' => $result['mer_order_no'], + ]); + } else { + return $this->toData('100900', 'The system is busy. Please try again later.4', [$result['err_msg'], $result['err_code']]); + } + break; + case 3: + $result = (new MoPayService())->create_order($data['order_no'], $data['total_amount']); + if ($result['status'] == 'SUCCESS') { + RechargeApplyModel::where('order_no', $data['order_no'])->update([ + 'pay_url' => $result['data']['pay_url'], + ]); + return $this->toData(0, 'Request successful.', [ + 'type' => 'bank_pay', + 'pay_url' => $result['data']['pay_url'], + 'order_no' => $data['order_no'], + ]); + } else { + return $this->toData('100600', 'The system is busy. Please try again later.5', [$result['err_msg'], $result['err_code']]); + } + break; + case 4: +// $result = (new HTPayService())->qrPay($data['order_no'], round($data['total_amount'])); +// if ($result['status'] == 1) { +// RechargeApplyModel::where('order_no', $data['order_no'])->update([ +// 'order_idx' => $result['orderNo'], +// 'pay_url' => $result['payUrl'], +// 'total_amount' => $result['oriAmount'] +// ]); +// return $this->toData(0, 'Request successful.', [ +// 'type' => 'bank_pay', +// 'pay_url' => $result['payUrl'], +// 'order_no' => $data['order_no'], +// ]); +// } else { +// return $this->toData('101900', 'The system is busy. Please try again later.6', [$result['status'], $result['message']]); +// } + // 20250110 跟负责人确认不要第三方验证,后台管理端手动审核订单信息 + return $this->toData(0, 'Request successful.', [ + 'type' => 'bank_pay', + 'pay_url' => '', + 'order_no' => $data['order_no'], + ]); + break; + case 5: + $result = (new XdPayService())->create_order($data['order_no'], $data['total_amount']); + if ($result['code'] == 200) { + RechargeApplyModel::where('order_no', $data['order_no'])->update([ + 'pay_url' => $result['data']['url'], + ]); + return $this->toData(0, 'Request successful.', [ + 'type' => 'bank_pay', + 'pay_url' => $result['data']['url'], + 'order_no' => $data['order_no'], + ]); + } else { + return $this->toData('101900', 'The system is busy. Please try again later.7', [$result['code'], $result['msg']]); + } + break; + case 6: + $result = (new QeaePayService())->create_order($data['order_no'], $data['total_amount']); + if ($result['respCode'] == 'SUCCESS') { + RechargeApplyModel::where('order_no', $data['order_no'])->update([ + 'pay_url' => $result['payInfo'], + ]); + return $this->toData(0, 'Request successful.', [ + 'type' => 'bank_pay', + 'pay_url' => $result['payInfo'], + 'order_no' => $data['order_no'], + ]); + } else { + return $this->toData('101900', 'The system is busy. Please try again later.8', [$result['respCode'], $result['tradeMsg']]); + } + break; + case 7: + $result = (new NicePayService())->create_order($data['order_no'], $data['total_amount']); + if ($result['err'] == 0 && !empty($result)) { + RechargeApplyModel::where('order_no', $data['order_no'])->update([ + 'pay_url' => $result['url'], + ]); + return $this->toData(0, 'Request successful.', [ + 'type' => 'bank_pay', + 'pay_url' => $result['url'], + 'order_no' => $data['order_no'], + ]); + } else { + return $this->toData('101900', 'The system is busy. Please try again later.9', [$result['err'], $result['err_msg']]); + } + break; + case 8: + $result = (new ClickPayService())->create_order($data['order_no'], $data['total_amount']); + if (strtoupper($result['platRespCode']) == 'SUCCESS') { + RechargeApplyModel::where('order_no', $data['order_no'])->update([ + 'order_idx' => $result['platOrderNum'], + ]); + return $this->toData(0, 'Request successful.', [ + 'type' => 'bank_pay', + 'pay_url' => $result['payData'], + 'order_no' => $data['order_no'], + ]); + } else { + return $this->toData('101900', 'The system is busy. Please try again later.10'); + } + break; + case 9: + if(in_array(trim($data['product']),['TRC20H5','TRC20Buy'])){ + $result = (new StarPayService())->create_order($data['order_no'], $data['total_amount'],$data['product'],$data['extra']); + if ($result['code'] == 200) { + $respon=json_decode($result['params'],true); + RechargeApplyModel::where('order_no', $data['order_no'])->update([ + 'pay_url' => $respon['payurl'], + ]); + return $this->toData(0, 'Request successful.', [ + 'type' => 'bank_pay', + 'pay_url' => $respon['payurl'], + 'order_no' => $data['order_no'], + ]); + } else { + return $this->toData('100600', 'The system is busy. Please try again later.5', $result); + } + }else{ + return $this->toData('102000', 'The system is busy. Please try again later.20'); + } + break; + default: + return $this->toData(0, 'Request successful.', []); + break; + } + + } else { + return $this->toData(100140, 'The system is busy. Please try again later.10', []); + } + } + + public function dealPayNotify($order_info) + { + $wallet = new WalletService(); + // 启动事务 + Db::startTrans(); + try { + //查询划转资金账户信息 + $account = $wallet->lockUserBalance($order_info['account_type'], $order_info['user_id']); + if (empty($account)) { + Db::rollback(); + return [ + 'code' => 100, + 'msg' => 'FAIL' + ]; + } + // 新增转入 特别需要注意的是,股票账户需要进行汇率转换 现货\合约\美股都是USD + $update_data['usable_num'] = $account['usable_num'] + $order_info['market_amount']; + $res = $wallet->updateUserBalance($order_info['account_type'], $update_data, $order_info['user_id']); + if (empty($res)) { + Db::rollback(); + return [ + 'code' => 300, + 'msg' => 'FAIL' + ]; + } + //插入资金变动日志 + $logs['user_id'] = $order_info['user_id']; + $logs['change_type'] = 1; + $logs['change_num'] = $order_info['market_amount']; + $logs['before_num'] = $account['usable_num']; + $logs['order_id'] = $order_info['order_no']; + $log_res = $wallet->addUserBalanceLog($order_info['account_type'], $logs); + if (empty($log_res)) { + Db::rollback(); + return [ + 'code' => 400, + 'msg' => 'FAIL' + ]; + } + //修改订单状态 + RechargeApplyModel::where('id', $order_info['id'])->update([ + 'status' => 1, + 'deal_time' => date('Y-m-d H:i:s'), + ]); + // 提交事务 + Db::commit(); + return [ + 'code' => 200, + 'msg' => 'SUCCESS' + ]; + } catch (\Exception $e) { + // 出现异常,回滚事务 + Db::rollback(); + return [ + 'code' => 500, + 'msg' => $e->getMessage() + ]; + } + } + + +} \ No newline at end of file diff --git a/app/home/service/PreStockService.php b/app/home/service/PreStockService.php new file mode 100644 index 0000000..eccbb2a --- /dev/null +++ b/app/home/service/PreStockService.php @@ -0,0 +1,145 @@ +toData('1', 'Params error'); + } + + $server = new IPOService(); + return $server->index($param['market_type'], $param); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage(),$exception->getTrace()]); + } + } + + // 列表 + public function stockDetail($param) + { + try { + // stock_type 3 美股 4 印尼 5 马股 6 泰股 + if (empty($param['market_type'])) { + return $this->toData('1', 'Params error'); + } + + $server = new IPOService(); + return $server->stockDetail($param['market_type'], $param); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } + + // 下单 + public function order($param, $userId) + { + try { + if (empty($userId)) { + return $this->toData('1', 'Login fail'); + } + + // 需要完成实名认证之后才能下单 + $user = UserModel::where('user_id', $userId)->find(); + if (empty($user) || $user->is_real != 1) { + return $this->toData('405', 'Only after completing real-name authentication can you place an order.'); + } + + // stock_type 3 美股 4 印尼 5 马股 6 泰股 + if (empty($param['market_type'])) { + return $this->toData('1', 'Params error'); + } + + $server = new IPOService(); + return $server->order($param['market_type'], $param, $userId); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } + + // 后支付-付款 + /* + + 支付金额(先支付)= 申购数量*申购价格+手续费 + 申购开始时间-公布中签时间 + 支付金额(后支付)=申购数量*申购价格+手续费 + 公布中签时间-申购截止时间 + 支付金额(后支付)=分配数量*申购价格+手续费 + + */ + public function postPay($param, $userId) + { + try { + if (empty($userId)) { + return $this->toData('1', 'Login fail'); + } + + // 需要完成实名认证之后才能下单 + $user = UserModel::where('user_id', $userId)->find(); + if (empty($user) || $user->is_real != 1) { + return $this->toData('405', 'Only after completing real-name authentication can you place an order.'); + } + + // stock_type 3 美股 4 印尼 5 马股 6 泰股 + if (empty($param['market_type'])) { + return $this->toData('1', 'Params error'); + } + + + $server = new IPOService(); + return $server->postPay($param['market_type'], $param, $userId); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } + + // 申购记录 + public function list($param, $userId) + { + try { + // stock_type 3 美股 4 印尼 5 马股 6 泰股 + if (empty($param['market_type'])) { + return $this->toData('1', 'Params error'); + } + + if (empty($userId)) { + return $this->toData('1', 'Login fail'); + } + + $server = new IPOService(); + return $server->list($param['market_type'], $param, $userId); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } + + // 申购订单详情 + public function detail($param, $userId) + { + try { + // stock_type 3 美股 4 印尼 5 马股 6 泰股 + if (empty($param['market_type'])) { + return $this->toData('1', 'Params error'); + } + + if (empty($userId)) { + return $this->toData('1', 'Login fail'); + } + + $server = new IPOService(); + return $server->detail($param['market_type'], $param, $userId); + } catch (\Exception $exception) { + return $this->toData('0', 'The system is busy. Please try again later.', [$exception->getMessage()]); + } + } +} \ No newline at end of file diff --git a/app/home/service/QeaePayService.php b/app/home/service/QeaePayService.php new file mode 100644 index 0000000..3dc565d --- /dev/null +++ b/app/home/service/QeaePayService.php @@ -0,0 +1,228 @@ +key = env('QEAE_PAY.KEY'); + $this->df_key = env('QEAE_PAY.DF_KEY'); + $this->merchant = env('QEAE_PAY.MERCHANT'); + } + + + /** + * @param $orderId // 订单id + * @param $amount + * @return mixed + */ + public function create_order($orderId,$amount) + { + // order_no + $notify_url = env('PAY.NOTIFY_URL'); + $post_data['goods_name'] = $orderId; // 商品名称必传参数 不超过50字节 + $post_data['mch_id'] = $this->merchant; //商户号 + $post_data['mch_order_no'] = $orderId; //商家订单号 + $post_data['order_date'] = date('Y-m-d H:i:s'); // 订单时间 + $post_data['pay_type'] = $this->pay_type; // 支付类型 + $post_data['trade_amount'] = $amount; //交易金额 当地货币 精确到元 + $post_data['version'] = '1.0'; //版本号 + $post_data['notify_url'] = $notify_url.url('qeaepay_notify'); + + $sign = $this->generateQueryString($post_data,$this->key); + $post_data['sign'] = $sign; + $post_data['sign_type'] = 'MD5'; // 签名方式固定MD5 + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res = $this->curlPost($this->pay_url,$post_data,10,$header); + $result = json_decode($res,true); + + return $result; + } + // 异步回调处理 + public function qeaePayNotify($data){ + Log::info('收到QeaePay异步回调:'.json_encode($data)); + + $sign=$this->generateQueryString($data,$this->key); + + if($sign==strtolower($data['sign'])){ + + if($data['tradeResult']==1){ + $order_info=RechargeApplyModel::getOrderByNo([ + 'order_no'=>$data['mchOrderNo'] + ]); + if($order_info && $data['amount']==$order_info['total_amount']){ + if($order_info['status']==0){ + return (new PayService())->dealPayNotify($order_info); + } + }else{ + Log::info('QeaePay支付订单不存在:'.json_encode($data)); + } + }else{ + Log::info('QeaePay支付订单支付失败:'.json_encode($data)); + } + }else{ + Log::info('QeaePay签名校验失败:'.json_encode($data)); + } + + } + // 代付 + public function apply_pay($orderId,$amount,$bank_account,$nike_name,$ifsc,$bank_code) + { + $notify_url=env('PAY.NOTIFY_URL'); + + $post_data['sign_type'] = 'MD5'; // 加密方式 + $post_data['mch_id'] = $this->merchant; //商家编号 + $post_data['mch_transferId'] = $orderId; //商家转账订单号 + $post_data['transfer_amount'] = floor($amount); //转账金额 + $post_data['apply_date'] = date('Y-m-d H:i:s'); // 订单时间; + $post_data['bank_code'] = $bank_code; // 收款银行代码 + $post_data['receive_name'] = $nike_name; // 收款银行户名 + $post_data['receive_account'] = $bank_account; // 收款银行账号 + $post_data['back_url'] = $notify_url.'/bs/qeaepay_appNotify'; + + $post_data['remark'] = $ifsc; + $sign=$this->generateQueryString($post_data,$this->df_key); + $post_data['sign']=$sign; + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res=$this->curlPost($this->app_url,$post_data,10,$header); + $result=json_decode($res,true); + + if($result['respCode']=='SUCCESS'){ + return [ + 'code'=>200, + 'msg'=>'ok', + 'order_idx'=>$result['tradeNo'], + 'content'=>$res + ]; + }else{ + return [ + 'code'=>300, + 'msg'=>$result['errorMsg'], + 'order_idx'=>'', + 'content'=>$res + ]; + } + } + public function qeaePayApplyNotify($data){ + Log::info('收到qeaepay代付异步回调:'.json_encode($data)); +// $data['reverse']=$data['reverse'] ? 'true':'false'; + + $sign=$this->generateQueryString($data,$this->df_key); + if($sign==strtolower($data['sign'])){ + if($data['tradeResult']==1){ + $order_info=UserWithdrawalModel::getUserDrawalInfo([ + 'order_no'=>$data['merTransferId'] + ]); + if($order_info && $order_info['status']==3){ + UserWithdrawalModel::where([ + 'id'=>$order_info['id'] + ])->update([ + 'status'=>4, + 'deal_time'=>date('Y-m-d H:i:s') + ]); + Log::info('qeaepay代付支付成功:'.json_encode($data)); + }else{ + Log::info('qeaepay代付订单不存在:'.json_encode($data)); + } + }else{ + UserWithdrawalModel::where([ + 'order_no'=>$data['orderId'] + ])->update([ + 'status'=>1, + ]); + Log::info('xdpay代付失败:'.json_encode($data)); + } + }else{ + Log::info('xdpay代付签名校验失败:'.json_encode($data)); + } + } + public function getBalance() + { + $post_data['mch_id']=$this->merchant; + $sign=$this->generateQueryString($post_data,$this->key); + $post_data['sign']=$sign; + $post_data['sign_type']='MD5'; + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res=$this->curlPost($this->bla_url,$post_data,10,$header); + $result=json_decode($res,true); + if($result['respCode']=='SUCCESS'){ + return [ + 'amount'=>$result['availableAmount'] + ]; + }else{ + return [ + 'amount'=>0 + ]; + } + } + private function curlPost($url, $post_data = array(), $timeout = 5, $header = "", $data_type = "") { + $header = empty($header) ? '' : $header; + //支持json数据数据提交 + if($data_type == 'json'){ + $post_string = json_encode($post_data); + }elseif($data_type == 'array') { + $post_string = $post_data; + }elseif(is_array($post_data)){ + $post_string = http_build_query($post_data, '', '&'); + } + + $ch = curl_init(); // 启动一个CURL会话 + curl_setopt($ch, CURLOPT_URL, $url); // 要访问的地址 + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查 // https请求 不验证证书和hosts + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在 + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器 + //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转 + //curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer + curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的Post请求 + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string); // Post提交的数据包 + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置超时限制防止死循环 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + //curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回 + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头 + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + private function generateQueryString($fields, $privateKey) { + // 按ASCII顺序对字段名进行自然排序 + ksort($fields); + + // 将字段按 k=v 格式拼接成字符串 + $query = ''; + foreach($fields as $key => $value) { + // sign 和signType 不参与签名 + if($key!='sign' && $key != 'sign_type'){ + $query .= $key . '=' . strval($value) . '&'; + } + } + // 去除末尾的 '&' + $query = rtrim($query, '&'); + // 在字符串末尾拼接私钥 + $query .= '&key=' . $privateKey; + $sign=md5($query); + return $sign; + } + + +} \ No newline at end of file diff --git a/app/home/service/StarPayService.php b/app/home/service/StarPayService.php new file mode 100644 index 0000000..46dda45 --- /dev/null +++ b/app/home/service/StarPayService.php @@ -0,0 +1,149 @@ +merchant_no; + $post_data['timestamp'] = time(); + $post_data['sign_type'] = 'MD5'; + + $params['merchant_ref']=$orderId; + $params['product']=$product; + $params['amount']=$amount; + $params['extra']=(object) []; + if($product=='TRC20Buy'){ + $params['extra']->fiat_currency=$fiat_currency; + } + $post_data['params'] = json_encode($params); + + + $post_data['sign'] =$this->sign_data($post_data); + + Log::info('starPay post-: ' . json_encode($post_data)); + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res=$this->curlPost($this->pay_url,$post_data,10,$header); + Log::info('starPay 返回-: ' . $res); + $result=json_decode($res,true); + return $result; + } + public function starPayNotify($data){ + Log::info('收到star_pay异步回调:'.json_encode($data)); + $sign=$this->sign_data($data); + if($sign==$data['sign']){ + Log::info('star_pay签名校验成功:'.json_encode($data)); + $result=json_decode($data['params'],true); + if($result['status']==1){ + $order_info=RechargeApplyModel::getOrderByNo([ + 'order_no'=>$result['merchant_ref'] + ]); + if($order_info && $result['amount']==$order_info['total_amount']){ + if($order_info['status']==0){ + return (new PayService())->dealPayNotify($order_info); + } + }else{ + Log::info('star_pay支付订单不存在:'.json_encode($data)); + } + }else{ + Log::info('star_pay支付订单支付失败:'.json_encode($data)); + } + }else{ + Log::info('star_pay签名校验失败:'.json_encode($data)); + } + return [ + 'code'=>300, + 'msg'=>'FAIL' + ]; + + } + private function sign_data($post_data){ + if(is_array($post_data['params'])){ + $sign_str=$this->merchant_no.json_encode($post_data['params']).$post_data['sign_type'].$post_data['timestamp'].$this->sign_key; + }else{ + $sign_str=$this->merchant_no.$post_data['params'].$post_data['sign_type'].$post_data['timestamp'].$this->sign_key; + } + + Log::info('star_pay签名:'.json_encode($sign_str)); + return md5($sign_str); + } + public function getTRC20BuyList() + { + $gpx_rate=StockMarketModel::where('stock_market_type',14)->value('rate'); + $eur_rate=StockMarketModel::where('stock_market_type',15)->value('rate'); + $json=[ + [ + "bank_name"=>"GBP", + "bank_code"=> "GBP", + "exchange_rate"=>$gpx_rate/100, + "unit"=>'GBP', + "min_num"=>10, + "max_num"=>30000, + ], + [ + "bank_name"=> "USD", + "bank_code"=> "USD", + "exchange_rate"=>1, + "unit"=>'USD', + "min_num"=>10, + "max_num"=>100000, + ], + [ + "bank_name"=> "EUR", + "bank_code"=> "EUR", + "exchange_rate"=>$eur_rate, + "unit"=>'EUR', + "min_num"=>10, + "max_num"=>92945, + ], + ]; + return $this->toData('0', 'SUCCESS', $json); + } + private function curlPost($url, $post_data = array(), $timeout = 5, $header = "", $data_type = "") + { + $header = empty($header) ? '' : $header; + //支持json数据数据提交 + if ($data_type == 'json') { + $post_string = json_encode($post_data); + } elseif ($data_type == 'array') { + $post_string = $post_data; + } elseif (is_array($post_data)) { + $post_string = http_build_query($post_data, '', '&'); + } + + $ch = curl_init(); // 启动一个CURL会话 + curl_setopt($ch, CURLOPT_URL, $url); // 要访问的地址 + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查 // https请求 不验证证书和hosts + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在 + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器 + //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转 + //curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer + curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的Post请求 + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string); // Post提交的数据包 + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置超时限制防止死循环 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + //curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回 + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头 + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + + + +} \ No newline at end of file diff --git a/app/home/service/StockService.php b/app/home/service/StockService.php new file mode 100644 index 0000000..259d284 --- /dev/null +++ b/app/home/service/StockService.php @@ -0,0 +1,67 @@ +toData('0', 'SUCCESS', ['status' => '2']); + } + + // 1 开启 2 关闭 + $market = StockMarketModel::where('stock_market_type', $param['type'])->find(); + if(empty($market)){ + return $this->toData('0', 'SUCCESS', ['status' => '2']); + } + + if($market->status == StockMarketModel::STATUS_OFF){ + return $this->toData('0', 'SUCCESS', ['status' => '2', 'market' => $market->toArray()]); + } + + // 如果是开启 则判断是否在开盘时间段 + $date = date('H:i'); + $dateTime = \DateTime::createFromFormat('H:i', $date); + $amOpenTime = \DateTime::createFromFormat('H:i', $market->am_open_time); + $pmOpenTime = \DateTime::createFromFormat('H:i', $market->pm_open_time); + $amCloseTime = \DateTime::createFromFormat('H:i', $market->am_close_time); + $pmCloseTime = \DateTime::createFromFormat('H:i', $market->pm_close_time); + + // 判断 上午盘 + if($amOpenTime > $amCloseTime){ + // 开盘时间 大于 闭盘时间 跨天 + if($dateTime >= $amOpenTime || $dateTime <= $amCloseTime){ + return $this->toData('0', 'SUCCESS', ['status' => '1','market' => $market->toArray(),$dateTime,$amOpenTime,$amCloseTime,1]); + } + } else { + if($dateTime >= $amOpenTime && $dateTime <= $amCloseTime){ + return $this->toData('0', 'SUCCESS', ['status' => '1','market' => $market->toArray(),$dateTime,$amOpenTime,$amCloseTime,2]); + } + } + + // 下午盘 + if($pmOpenTime > $pmCloseTime){ + // 开盘时间 大于 闭盘时间 跨天 + if($dateTime >= $pmOpenTime || $dateTime <= $pmCloseTime){ + return $this->toData('0', 'SUCCESS', ['status' => '1','market' => $market->toArray(),$dateTime,$pmOpenTime,$pmCloseTime,3]); + } + } else { + if($dateTime >= $pmOpenTime && $dateTime <= $pmCloseTime){ + return $this->toData('0', 'SUCCESS', ['status' => '1','market' => $market->toArray(),$dateTime,$pmOpenTime,$pmCloseTime,4]); + } + } + + return $this->toData('0', 'SUCCESS', ['status' => '2','market' => $market->toArray()]); + }catch (\Exception $exception){ + return $this->toData('400','System error',[$exception->getMessage()]); + } + + } +} \ No newline at end of file diff --git a/app/home/service/TeamService.php b/app/home/service/TeamService.php new file mode 100644 index 0000000..cef16c5 --- /dev/null +++ b/app/home/service/TeamService.php @@ -0,0 +1,197 @@ +$user_id + ]); + $level2_num=UserLevelModel::getUserLevelCount([ + 'grandpa_id'=>$user_id + ]); + $level3_num=UserLevelModel::getUserLevelCount([ + 'top_id'=>$user_id + ]); + + //总人数 + $total_num=$level_num+$level2_num+$level3_num; + + $users_level=UserLevelModel::getUsers([ + 'parent_id'=>$user_id + ]); + if(!empty($users_level)){ + $users_level_arr=array_column($users_level,'user_id'); + $pay_level=RechargeApplyModel::getUserPayNum($users_level_arr); + }else{ + $pay_level=0; + } + $users_level2=UserLevelModel::getUsers([ + 'grandpa_id'=>$user_id + ]); + if(!empty($users_level2)){ + $users_level2_arr=array_column($users_level2,'user_id'); + $pay_level2=RechargeApplyModel::getUserPayNum($users_level2_arr); + }else{ + $pay_level2=0; + } + $users_level3=UserLevelModel::getUsers([ + 'top_id'=>$user_id + ]); + if(!empty($users_level3)){ + $users_level3_arr=array_column($users_level3,'user_id'); + $pay_level3=RechargeApplyModel::getUserPayNum($users_level3_arr); + }else{ + $pay_level3=0; + } + + $total_pay=$pay_level+$pay_level2+$pay_level3; + + + + //总收入 + $level_back_num=UserBrokerageModel::getUserBrokerageNum([ + 'user_id'=>$user_id, + 'level_type'=>1 + ],'brokerage_num'); + $level2_back_num=UserBrokerageModel::getUserBrokerageNum([ + 'user_id'=>$user_id, + 'level_type'=>2 + ],'brokerage_num'); + $level3_back_num=UserBrokerageModel::getUserBrokerageNum([ + 'user_id'=>$user_id, + 'level_type'=>3 + ],'brokerage_num'); + + $total_back_num=$level_back_num+$level2_back_num+$level3_back_num; + + //今日收入 + $today=date('Y-m-d 00:00:00'); + $level_today_num=UserBrokerageModel::getUserBrokerageNum([ + ['user_id','=',$user_id], + ['level_type','=',1], + ['create_time','>=',$today], + ],'brokerage_num'); + $level2_today_num=UserBrokerageModel::getUserBrokerageNum([ + ['user_id','=',$user_id], + ['level_type','=',2], + ['create_time','>=',$today], + ],'brokerage_num'); + $level3_today_num=UserBrokerageModel::getUserBrokerageNum([ + ['user_id','=',$user_id], + ['level_type','=',3], + ['create_time','>=',$today], + ],'brokerage_num'); + + + $today_back_num=$level_today_num+$level2_today_num+$level3_today_num; + + $result=[ + 'total_num'=>[ + 'reg_num'=>$total_num, + 'recharge_num'=>$total_pay, + 'back_num'=>$total_back_num, + 'today_back_num'=>$today_back_num + ], + 'level1'=>[ + 'reg_num'=>$level_num, + 'recharge_num'=>$pay_level, + 'back_num'=>$level_back_num, + 'today_back_num'=>$level2_today_num + ], + 'level2'=>[ + 'reg_num'=>$level2_num, + 'recharge_num'=>$pay_level2, + 'back_num'=>$level2_back_num, + 'today_back_num'=>$level2_today_num + ], + 'level3'=>[ + 'reg_num'=>$level3_num, + 'recharge_num'=>$pay_level3, + 'back_num'=>$level3_back_num, + 'today_back_num'=>$level3_today_num + ] + + ]; + + return $this->toData(0,'Request successful.',$result); + } + + public function getUserTeamBack(array $data) : array + { + $list=UserBrokerageModel::getUserBrokerageList($data); + return $this->toData(0,'Request successful.',$list); + } + public function getUserTeamList(array $data):array + { + $list=UserLevelModel::getUserTeamList($data); + return $this->toData(0,'Request successful.',$list); + } + + //注册返佣 + public function regBrokerage(int $parent_id,int $grandpa_id,int $top_id) + { + $reg_brokerage_stting=$this->getBrokerageRegSetting(); + $reg_parent_brokerage=$reg_brokerage_stting['parent_fee']; + $reg_grandpa_brokerage=$reg_brokerage_stting['grandpa_fee']; + $reg_top_brokerage=$reg_brokerage_stting['top_fee']; + if($reg_parent_brokerage>0 && $parent_id>0){ + $this->addUserBrokerage([ + 'user_id'=>$parent_id, + 'level_type'=>1, + 'back_type'=>0, + 'brokerage_num'=>$reg_parent_brokerage, + 'service_fee'=>0, + 'create_time'=>date('Y-m-d H:i:s'), + ]); + } + if($reg_grandpa_brokerage>0 && $grandpa_id>0){ + $this->addUserBrokerage([ + 'user_id'=>$grandpa_id, + 'level_type'=>2, + 'back_type'=>0, + 'brokerage_num'=>$reg_parent_brokerage, + 'service_fee'=>0, + 'create_time'=>date('Y-m-d H:i:s'), + ]); + } + if($reg_top_brokerage>0 && $top_id>0){ + $this->addUserBrokerage([ + 'user_id'=>$top_id, + 'level_type'=>3, + 'back_type'=>0, + 'brokerage_num'=>$reg_parent_brokerage, + 'service_fee'=>0, + 'create_time'=>date('Y-m-d H:i:s'), + ]); + } + } + private function addUserBrokerage($data) + { + UserBrokerageModel::InsertUserBrokerage($data); + //查询提现资金账户信息 + $from_account=(new WalletService())->lockUserBalance(1,$data['user_id']); + if(!empty($from_account)){ + $from_update['usable_num']=$from_account['usable_num']+$data['brokerage_num']; + (new WalletService())->updateUserBalance(1,$from_update,$data['user_id']); + $to_log['user_id']=$data['user_id']; + $to_log['change_type']=9; + $to_log['change_num']=$data['brokerage_num']; + $to_log['before_num']=$from_update['usable_num']; + (new WalletService())->addUserBalanceLog(1,$to_log); + } + } + + +} \ No newline at end of file diff --git a/app/home/service/TrcPayService.php b/app/home/service/TrcPayService.php new file mode 100644 index 0000000..66e192e --- /dev/null +++ b/app/home/service/TrcPayService.php @@ -0,0 +1,384 @@ +getPayConfig($key); + $this->http_url=env('WALLET.HTTP_URL'); + $this->app_id=$config['app_id']; + $this->private_key=$config['private_key']; + $this->public_key=$config['public_key']; + } + + public function WalletAddress() + { + $num=WalletListModel::where([ + 'user_id'=>0, + 'wallet_type'=>'TRC-20' + ])->count(); + if($num>100){ + return false; + } + $url=$this->http_url."/wallet/get_address"; + $data['version']="V3"; + $data['time']=time(); + $data['chain_name']='TRON'; + $encrypt_str=json_encode($data); + $str=RsaUtility::Encrypt($encrypt_str,$this->private_key); + $post_data['app_id']=$this->app_id; + $post_data['data']=$str; + $res=$this->http_post_res($url,$post_data); + $result=json_decode(RsaUtility::Decrypt($res['data'],$this->public_key),true); + if($result['code']==0 && $result['message']=='SUCCESS'){ + WalletListModel::InsertUserWalletAddress([ + 'user_id'=>0, + 'wallet_type'=>'TRC-20', + 'wallet_address'=>$result['data']['address'] + ]); + return true; + }else{ + Log::error('钱包服务器返回数据异常 '.json_encode($result)); + return false; + } + } + public function TrcpayNotify($data) + { + $result=json_decode(RsaUtility::Decrypt($data,$this->public_key),true); + //var_dump($result); + //充值 + if($result['type']==1){ + $user_id=WalletListModel::getUidByWallet([ + 'wallet_address'=>$result['to_address'] + ]); + if($user_id){ + $channel=PaymentListModel::getPaymentInfo([ + 'channel_type'=>'TRC-20' + ]); + //var_dump($channel); + if($result['symbol']=='USDT(TRC20)'){ + $account_type=1;//默认充值到现货账户 + return $this->dealRechangePay($user_id,$account_type,$channel,$result['amount'],$result['tx_hash']); + } + } + }else{ + + } + return 'SUCCESS'; + } + public function dealOrderConfirm($data) + { + $result=json_decode(RsaUtility::Decrypt($data,$this->public_key),true); + $result_data['check_sum']=0; + //$result_data['check_sum']=$result['check_sum']; + if(!empty($result)){ + $info=UserWithdrawalModel::getUserDrawalInfo([ + 'order_no'=>$result['request_id'] + ]); + if(!empty($info) && $info['apply_num']==$result['amount']){ + $result_data['check_sum']= $result['check_sum']; + } + } + $result_data['check_sum']= $result['check_sum']; + $encrypt_str=json_encode($result_data); + $str=RsaUtility::Encrypt($encrypt_str,$this->private_key); + return [ + 'data'=>$str + ]; + } + public function TrcAgnetPay($amount,$wallet_address,$order_no) + { + $url=$this->http_url."/wallet/transfer"; + $data['version']="V3"; + $data['time']=time(); + $data['to_address']=$wallet_address; + $data['amount']=$amount; + $data['symbol']='USDT(TRC20)'; + $data['request_id']=$order_no; + $encrypt_str=json_encode($data); + //echo $encrypt_str; + $str=RsaUtility::Encrypt($encrypt_str,$this->private_key); + $post_data['app_id']=$this->app_id; + $post_data['data']=$str; + $res=$this->http_post_res($url,$post_data); + $result=json_decode(RsaUtility::Decrypt($res['data'],$this->public_key),true); + if($result['code']==0){ + return [ + 'code'=>200, + 'msg'=>'ok', + 'order_idx'=>$result['data']['order_no'], + 'content'=>json_encode($result) + ]; + }else{ + return [ + 'code'=>300, + 'msg'=>$result['message'], + 'order_idx'=>'', + 'content'=>json_encode($result) + ]; + } + } + public function getTrcBalance(){ + $url=$this->http_url."/wallet/balance"; + $data['version']="V3"; + $data['symbol']='USDT(TRC20)'; + $data['time']=time(); + $encrypt_str=json_encode($data); + //echo $encrypt_str; + $str=RsaUtility::Encrypt($encrypt_str,$this->private_key); + $post_data['app_id']=$this->app_id; + $post_data['data']=$str; + $res=$this->http_post_res($url,$post_data); + $result=json_decode(RsaUtility::Decrypt($res['data'],$this->public_key),true); + if($result['code']==0){ + return [ + 'amount'=>$result['data']['amount'] + ]; + }else{ + return [ + 'amount'=>0 + ]; + } + } + private function dealRechangePay($user_id,$account_type,$channel,$amount,$tx_hash) + { + $ex_res=RechargeApplyModel::getOrderInfo([ + 'order_idx'=>$tx_hash + ]); + if($ex_res){ + return 'SUCCESS'; + } + if($channel['pay_type']==1){ + $fee= $amount * $channel['service_rate'] ; + }else{ + $fee= $channel['service_rate']; + } + $total_amount=$amount; + $market_amount=$amount-$fee; + //var_dump($market_amount); + if($market_amount>0){ + $rechange_data['user_id']=$user_id; + $rechange_data['account_type']=$account_type; + $rechange_data['recharge_type']=1; + $rechange_data['recharge_channel']=0; + $rechange_data['order_no']=$this->generateOrderNumber(); + $rechange_data['order_idx']=$tx_hash; + $rechange_data['deal_time']=date('Y-m-d H:i:s'); + $rechange_data['recharge_num']=$market_amount; + $rechange_data['currency_rate']=1; + $rechange_data['status']=1; + $rechange_data['market_amount']=$market_amount; + $rechange_data['service_fee']=$fee; + $rechange_data['total_amount']=$total_amount; + + $res=RechargeApplyModel::AddUserRecharge($rechange_data); + //var_dump($res); + if($res){ + Db::startTrans(); + try { + $wallet_obj=new WalletService(); + //查询提现资金账户信息 + $account_info=$wallet_obj->lockUserBalance($account_type,$user_id); + if(empty($account_info)){ + Db::rollback(); + return 'FAIL'; + } + $acc_update['usable_num']=$account_info['usable_num']+$market_amount; + $res=$wallet_obj->updateUserBalance($account_type,$acc_update,$user_id); + if(empty($res)){ + Db::rollback(); + return 'FAIL'; + } + $log_data['user_id']=$user_id; + $log_data['change_type']=1; //充值 + $log_data['change_num']=$market_amount; + $log_data['before_num']=$account_info['usable_num']; + $log_data['order_id']=$rechange_data['order_no']; + $res=$wallet_obj->addUserBalanceLog($account_type,$log_data); + if(empty($res)) Db::rollback(); + Db::commit(); + return 'SUCCESS'; + } catch (\Exception $exception) { + // 回滚事务 + Db::rollback(); + return 'FAIL'; + } + }else{ + return 'FAIL'; + } + + }else{ + return 'SUCCESS'; + } + } + + private function http_post_res($url, $postData) + { + try { + $client = new Client(); + $response = $client->request("POST", $url,[ + 'json' => $postData, + ]); + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + return $res; + }catch (\Exception $exception){ + Log::error('给钱包服务器发送数据异常1 '.$exception->getMessage()); + } catch (GuzzleException $e) { + Log::error('给钱包服务器发送数据异常2 '.$e->getMessage()); + } + } + + private function getPayConfig($key){ + $config=[ + 'test'=>[ + 'app_id'=>'MQ6fGxVZX1SbnYFxk1qH', + 'private_key'=>'-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDOc+ILpnKhurA+ +Rz1etWSC8bzbsyUzNFC7lSkpACRr3LlCoWbBXeRpgpWMwSW7B80QzvTTbZSr/Kk8 +sTJeotKCBCu1O0NpmSlsVe+BVfKoluSzdOmDQa7fViX0tNU+shLuef5oX5jTE3FA +wCsLMrCYAYKvwUrylrHC4EX6IznL1MD5anHLUNqrUHonNsHx4ZYX16Wpwlst4f2s +XgVnrnesX7iPoupIUgWhcLdKFhIQI0XAY/aoALKy+YGREimxlpm/FxQcCWC1tZBe +cPGWjLicHbGmyOcFUXxc/4D0XmdS+Xcr9pFWHyHV5iRtM6WFoWHKLPaz5+fPrIaW +6hXRSPeJAgMBAAECggEABmkcxMXXW2RDorttkWpKg7Jj7eKDLjLaquh3zbkeaGcD +Lal7WlfDBu+yGxvIQyV73aC/g20sp6aBzsulx8CAjt74SHldn4LNAXsto7N6hHej +BFuGALhiaLbxGMcgtACti9An8S++vBcndh5Bd+iMCTxKxZBX9m5teKKkKZ88ZTLY +uopvvtP51rc2Wo3h9dF0h4DIjJeguChDNKdxgT+PCukZ2DZsn8qL+1xAqPj7MKg9 +dukXLAmaa3nfcyKmc62cuIW/pRdZ6ZwI6rJ1p4/UwLLx93M9BXAMIJ+e37D0XtV+ +KJ+dAMRbwezK4isaQJjC0Z8hhtzbC0VN5Ih1SwBSAQKBgQDzA8n/xB5pXiMO1o0r +h7GnkSQSvwFCa8y2Okbm/SnJue3iaIhJGatVIJoWwRb6LFMNzRf+uKl9c3MJGS0G +CzT4Azswp1vuNcKq2FtKpAhq3X3CZ50sAmIH5dyht/yT0Zna0zJ9HB7XpEZlEZJQ +GwJNGt2gMDwEdzY3JoCeoSzqwQKBgQDZe/VzAFAsRuGN0DFCa0Rkp/+s6PiI3yUV +g57V3n8blZZZUjgWRgc0mnjHYOlvfbyUJEnRzUcMWoj+8iieg4bxmVTChEbrxkbd +IQVhQJOcjbokiR1UhsN67CkZcPzNXirGuek8j190DJHvCl26F9gkHCHHu9ryzYlp +P47ZgSwmyQKBgQDKG4efIJOOXE1Z5NRJtLPqwco3kQVSIWeC0prvNvPPIsQWPYvD +CAc3aELe073xWHXGj6D6JshHXoH4uih40089SSqr/zR0u99nyUK7pAqgHg+eZCAS +XvT6zpAdK3Bz26lSlb1y0bVQ8P3exqth1eSnDcXumM8Bg8fiPDJSO4eowQKBgGv5 +T+W1fRhOZIL8nsgj60Ox6IzW6TVC2+1veDckDKUMQiW8XR4pzEAAhQAvjBWPLkW6 +MnAX4zMt65/vZ90y3ZcrEdq0w2Ug/mOglkQvRFnQP18ON+KUOY7YmpsH7mqjWsdo +23P2lmROLVGpKtlOJz/eO6MnD8/F3XfEV06DBAGJAoGAQSC0XLlqqgwr7kYQwjQN +HNulo7QRhU36Y13MRMoGQ0FdOzjwbOxnt3Ozu0qjnraaUsBUaeyNam3kqamL63UF +4559oHwShlqNUEj/X769827MMpRpgO2ZuRZ0Vbi41aSRPC/bPnVKxk1+rOcJ1ofO +0Zmj0Gz7P2v5BLO7m1dlhhw= +-----END PRIVATE KEY-----', + 'public_key'=>'-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2MdaHtMSUnIJzmyhtHkQ +oR2ddffyU8UCATVnoKgcgzst55TvKmY2zCbjcf6cfJVIkYIEf5Wny3yhZbSEVRNg +GeEpB2N2QVYd3qdMVEa0Wq+rcrXzdzNy8uq0FzJMw114LPzF+OGKO8gKcmPnYKFm +4dbFxfIYhWQ+DaRJxgSZ6OaK5hFBXBlvUDLagn98ckdHvENhwuWaQ3Z2MpOhvO6z +qQLLj0VQU/LEkfnAcKpyy31iIfJxbMRop6DAJH+GXbhn5eARH8GDJLz32WkkqC8+ +vIkQhZyQI7fjpqtQoMXr7C31lME0QGLEQcWZtt8PfzFzMeW9MEcBWuxF41Ghf8jC +SwIDAQAB +-----END PUBLIC KEY-----' + ], + 'bourse'=>[ + 'app_id'=>'bVzIS6lChCNXk6w', + 'private_key'=>'-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCabCMxKsktrZQn +NkVYcu+UOI75uF4Jq6HoABNuTEXf7ff5SGTkJkLzk2lsPQwJQymX201uQV3FJqKg +HMMZwcFvfmNn2dapBgmyoO3fnWHxULVV04m+wFF7ol77c7llbvKTXnWZU3CEm42v +Bu0rIZrYmsWOvQN97LLfQmpfFGgbFP+fV8cQ2OaGC8r+BrBU2nzTVexlstBkaxEg +j15hlc5OC1sQvzpwnjmbydrL1LKEgMlwAAFLeEYhudb+ulaXGWG0Hm9YUEW0GAmD +eMaC6zgCI0rppLhGVTFrYnDCo0G3zoj+lqxVTgx3+u7dGKU63BLPuMEkzIdDizYQ +OJJ8YygbAgMBAAECggEAZscgaSIEAh3sZGjPoL3mzS0TpAtcs20DdqlORXQIcbEu +AUF4vQzmNL3hRcQf1a5Y6ZRxpbdl1MkRJiXeiK8XssBZIw6uu5KkM7q+d72FKZrB +Bl2j6UyRLwtz0kJEm8lLNGCDPsh1NB1gIKUohzN3n0DrykPtJgu7RbMrnxqy64p2 +qKYVh3hwbOkxTjde5E0AvPxH7iO4gRvOBZ9NmtKiDAVDkdyNI9lxYokya95Ag4cm +FJeDUoF1N8Wiw9lcjIVVEXeL+pI+rAX0zM/3jln0MWdE8FnaKp3o9YZkZsPpv3yu +EuJC0xf8iDJI28t+jEVmfw64XkvAOrN+8inEyfUy2QKBgQDHr1DzRVxLxqFBLRoj +O+wflwA9LcZain/DPCG+zTeChcf5NPB5l+yDIkAubx6MvFlBbnJ7nSu+i0KiJ/Bg +BZncadaivUA3oAsx5VG0th8Zv1jrBwIFPpzS90avpbEYy6ru+YMT+uYXpgpmYDSh +8HqcO2xcoUz7nO+LvtIlCHjcxwKBgQDF+QB7XQVDymA2p+POQ0nPE6gS8StFwvs1 +X/4F4CLBebRtcXvsj/NKqUva9682zCE08A9JTOp3UsqCA3gJEXFs/OBfgZKD/yoh +LmP81ANiJsNpcriEanE1tVifSID6oBkHPRgdsF1V6/C5/I6X6CPJh3Grh0t1/dW0 +uEeOj7p+DQKBgGeq9PPXRptwe7dCmxc/vM6Jrm4Una3TyZCqXzqXgAIbQj525YG7 +BebumTOCLPITtqLpnDXg2x0JX4agBYNUZRSxPeUvK2+1fxpgW5LeGjdbx+X8tWfT +ocdE6UW3V8HvusZmc06kK2CLq0qLF8ga+QyzLQbKFxVp3FNItgDT7StxAoGAcg75 +xhlbtSjdsd+ckfOWjKWoifFEmxaxIJlDgyMVIx75YqylVy/AXd2YBHn7Crkk0JkW +VYbo9wJOBgX1nFPeY4p1wtCmF0JlhWRy2vFTWbM3loMv56pjuyvV+T8OgFbI1LDQ +OhqoS555vM3TYZWvOKa+SLLUORCblVkucOZB7ekCgYArqqbE+tjNaVJ25KVtgmf1 +OswFLizTSmbzsyDvTT4BawgLbK/rOJB9fERujTNd0ZtM/uJ/MTgIWOaXxlA7SjX3 +yeScRql1I+9mvUZh/BvFCsir0ElfnMiGuZ/k6jqq0nl/h0a2nScISjvNwZwg0elF +Zwuv1gWW/tQFCSdfF8ewBQ== +-----END PRIVATE KEY-----', + 'public_key'=>'-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvhOR8XKjt5TH8wNpel26 +vDvWgC428q+QGyY0tQcYqAna7fTB1ta5DB1a8MyWIkV9kqwzBJbND/rSVZLyW//e +K7DliUvcNCCksC5RTvVW2A+cpUTemNz9Oc/lFcsszac3XQXlvieTWg20ii4s89N9 +vwr0fWi72umEtkDkpDcU/aGJWv5yxBl3OMeIPUqPiM+9quiWr5ZUqo6zlvtzWz1H +57IPdOxgGoRgCccaINt2PJVDFJ0d3L+ZQsKEKJY4OkhLAjKbuEDxuj0BcLVwnPr1 +x52/dTSyUZca3nJOeaSRBEzOx5oqbbRfyUbzQhFu2UD/ZeDS4dIRmxPeDcF+5aJF +IQIDAQAB +-----END PUBLIC KEY-----' + ], + 'stock'=>[ + 'app_id'=>'mCy0zbuRRRstYGq', + 'private_key'=>'-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDTu2XAYZ+hQkrl +mUP0xpSwg1wMxmTfXKeOQmmwfSgi2k5g/NlTblwoK+pVDaav1UXIEI5cThZWu+HT +ljPxZHSQlldSy/N34yE33ioTl1Bq7W10Yq6iOjJMybjqmARbbbdbNB5ktnb3DmmQ +ZxexV2Pj7XUrVDtagngH7JF1lEaK6zkbP8koxBOo/sBmvIsd6ps+B+5nMOnpYMNd +0dn1N6YJmjWKVbkRbNDM5BasJwTQ8kbYQ/XN0YhCdjixcrhpADDypkqQJ/AA2Ys+ +8uEtnB1yZV+hbCMbbUDpZlsOagLmF3C7FywHxzXlkuzdTP/Til7tjnky0B1E4fv1 +e3Ff5eTZAgMBAAECggEBAMkMSqQQjtk6749wpzyIS6wIL6HZyPLnMhs9KMpzLWda +z838ighU5KEoggxdOAgChY5hWix/4WpeYSLen1f5wU2B1E1EaF1QiLxZ8q5DohLG +fIZlJdnZVOXhLftkec6vMcoihTGwqOoS/14k5jR4/NrzIa0RAIMDHCK6Ga0CLLG+ +yxR/D1kh/mzJ3g+l/smrfwSJKcglSAJA79sqCOirY26cTv8xabM1MqECClhhS1p2 +o2BICiy1AyOR0pXS8Z5IvC3IEMJBs4XmkYHc1118w8Y97o+2EyY2LNLe5z3GvPgS +n2vFN+Wr9z1C4fUKnoW8W60VXacP+FTN14ydj4jRBHkCgYEA85ZhjLID0V9j/eIH +2mvAOzK/HULNYExNuLb461tda4fIHbcU93gCFvmf+BTbxRwsOJsYQ+Cd1NZe7OH4 +JrXFrEUNh5oGz+UANTbIkWHFEUeyihe0dcbS2n4/7siY9gUU897zgdKIt3H5T9rP +9fuXTt0F2u7nGMYdOJPPO5czI08CgYEA3oV1vSI1HdYWsBUbcTSUQsU1r8YpoagH +kmwYTvm8KiizdI9VOQLj6xMRZCDidsYqrduT9fcce756R/QE7QEb6wsHFzfoHiCp +ZYfjYp6YouyU8snQzwVmO7JkvOZcWQedcoZGJ/ZadKOoGNWlXQn8WqQuTSw/1kta +nkPkhM7Xi1cCgYBopH+/q3HMbkhMdt+cy5FHXSOQ9HO6HM1+vsvsf9GAMlKbwVz2 +es2bBR3du0g2Q0YUAzzHXCUxm+4noWOzbX8/5GJNkLPAd8ZBFgnPusqoA78FZ+2U +cxd92aKpd++OMNyxb2P4r3MgK4xI691O9QgpTvYG+X65u9ItzgHGvcuwLQKBgBBe +dvPL0WZ5ej/HvbYNLR7gTPu6MxPOPYha5Urh+iKLze+0H4vLF6MSSwQ3mxErsLYL +Yg4E+JZtw6cJX1dj7n7S19mwZiXZNzzdyy9VBVtu1eIqUG76MbQQgnKW65ItCjsD +f6Ou7qaH53S0Oq7mbibozvMkXynPb0IXMndGk/qPAoGACYz1oExg/3zGNezrC2PY +fFkgZY69iGjr6y9G6giy15ocBHR+1lLVSKkzzrCuO9tw+sGQCXiFGxx2Ne3k/htu +mzqXoTsMRyGk5Pi7I/zRyvKXiIm/adz46m/Y8l6aDgexFuW9Y+23L3IwPWaZzR+z +VjXIC2JkJA2RpBAV0HIXEgQ= +-----END PRIVATE KEY-----', + 'public_key'=>'-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyQtS6llJRABJkVE/cuVE +5lvur0kPYSN/tBgwwye/O2jHl5M0fZGFpx3KLeq8PQxqobGXFYe4CzxX5/RNP7OT +/AGR1UqkSK0ZGYGcz0kanIq+Oq1xCZQQyEAcZ9elZzUG3hBi1TR8Dn2MvIuRvKVz +EFVyyWoAjL+dBV5yn26cXXNkDVkrD4qtFUihUe76xXTxf5TWXCYzmIX4yeu1w47w +f/K2rWENe/Uo2fUaAfN41hsrIZMo8LZLGi94G4hVlXqfE9F/KSGJh0YNF5o0Lod7 +cS/uZZvDSYc2CqBoT5OGsdz6l93kd9QBupAmwQL/u4CmeOePyuZ3rA1yHxQBpEzF +ZwIDAQAB +-----END PUBLIC KEY-----' + ] + ]; + return isset($config[$key]) ? $config[$key]: $config['test']; + } + + + +} \ No newline at end of file diff --git a/app/home/service/UserService.php b/app/home/service/UserService.php new file mode 100644 index 0000000..fe384ec --- /dev/null +++ b/app/home/service/UserService.php @@ -0,0 +1,1576 @@ +createUserLevel($user_id, $parent_id); + (new TeamService())->regBrokerage($data['parent_id'], $data['grandpa_id'], $data['top_id']); + } + $this->initUserWallet($user_id); + } + + /** + * 处理用户等级关系 + * @param int $user_id + * @param int $parent_id + * @return bool + */ + private function createUserLevel(int $user_id, int $parent_id) + { + //插入用户等级关系 + if ($parent_id > 0) { + $parent_info = UserLevelModel::getUserLevelById($parent_id); + $grandpa_id = $parent_info['parent_id']; + $top_id = $parent_info['grandpa_id']; + } else { + $grandpa_id = 0; + $top_id = 0; + } + $data['user_id'] = $user_id; + $data['parent_id'] = $parent_id; + $data['grandpa_id'] = $grandpa_id; + $data['top_id'] = $top_id; + UserLevelModel::InsertUserLevel($data); + return $data; + } + + public function getUserLevel(int $user_id) + { + $level_info = UserLevelModel::getUserLevelById($user_id); + $this->setUserLevel($user_id, $level_info); + } + + /** + * 初始化各钱包数据 U数据 + * @param int $user_id + * @return void + */ + private function initUserWallet(int $user_id) + { + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + UserMoneyModel::InsertUserMoneyk([ + 'user_id' => $user_id, + 'stock_id' => 'USD', + 'usable_num' => 0, + 'frozen_num' => 0, + ]); + }else{ + if (env('FEATURE.HAS_STOCK_US')) { + UserStockModel::InsertUserStock([ + 'user_id' => $user_id, + 'stock_id' => 'USD', + 'usable_num' => 0, + 'frozen_num' => 0, + ]); + } + if (env('FEATURE.HAS_DIGITAL')) { + UserDigitalModel::InsertUserDigital([ + 'user_id' => $user_id, + 'digital_id' => 'USDT', + 'usable_num' => 0, + 'frozen_num' => 0, + ]); + } + if (env('FEATURE.HAS_CONTRACT')) { + UserContractModel::InsertUserContract([ + 'user_id' => $user_id, + 'contract_id' => 'USDT', + 'usable_num' => 0, + 'frozen_num' => 0, + ]); + } + } + + + } + + /** + * @desc 获取用户信息 + * @param $userId + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function getUserInfo($userId) + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first', []); + } + + $info = UserModel::getFieldsByUserId('trade_password,lever_status,gender,last_name,first_name,real_status,country_id,user_no,nick_name,email,phone_number,country_code,is_real,head_img_id,invite_code,is_test_user', $userId); + if (empty($info)) { + return $this->toData('100400', 'The user does not exist.', []); + } + + // 获取国家名称 + $countryId = $info['country_id']; + + $countryName = ''; + if ($countryId > 0) { + $countryName = CountryModel::getNameById($countryId); + } + + // 获取头像 + $headPath = env('USER.DEFAULT_HEAD_IMG_PATH'); + if ($info['head_img_id'] > 0) { + $headPath = FileModel::getFilePath($info['head_img_id']); + } + + $key = 'LEVERAGE:' . $userId; + $leverageNum = Cache::store('redis')->get($key); + if (empty($leverageNum)) { + $key = 'LEVERAGE:0'; + $leverageNum = Cache::store('redis')->get($key); + } + $leverageNum= empty($leverageNum) ? 1: $leverageNum; + + // 返回数据 + return $this->toData('0', 'Modification successful.', [ + 'logo' => $headPath, + 'userId' => $userId, + 'userNo' => $info['user_no'], + 'nickName' => $info['nick_name'], + 'nation' => $info['country_code'], + 'phone' => $info['phone_number'], + 'email' => $info['email'], + 'isReal' => $info['is_real'], + 'is_test_user' => $info['is_test_user'], + 'real_status' => $info['real_status'], + 'inviteCode' => $info['invite_code'], + 'firstName' => $info['first_name'], + 'lastName' => $info['last_name'], + 'gender' => (string)$info['gender'], + 'isSetPayPassword' => $info['trade_password'] ? '1' : '0', + 'country' => $countryName, + 'countryId' => $countryId, + 'lever_status' => $info['lever_status'], + 'leverage_num' =>$leverageNum + ]); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * @desc 设置用户国家 + * @param $userId + * @param $param + * @return array + */ + public function setCountry($userId, $param): array + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + // 邮件注册参数校验 + validate(UserValidate::class)->scene('setCountry')->check($param); + $countryId = $param['country_id']; + + // 国家是否存在 + $country = CountryModel::getById($countryId); + if (empty($country)) { + return $this->toData('100400', 'Unsupported country or region.', []); + } + + // 是否是黑名单国家 + if ($this->checkForbidNation($country['code'])) { + return $this->toData('100400', 'Unsupported country or region.', []); + } + + // 设置 + UserModel::updateFieldsByUserId(['country_id' => $country['id']], $userId); + return $this->toData('0', 'Modification successful.'); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('100400', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * @desc 更新用户头像 + * @param $userId + * @param $param + * @return array + */ + public function updateHeadImg($userId, $param): array + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('updateHeadImg')->check($param); + $fileId = $param['file_id']; + + // 文件是否存在 + $file = FileModel::getById($fileId); + if (empty($file)) { + return $this->toData('100400', 'The file does not exist.', []); + } + + + // 设置 + UserModel::updateFieldsByUserId(['head_img_id' => $fileId], $userId); + return $this->toData('0', 'Modification successful.'); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('100400', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', []); + } + } + + /** + * @desc 设置用户 昵称 性别 名字信息 + * @param $userId + * @param $param + * @return array + */ + public function updateInfo($userId, $param): array + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('updateInfo')->check($param); + + // 查找用户信息 + $user = UserModel::getFieldsByUserId('user_id,nick_name,first_name,first_name,gender', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + $nickName = $param['nick_name']; + $gender = $param['gender']; + $lastName = $param['last_name'] ?? $user['last_name']; + $first_name = $param['first_name'] ?? $user['first_name']; + + UserModel::updateFieldsByUserId([ + 'nick_name' => $nickName, + 'first_name' => $first_name, + 'last_name' => $lastName, + 'gender' => $gender, + ], $userId); + + // 返回 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 登陆状态下发送短信 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function sendEmail($userId, $param) + { + try { + $ip = $this->getClientRealIp(); + + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('sendEmail')->check($param); + + // 如果是非交易业务 需要判断验证码获取次数 + $key = 'USER:SEND_CODE_NUM:' . $ip; + if ($param['business'] == '1') { + if ($this->checkGetNoTradeCodeNum($key)) { + return $this->toData('100300', 'No worries. Please feel free to reach out again tomorrow.', []); + } + } + + // 提取参数 + $emailType = $param['email_type']; // 1 给已经绑定的邮箱发 2 给新邮箱发 + $email = $param['email'] ?? ''; + if ($emailType == 1) { + $email = UserModel::getEmailById($userId); + if (empty($email)) { + return $this->toData('100400', '邮箱未绑定', []); + } + } + + // 获取邮件内容 + $content = $this->getEmailContent(); + $content['email'] = $email; + $code = $content['code']; + Queue::push('app\home\job\SendEmail', $content, 'sendEmail'); + + // 设置缓存 + $sendEmailCacheKey = 'USER:sendEmailLoginTrade:' . $email; + if ($param['business'] == '1') { + $sendEmailCacheKey = 'USER:sendEmailLoginNoTrade:' . $email; + // 累加ip获取的次数 + $this->updateHadGetCodeNumCache($key); + } + + $this->insertCodeToCache($sendEmailCacheKey, $code, 300); + + // 返回结果 + return $this->toData('0', 'Modification successful.'); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + /** + * @desc 登陆状态下发送短信 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function sendSms($userId, $param): array + { + try { + $ip = $this->getClientRealIp(); + + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('sendSms')->check($param); + + // 如果是非交易业务 需要判断验证码获取次数 + $key = 'USER:SEND_CODE_NUM:' . $ip; + if ($param['business'] == '1') { + if ($this->checkGetNoTradeCodeNum($key)) { + return $this->toData('100300', 'No worries. Please feel free to reach out again tomorrow.', []); + } + } + + // 提取参数 + $phoneType = $param['phone_type']; // 1 给已经绑定的手机发 2 给新手机发 + $phone = $param['phone'] ?? ''; + $nation = $param['nation'] ?? ''; + if ($phoneType == 1) { + $user = UserModel::getFieldsByUserId('country_code,phone_number', $userId); + if (empty($user)) { + return $this->toData('100400', 'The phone number is not linked/bound.', []); + } + $phone = $user['phone_number']; + $nation = $user['country_code']; + } else { + // 如果给新手机发 判断国家码是否存在 + $nationCheck = CountryModel::checkCodeExists($nation); + if (!$nationCheck) { + return $this->toData('100400', 'Unsupported country or region.', []); + } + } + + $mobile = $nation . $phone; + + // 获取邮件内容 + $content = $this->getSmsContent(1); + $content['mobile'] = $mobile; + $code = $content['code']; + Queue::push('app\home\job\SendSms', $content, 'sendSms'); + + // 设置缓存 + $sendCodeKey = 'USER:sendSmsLoginTrade:' . $mobile; + + if ($param['business'] == '1') { + $sendCodeKey = 'USER:sendSmsLoginNoTrade:' . $mobile; + // 累加已经获取的次数 + $this->updateHadGetCodeNumCache($key); + } + $this->insertCodeToCache($sendCodeKey, $code, 300); + + + // 返回结果 + return $this->toData('0', 'Modification successful.'); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + public function setPayPasswordByEmail($userId, $param) + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code pay_password + validate(UserValidate::class)->scene('setPayPasswordByEmail')->check($param); + + // 获取用户 + $user = UserModel::getFieldsByUserId('email,user_id,trade_password', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + +// // 校验验证码 +// $key = 'USER:sendEmailLoginNoTrade:'.$user['email']; +// $emailCache = Cache::store('redis')->get($key); +// if(empty($param['email_code']) || $emailCache != $param['email_code']){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 如果已经存在交易密码 则不能设置 + if (!empty($user['trade_password'])) { + return $this->toData('100400', 'The payment password has already been set.', []); + } + + // 加密密码 + $payPassword = $param['pay_password']; + $salt = env('ENCRYPT.SALT'); + $payPassword = (new UnqId())->encryptPassword($payPassword, $salt); + + // 设置密码 + UserModel::setPayPassword($payPassword, $salt, $userId); + + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', []); + } + } + + /** + * @desc 通过短信设置取款密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function setPayPasswordBySms($userId, $param) + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 nation phone pay_password + validate(UserValidate::class)->scene('setPayPasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('country_code,phone_number,user_id,trade_password', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + if (!empty($user['trade_password'])) { + return $this->toData('100400', 'The payment password has already been set.', []); + } + +// // 校验验证码 +// $mobile = $user['country_code'].$user['phone_number']; +// $key = 'USER:sendSmsLoginNoTrade:'.$mobile; +// if(Cache::store('redis')->get($key) != $param['sms_code']){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验验证码 + $payPassword = $param['pay_password']; + $salt = env('ENCRYPT.SALT'); + $payPassword = (new UnqId())->encryptPassword($payPassword, $salt); + + + // 设置密码 + UserModel::setPayPassword($payPassword, $salt, $userId); + + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 通过手机号修改交易密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updatePayPasswordBySms($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('updatePayPasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,trade_password,salt,phone_number,country_code', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $nation = $user['country_code']; +// $phone = $user['phone_number']; +// $smsCode = $param['sms_code']; + $payPassword = $param['pay_password']; + $payPasswordNew = $param['pay_password_new']; + + // 校验验证码 +// $mobile = $nation.$phone; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验旧密码 + $checkPasswordBool = (new UnqId())->checkPassword($payPassword, $user['trade_password'], $user['salt']); + if (!$checkPasswordBool) { + return $this->toData('100400', 'Incorrect password.'); + } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($payPasswordNew, $user['salt']); + UserModel::updateFieldsByUserId(['trade_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 根据邮箱修改交易密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updatePayPasswordByEmail($userId, $param) + { + // 通过 邮箱 收款密码 重新设置收款密码 + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('updatePayPasswordByEmail')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,trade_password,salt,email', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $email = $user['email']; +// $emailCode = $param['email_code']; + $payPassword = $param['pay_password']; + $payPasswordNew = $param['pay_password_new']; + + // 校验验证码 +// $cacheEmailKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheEmailCode = Cache::store('redis')->get($cacheEmailKey); +// if(empty($emailCode) || $emailCode != $cacheEmailCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验旧密码 + $checkPasswordBool = (new UnqId())->checkPassword($payPassword, $user['trade_password'], $user['salt']); + if (!$checkPasswordBool) { + return $this->toData('100400', 'Incorrect password.', []); + } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($payPasswordNew, $user['salt']); + UserModel::updateFieldsByUserId(['trade_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 根据短信重新设置交易密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function resetPayPasswordBySms($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('resetPayPasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,salt,phone_number,country_code', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $nation = $user['country_code']; +// $phone = $user['phone_number']; +// $smsCode = $param['sms_code']; + $payPasswordNew = $param['pay_password_new']; + + // 校验验证码 +// $mobile = $nation.$phone; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($payPasswordNew, $user['salt']); + UserModel::updateFieldsByUserId(['trade_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 通过邮箱重新设置交易密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function resetPayPasswordByEmail($userId, $param) + { + // 通过邮箱验证码 新密码 设置交易密码 + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('resetPayPasswordByEmail')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,salt,email', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $email = $user['email']; +// $emailCode = $param['email_code']; + $payPasswordNew = $param['pay_password_new']; + + // 校验验证码 +// $cacheEmailKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheEmailCode = Cache::store('redis')->get($cacheEmailKey); +// if(empty($emailCode) || $emailCode != $cacheEmailCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($payPasswordNew, $user['salt']); + UserModel::updateFieldsByUserId(['trade_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + public function updatePasswordBySms($userId, $param) + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('updatePasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,login_password,salt,phone_number,country_code', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $nation = $user['country_code']; +// $phone = $user['phone_number']; +// $smsCode = $param['sms_code']; + $password = $param['password']; + $passwordNew = $param['password_new']; + + // 校验验证码 +// $mobile = $nation.$phone; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验旧密码 + $checkPasswordBool = (new UnqId())->checkPassword($password, $user['login_password'], $user['salt']); + if (!$checkPasswordBool) { + return $this->toData('100400', 'Incorrect password.', []); + } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($passwordNew, $user['salt']); + UserModel::updateFieldsByUserId(['login_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 邮箱修改登陆密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updatePasswordByEmail($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('updatePasswordByEmail')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,login_password,salt,email', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $email = $user['email']; +// $emailCode = $param['email_code']; + $password = $param['password']; + $passwordNew = $param['password_new']; + + // 校验验证码 +// $cacheEmailKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheEmailCode = Cache::store('redis')->get($cacheEmailKey); +// if(empty($emailCode) || $emailCode != $cacheEmailCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验旧密码 + $checkPasswordBool = (new UnqId())->checkPassword($password, $user['login_password'], $user['salt']); + if (!$checkPasswordBool) { + return $this->toData('100400', 'Incorrect password.', []); + } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($passwordNew, $user['salt']); + UserModel::updateFieldsByUserId(['login_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 短信重新设置登陆密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function resetPasswordBySms($userId, $param) + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('resetPasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,salt,phone_number,country_code', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $nation = $user['country_code']; +// $phone = $user['phone_number']; +// $smsCode = $param['sms_code']; + $passwordNew = $param['password_new']; + + // 校验验证码 +// $mobile = $nation.$phone; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($passwordNew, $user['salt']); + UserModel::updateFieldsByUserId(['login_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 邮箱重新设置登陆密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function resetPasswordByEmail($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('resetPasswordByEmail')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,salt,email', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $email = $user['email']; +// $emailCode = $param['email_code']; + $passwordNew = $param['password_new']; + + // 校验验证码 +// $cacheEmailKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheEmailCode = Cache::store('redis')->get($cacheEmailKey); +// if(empty($emailCode) || $emailCode != $cacheEmailCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($passwordNew, $user['salt']); + UserModel::updateFieldsByUserId(['login_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + public function bindEmail($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('bindEmail')->check($param); + + // 判断验证码 +// $emailCode = $param['email_code']; + $email = $param['email']; +// $cacheCodeKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheSmsCode = Cache::store('redis')->get($cacheCodeKey); +// if(empty($emailCode) || $emailCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('email,user_id', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 判读是否已经绑定 + if (!empty($user['email'])) { + return $this->toData('100400', 'You have already bound your email', []); + } + + //判断手机号是否已经被别人绑定 + $emailExits = UserModel::checkEmailExists($email); + if ($emailExits) { + return $this->toData('100400', 'The email has been bound', []); + } + + // 执行入库操作 + UserModel::updateFieldsByUserId(['email' => $email], $userId); + + // 返回结果 + return $this->toData('0', 'Binding successful', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + /** + * @desc 修改已经绑定的手机号 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updateEmail($userId, $param): array + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 nation phone sms_code + validate(UserValidate::class)->scene('updateEmail')->check($param); + + // 判断验证码 +// $emailCode = $param['email_code']; + $email = $param['email']; +// $cacheCodeKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheSmsCode = Cache::store('redis')->get($cacheCodeKey); +// if(empty($emailCode) || $emailCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('login_password,email,user_id,salt', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 判读是否已经绑定 需要已经绑定 + if (empty($user['email'])) { + return $this->toData('100400', 'Email is not linked/bound.', []); + } + + //校验登陆密码 + $passwordCheck = (new UnqId())->checkPassword($param['password'], $user['login_password'], $user['salt']); + if (!$passwordCheck) { + return $this->toData('100400', 'Incorrect password.', []); + } + + //判断手机号是否已经被别人绑定 + $emailExits = UserModel::checkEmailExists($email); + if ($emailExits) { + return $this->toData('100400', 'The email has already been linked/bound.', []); + } + + // 执行入库操作 + UserModel::updateFieldsByUserId(['email' => $email], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + + public function bindPhone($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 nation phone sms_code + validate(UserValidate::class)->scene('bindPhone')->check($param); + + // 判断验证码 +// $smsCode = $param['sms_code']; +// $mobile = $param['nation'].$param['phone']; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,country_code,phone_number', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 判读是否已经绑定 + if (!empty($user['phone_number'])) { + return $this->toData('100400', 'The phone number has already been linked/bound.', []); + } + + //判断手机号是否已经被别人绑定 + $phoneExits = UserModel::checkPhoneExists($param['phone']); + if ($phoneExits) { + return $this->toData('100400', 'The phone number has already been linked/bound.', []); + } + + // 判断国家码是否存在 + $codeExists = CountryModel::checkCodeExists($param['nation']); + if (!$codeExists) { + return $this->toData('100400', 'Unsupported country or region.', []); + } + + // 执行入库操作 + UserModel::updateFieldsByUserId(['phone_number' => $param['phone'], 'country_code' => $param['nation']], $userId); + + // 返回结果 + return $this->toData('0', 'Binding successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + /** + * @desc 修改已经绑定的手机号 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updatePhone($userId, $param): array + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 nation phone sms_code + validate(UserValidate::class)->scene('updatePhone')->check($param); + + // 判断验证码 +// $smsCode = $param['sms_code']; +// $mobile = $param['nation'].$param['phone']; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 判断国家码是否存在 + $codeExists = CountryModel::checkCodeExists($param['nation']); + if (!$codeExists) { + return $this->toData('100400', 'Unsupported country or region', []); + } + + //判断手机号是否已经被别人绑定 + $phoneExits = UserModel::checkPhoneExists($param['phone']); + if ($phoneExits) { + return $this->toData('100400', 'The phone number has already been linked/bound.', []); + } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('salt,login_password,user_id,country_code,phone_number', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 判读是否已经绑定 需要已经绑定手机 + if (empty($user['phone_number'])) { + return $this->toData('100400', 'The phone number is not linked/bound.', []); + } + + //校验登陆密码 + $passwordCheck = (new UnqId())->checkPassword($param['password'], $user['login_password'], $user['salt']); + if (!$passwordCheck) { + return $this->toData('100400', 'Incorrect password.', []); + } + + // 执行入库操作 + UserModel::updateFieldsByUserId(['phone_number' => $param['phone'], 'country_code' => $param['nation']], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + public function apply_loan($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 nation phone sms_code + validate(UserValidate::class)->scene('apply_loan')->check($param); + $count=UserLoanModel::where('status',0)->where('user_id',$userId)->count(); + if($count>0){ + return $this->toData('100402', 'You have applied, please be patient and wait.', []); + } + + $userloan=new UserLoanModel(); + $userloan->user_id=$userId; + $userloan->num= intval($param['num']); + $userloan->day= intval($param['day']); + $userloan->status= 0; + $userloan->is_delete= 0; + $userloan->create_time=date('Y-m-d H:i:s'); + $userloan->save(); + + // 返回结果 + return $this->toData('0', 'Binding successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + public function loan($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + $data['where']['user_id']=$userId; + $data['page']=isset($param['page']) ? intval($param['page']) : 1; + $data['size']=isset($param['size']) ? intval($param['size']) : 10; + $list=UserLoanModel::getUserLoanList($data); + // 返回结果 + return $this->toData('0', 'successful.', $list); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + + /** + * @desc 退出登陆 + * @param $userId + * @return array + */ + public function logout($userId) + { + try { + // 删除缓存 + $this->delUserTokenCache($userId); + return $this->toData('0', 'Modification successful.'); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 获取用户登陆信息 + * @param $userId + * @return array + */ + public function loginLog($userId): array + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + $data = UserLoginLog::getLog($userId); + if (empty($data)) { + return $this->toData('0', 'Modification successful.', []); + } + + $res = []; + foreach ($data as $item) { + $countryCn = ''; + $countryEn = ''; + $cityCn = ''; + $cityEn = ''; + if (!empty($item['country'])) { + $countryArr = json_decode($item['country'], true); + $countryCn = $countryArr['cn']; + $countryEn = $countryArr['en']; + } + + if (!empty($item['city'])) { + $cityArr = json_decode($item['city'], true); + $cityCn = $cityArr['cn']; + $cityEn = $cityArr['en']; + } + + $res[] = [ + 'device' => $item['device'], + 'ip' => $item['ip'], + 'countryCn' => $countryCn, + 'countryEn' => $countryEn, + 'cityCn' => $cityCn, + 'cityEn' => $cityEn, + 'loginDate' => $item['login_date'], + ]; + } + + return $this->toData('0', 'Modification successful.', $res); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', []); + } + } + + /** + * 用户申请使用杠杆 + * @param $userId + * @return array + */ + public function leverApply($userId) + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('lever_status,user_id', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + if (in_array($user['lever_status'], [UserModel::LEVER_STATUS_NO, UserModel::LEVER_STATUS_FAIL])) { + $level_status=env('USER_LEVEL.NO_APPLY')==1 ? UserModel::LEVER_STATUS_PASSED : UserModel::LEVER_STATUS_APPLY; + UserModel::update(['lever_status' => $level_status, 'update_time' => date('Y-m-d H:i:s')], ['user_id' => $userId]); + return $this->toData('0', 'success.', []); + } + + return $this->toData('0', 'Already submitted.', []); + + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', []); + } + } + public function applyTestAccount($userId) + { + + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('test_account,user_id,user_no', $userId); + if (empty($user)) { + return $this->toData('100401', 'Please log in first.', []); + } + if(!empty($user['test_account'])){ + return $this->toData('0', 'success.', []); + } + //添加模拟账号 + $userNo=$this->getUniqUserNo(); + $email="test_".$userNo."@test.com"; + $salt = env('ENCRYPT.SALT'); + $password = (new UnqId())->encryptPassword('test12345', $salt); + $userInviteCode=$this->getUniqInviteCode(); + $parentUserId = $userId; + $ip = (new BaseHomeService())->getClientRealIp(); + $test_userId = UserModel::emailRegister($email, $userNo, $userInviteCode, $parentUserId, $password, $ip, $salt, 2, 0); + if($test_userId){ + $this->doRegInitUserInfo($test_userId,$parentUserId); + UserModel::where('user_id', $userId)->update([ + 'test_account' => $test_userId + ]); + UserModel::where('user_id', $test_userId)->update([ + 'is_real' => 0, + 'real_status'=>3 + ]); + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + UserMoneyModel::where('user_id', $test_userId)->update([ + 'user_id' => $test_userId, + 'stock_id' => 'USD', + 'usable_num' => 100000, + 'frozen_num' => 0, + ]); + }else{ + UserDigitalModel::where('user_id', $test_userId)->update([ + 'user_id' => $test_userId, + 'digital_id' => 'USDT', + 'usable_num' => 100000, + 'frozen_num' => 0, + ]); + UserContractModel::where('user_id', $test_userId)->update([ + 'user_id' => $test_userId, + 'contract_id' => 'USDT', + 'usable_num' => 100000, + 'frozen_num' => 0, + ]); + UserForexModel::InsertUserForex([ + 'user_id' => $test_userId, + 'contract_id' => 'USD', + 'usable_num' => 100000, + 'frozen_num' => 0, + ]); + UserStockHkdModel::InsertUserStock([ + 'user_id' => $test_userId, + 'stock_id' => 'HKD', + 'usable_num' => 100000, + 'frozen_num' => 0, + ]); + } + + } + return $this->toData('0', 'success.', []); + } + public function applyTestMoney($userId,$param){ + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('is_test_user,user_id,user_no', $userId); + if (empty($user)) { + return $this->toData('100401', 'Please log in first.', []); + } + if($user['is_test_user']!=2){ + return $this->toData('100402', 'error.', []); + } + $num=isset($param['num']) ? intval($param['num']) : 0; + if($num<=0 || $num>100000){ + return $this->toData('100401', 'error.', []); + } + $user_money=UserMoneyModel::getUserUSDByUserId(['user_id'=>$userId]); + $update_num=$user_money['usable_num']+$num; + UserMoneyModel::where('user_id', $userId)->update([ + 'stock_id' => 'USD', + 'usable_num' => $update_num, + 'update_time' => date('Y-m-d H:i:s'), + ]); + + return $this->toData('0', 'success.', []); + } + public function testLogin($userId) + { + // 获取用户信息 + $user = UserModel::getFieldsByUserId('test_account,user_id,user_no', $userId); + if (empty($user)) { + return $this->toData('100401', 'Please log in first.', []); + } + if(empty($user['test_account'])){ + return $this->toData('100402', 'Please log in first.', []); + } + //登录模拟账号 + $test_user=UserModel::getFieldsByUserId('test_account,user_id,user_no,nick_name,invite_code,is_real,is_test_user', $user['test_account']); + // 生成token + $token = (new Jwt())->getToken($test_user['user_id'], env('ENCRYPT.SALT')); + if (empty($token)) { + return $this->toData('100300', 'The system is busy.', []); + } + + // 将token存致缓存 覆盖新的缓存 实现单设备登陆 + $this->setUserTokenCache($token, $test_user['user_id']); + // 删除缓存 + $this->delUserTokenCache($userId); + // 返回结果以及用户信息 + return $this->toData('0', 'Request successful.', [ + 'userId' => $test_user['user_id'], + 'userNo' => $test_user['user_no'], + 'nickName' => $test_user['nick_name'], + 'inviteCode' => $test_user['invite_code'], + 'isReal' => $test_user['is_real'], + 'is_test_user' => $test_user['is_test_user'], + 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), + 'token' => $token, + ]); + } + public function formalLogin($userId) + { + // 获取用户信息 + $user = UserModel::getFieldsByUserId('parent_id,user_id,user_no,is_test_user', $userId); + if (empty($user)) { + return $this->toData('100401', 'Please log in first.', []); + } + if(empty($user['parent_id'])){ + return $this->toData('100402', 'The system is busy.', []); + } + if(empty($user['is_test_user'])){ + return $this->toData('100403', 'The system is busy.', []); + } + //登录模拟账号 + $test_user=UserModel::getFieldsByUserId('test_account,user_id,user_no,nick_name,invite_code,is_real,is_test_user', $user['parent_id']); + if($test_user['test_account']!=$userId){ + return $this->toData('100404', 'The system is busy.', []); + } + // 生成token + $token = (new Jwt())->getToken($test_user['user_id'], env('ENCRYPT.SALT')); + if (empty($token)) { + return $this->toData('100300', 'The system is busy.', []); + } + + // 将token存致缓存 覆盖新的缓存 实现单设备登陆 + $this->setUserTokenCache($token, $test_user['user_id']); + // 删除缓存 + $this->delUserTokenCache($userId); + // 返回结果以及用户信息 + return $this->toData('0', 'Request successful.', [ + 'userId' => $test_user['user_id'], + 'userNo' => $test_user['user_no'], + 'nickName' => $test_user['nick_name'], + 'inviteCode' => $test_user['invite_code'], + 'isReal' => $test_user['is_real'], + 'is_test_user' => $test_user['is_test_user'], + 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), + 'token' => $token, + ]); + } +} diff --git a/app/home/service/UserService.php.backup b/app/home/service/UserService.php.backup new file mode 100644 index 0000000..979357a --- /dev/null +++ b/app/home/service/UserService.php.backup @@ -0,0 +1,1330 @@ +createUserLevel($user_id, $parent_id); + (new TeamService())->regBrokerage($data['parent_id'], $data['grandpa_id'], $data['top_id']); + } + $this->initUserWallet($user_id); + } + + /** + * 处理用户等级关系 + * @param int $user_id + * @param int $parent_id + * @return bool + */ + private function createUserLevel(int $user_id, int $parent_id) + { + //插入用户等级关系 + if ($parent_id > 0) { + $parent_info = UserLevelModel::getUserLevelById($parent_id); + $grandpa_id = $parent_info['parent_id']; + $top_id = $parent_info['grandpa_id']; + } else { + $grandpa_id = 0; + $top_id = 0; + } + $data['user_id'] = $user_id; + $data['parent_id'] = $parent_id; + $data['grandpa_id'] = $grandpa_id; + $data['top_id'] = $top_id; + UserLevelModel::InsertUserLevel($data); + return $data; + } + + public function getUserLevel(int $user_id) + { + $level_info = UserLevelModel::getUserLevelById($user_id); + $this->setUserLevel($user_id, $level_info); + } + + /** + * 初始化各钱包数据 U数据 + * @param int $user_id + * @return void + */ + private function initUserWallet(int $user_id) + { + if (env('FEATURE.HAS_STOCK_US')) { + UserStockModel::InsertUserStock([ + 'user_id' => $user_id, + 'stock_id' => 'USD', + 'usable_num' => 0, + 'frozen_num' => 0, + ]); + } + if (env('FEATURE.HAS_DIGITAL')) { + UserDigitalModel::InsertUserDigital([ + 'user_id' => $user_id, + 'digital_id' => 'USDT', + 'usable_num' => 0, + 'frozen_num' => 0, + ]); + } + if (env('FEATURE.HAS_CONTRACT')) { + UserContractModel::InsertUserContract([ + 'user_id' => $user_id, + 'contract_id' => 'USDT', + 'usable_num' => 0, + 'frozen_num' => 0, + ]); + } + + } + + /** + * @desc 获取用户信息 + * @param $userId + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function getUserInfo($userId) + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first', []); + } + + $info = UserModel::getFieldsByUserId('trade_password,lever_status,gender,last_name,first_name,real_status,country_id,user_no,nick_name,email,phone_number,country_code,is_real,head_img_id,invite_code', $userId); + if (empty($info)) { + return $this->toData('100400', 'The user does not exist.', []); + } + + // 获取国家名称 + $countryId = $info['country_id']; + + $countryName = ''; + if ($countryId > 0) { + $countryName = CountryModel::getNameById($countryId); + } + + // 获取头像 + $headPath = env('USER.DEFAULT_HEAD_IMG_PATH'); + if ($info['head_img_id'] > 0) { + $headPath = FileModel::getFilePath($info['head_img_id']); + } + + $key = 'LEVERAGE:' . $userId; + $leverageNum = Cache::store('redis')->get($key); + if (empty($leverageNum)) { + $key = 'LEVERAGE:0'; + $leverageNum = Cache::store('redis')->get($key); + } + $leverageNum= empty($leverageNum) ? 1: $leverageNum; + + // 返回数据 + return $this->toData('0', 'Modification successful.', [ + 'logo' => $headPath, + 'userId' => $userId, + 'userNo' => $info['user_no'], + 'nickName' => $info['nick_name'], + 'nation' => $info['country_code'], + 'phone' => $info['phone_number'], + 'email' => $info['email'], + 'isReal' => $info['is_real'], + 'real_status' => $info['real_status'], + 'inviteCode' => $info['invite_code'], + 'firstName' => $info['first_name'], + 'lastName' => $info['last_name'], + 'gender' => (string)$info['gender'], + 'isSetPayPassword' => $info['trade_password'] ? '1' : '0', + 'country' => $countryName, + 'countryId' => $countryId, + 'lever_status' => $info['lever_status'], + 'leverage_num' =>$leverageNum + ]); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * @desc 设置用户国家 + * @param $userId + * @param $param + * @return array + */ + public function setCountry($userId, $param): array + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + // 邮件注册参数校验 + validate(UserValidate::class)->scene('setCountry')->check($param); + $countryId = $param['country_id']; + + // 国家是否存在 + $country = CountryModel::getById($countryId); + if (empty($country)) { + return $this->toData('100400', 'Unsupported country or region.', []); + } + + // 是否是黑名单国家 + if ($this->checkForbidNation($country['code'])) { + return $this->toData('100400', 'Unsupported country or region.', []); + } + + // 设置 + UserModel::updateFieldsByUserId(['country_id' => $country['id']], $userId); + return $this->toData('0', 'Modification successful.'); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('100400', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * @desc 更新用户头像 + * @param $userId + * @param $param + * @return array + */ + public function updateHeadImg($userId, $param): array + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('updateHeadImg')->check($param); + $fileId = $param['file_id']; + + // 文件是否存在 + $file = FileModel::getById($fileId); + if (empty($file)) { + return $this->toData('100400', 'The file does not exist.', []); + } + + + // 设置 + UserModel::updateFieldsByUserId(['head_img_id' => $fileId], $userId); + return $this->toData('0', 'Modification successful.'); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('100400', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', []); + } + } + + /** + * @desc 设置用户 昵称 性别 名字信息 + * @param $userId + * @param $param + * @return array + */ + public function updateInfo($userId, $param): array + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('updateInfo')->check($param); + + // 查找用户信息 + $user = UserModel::getFieldsByUserId('user_id,nick_name,first_name,first_name,gender', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + $nickName = $param['nick_name']; + $gender = $param['gender']; + $lastName = $param['last_name'] ?? $user['last_name']; + $first_name = $param['first_name'] ?? $user['first_name']; + + UserModel::updateFieldsByUserId([ + 'nick_name' => $nickName, + 'first_name' => $first_name, + 'last_name' => $lastName, + 'gender' => $gender, + ], $userId); + + // 返回 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 登陆状态下发送短信 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function sendEmail($userId, $param) + { + try { + $ip = $this->getClientRealIp(); + + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('sendEmail')->check($param); + + // 如果是非交易业务 需要判断验证码获取次数 + $key = 'USER:SEND_CODE_NUM:' . $ip; + if ($param['business'] == '1') { + if ($this->checkGetNoTradeCodeNum($key)) { + return $this->toData('100300', 'No worries. Please feel free to reach out again tomorrow.', []); + } + } + + // 提取参数 + $emailType = $param['email_type']; // 1 给已经绑定的邮箱发 2 给新邮箱发 + $email = $param['email'] ?? ''; + if ($emailType == 1) { + $email = UserModel::getEmailById($userId); + if (empty($email)) { + return $this->toData('100400', '邮箱未绑定', []); + } + } + + // 获取邮件内容 + $content = $this->getEmailContent(); + $content['email'] = $email; + $code = $content['code']; + Queue::push('app\home\job\SendEmail', $content, 'sendEmail'); + + // 设置缓存 + $sendEmailCacheKey = 'USER:sendEmailLoginTrade:' . $email; + if ($param['business'] == '1') { + $sendEmailCacheKey = 'USER:sendEmailLoginNoTrade:' . $email; + // 累加ip获取的次数 + $this->updateHadGetCodeNumCache($key); + } + + $this->insertCodeToCache($sendEmailCacheKey, $code, 300); + + // 返回结果 + return $this->toData('0', 'Modification successful.'); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + /** + * @desc 登陆状态下发送短信 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function sendSms($userId, $param): array + { + try { + $ip = $this->getClientRealIp(); + + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('sendSms')->check($param); + + // 如果是非交易业务 需要判断验证码获取次数 + $key = 'USER:SEND_CODE_NUM:' . $ip; + if ($param['business'] == '1') { + if ($this->checkGetNoTradeCodeNum($key)) { + return $this->toData('100300', 'No worries. Please feel free to reach out again tomorrow.', []); + } + } + + // 提取参数 + $phoneType = $param['phone_type']; // 1 给已经绑定的手机发 2 给新手机发 + $phone = $param['phone'] ?? ''; + $nation = $param['nation'] ?? ''; + if ($phoneType == 1) { + $user = UserModel::getFieldsByUserId('country_code,phone_number', $userId); + if (empty($user)) { + return $this->toData('100400', 'The phone number is not linked/bound.', []); + } + $phone = $user['phone_number']; + $nation = $user['country_code']; + } else { + // 如果给新手机发 判断国家码是否存在 + $nationCheck = CountryModel::checkCodeExists($nation); + if (!$nationCheck) { + return $this->toData('100400', 'Unsupported country or region.', []); + } + } + + $mobile = $nation . $phone; + + // 获取邮件内容 + $content = $this->getSmsContent(1); + $content['mobile'] = $mobile; + $code = $content['code']; + Queue::push('app\home\job\SendSms', $content, 'sendSms'); + + // 设置缓存 + $sendCodeKey = 'USER:sendSmsLoginTrade:' . $mobile; + + if ($param['business'] == '1') { + $sendCodeKey = 'USER:sendSmsLoginNoTrade:' . $mobile; + // 累加已经获取的次数 + $this->updateHadGetCodeNumCache($key); + } + $this->insertCodeToCache($sendCodeKey, $code, 300); + + + // 返回结果 + return $this->toData('0', 'Modification successful.'); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + public function setPayPasswordByEmail($userId, $param) + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code pay_password + validate(UserValidate::class)->scene('setPayPasswordByEmail')->check($param); + + // 获取用户 + $user = UserModel::getFieldsByUserId('email,user_id,trade_password', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + +// // 校验验证码 +// $key = 'USER:sendEmailLoginNoTrade:'.$user['email']; +// $emailCache = Cache::store('redis')->get($key); +// if(empty($param['email_code']) || $emailCache != $param['email_code']){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 如果已经存在交易密码 则不能设置 + if (!empty($user['trade_password'])) { + return $this->toData('100400', 'The payment password has already been set.', []); + } + + // 加密密码 + $payPassword = $param['pay_password']; + $salt = env('ENCRYPT.SALT'); + $payPassword = (new UnqId())->encryptPassword($payPassword, $salt); + + // 设置密码 + UserModel::setPayPassword($payPassword, $salt, $userId); + + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', []); + } + } + + /** + * @desc 通过短信设置取款密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function setPayPasswordBySms($userId, $param) + { + try { + // 主键 + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 nation phone pay_password + validate(UserValidate::class)->scene('setPayPasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('country_code,phone_number,user_id,trade_password', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + if (!empty($user['trade_password'])) { + return $this->toData('100400', 'The payment password has already been set.', []); + } + +// // 校验验证码 +// $mobile = $user['country_code'].$user['phone_number']; +// $key = 'USER:sendSmsLoginNoTrade:'.$mobile; +// if(Cache::store('redis')->get($key) != $param['sms_code']){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验验证码 + $payPassword = $param['pay_password']; + $salt = env('ENCRYPT.SALT'); + $payPassword = (new UnqId())->encryptPassword($payPassword, $salt); + + + // 设置密码 + UserModel::setPayPassword($payPassword, $salt, $userId); + + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 通过手机号修改交易密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updatePayPasswordBySms($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('updatePayPasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,trade_password,salt,phone_number,country_code', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $nation = $user['country_code']; +// $phone = $user['phone_number']; +// $smsCode = $param['sms_code']; + $payPassword = $param['pay_password']; + $payPasswordNew = $param['pay_password_new']; + + // 校验验证码 +// $mobile = $nation.$phone; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验旧密码 + $checkPasswordBool = (new UnqId())->checkPassword($payPassword, $user['trade_password'], $user['salt']); + if (!$checkPasswordBool) { + return $this->toData('100400', 'Incorrect password.'); + } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($payPasswordNew, $user['salt']); + UserModel::updateFieldsByUserId(['trade_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 根据邮箱修改交易密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updatePayPasswordByEmail($userId, $param) + { + // 通过 邮箱 收款密码 重新设置收款密码 + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('updatePayPasswordByEmail')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,trade_password,salt,email', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $email = $user['email']; +// $emailCode = $param['email_code']; + $payPassword = $param['pay_password']; + $payPasswordNew = $param['pay_password_new']; + + // 校验验证码 +// $cacheEmailKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheEmailCode = Cache::store('redis')->get($cacheEmailKey); +// if(empty($emailCode) || $emailCode != $cacheEmailCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验旧密码 + $checkPasswordBool = (new UnqId())->checkPassword($payPassword, $user['trade_password'], $user['salt']); + if (!$checkPasswordBool) { + return $this->toData('100400', 'Incorrect password.', []); + } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($payPasswordNew, $user['salt']); + UserModel::updateFieldsByUserId(['trade_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 根据短信重新设置交易密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function resetPayPasswordBySms($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('resetPayPasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,salt,phone_number,country_code', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $nation = $user['country_code']; +// $phone = $user['phone_number']; +// $smsCode = $param['sms_code']; + $payPasswordNew = $param['pay_password_new']; + + // 校验验证码 +// $mobile = $nation.$phone; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($payPasswordNew, $user['salt']); + UserModel::updateFieldsByUserId(['trade_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 通过邮箱重新设置交易密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function resetPayPasswordByEmail($userId, $param) + { + // 通过邮箱验证码 新密码 设置交易密码 + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('resetPayPasswordByEmail')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,salt,email', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $email = $user['email']; +// $emailCode = $param['email_code']; + $payPasswordNew = $param['pay_password_new']; + + // 校验验证码 +// $cacheEmailKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheEmailCode = Cache::store('redis')->get($cacheEmailKey); +// if(empty($emailCode) || $emailCode != $cacheEmailCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($payPasswordNew, $user['salt']); + UserModel::updateFieldsByUserId(['trade_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + public function updatePasswordBySms($userId, $param) + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('updatePasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,login_password,salt,phone_number,country_code', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $nation = $user['country_code']; +// $phone = $user['phone_number']; +// $smsCode = $param['sms_code']; + $password = $param['password']; + $passwordNew = $param['password_new']; + + // 校验验证码 +// $mobile = $nation.$phone; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验旧密码 + $checkPasswordBool = (new UnqId())->checkPassword($password, $user['login_password'], $user['salt']); + if (!$checkPasswordBool) { + return $this->toData('100400', 'Incorrect password.', []); + } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($passwordNew, $user['salt']); + UserModel::updateFieldsByUserId(['login_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 邮箱修改登陆密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updatePasswordByEmail($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 + validate(UserValidate::class)->scene('updatePasswordByEmail')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,login_password,salt,email', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $email = $user['email']; +// $emailCode = $param['email_code']; + $password = $param['password']; + $passwordNew = $param['password_new']; + + // 校验验证码 +// $cacheEmailKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheEmailCode = Cache::store('redis')->get($cacheEmailKey); +// if(empty($emailCode) || $emailCode != $cacheEmailCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 校验旧密码 + $checkPasswordBool = (new UnqId())->checkPassword($password, $user['login_password'], $user['salt']); + if (!$checkPasswordBool) { + return $this->toData('100400', 'Incorrect password.', []); + } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($passwordNew, $user['salt']); + UserModel::updateFieldsByUserId(['login_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 短信重新设置登陆密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function resetPasswordBySms($userId, $param) + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('resetPasswordBySms')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,salt,phone_number,country_code', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $nation = $user['country_code']; +// $phone = $user['phone_number']; +// $smsCode = $param['sms_code']; + $passwordNew = $param['password_new']; + + // 校验验证码 +// $mobile = $nation.$phone; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($passwordNew, $user['salt']); + UserModel::updateFieldsByUserId(['login_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 邮箱重新设置登陆密码 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function resetPasswordByEmail($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('resetPasswordByEmail')->check($param); + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,salt,email', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 提取参数 +// $email = $user['email']; +// $emailCode = $param['email_code']; + $passwordNew = $param['password_new']; + + // 校验验证码 +// $cacheEmailKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheEmailCode = Cache::store('redis')->get($cacheEmailKey); +// if(empty($emailCode) || $emailCode != $cacheEmailCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 设置密码 + $newPassword = (new UnqId())->encryptPassword($passwordNew, $user['salt']); + UserModel::updateFieldsByUserId(['login_password' => $newPassword], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + public function bindEmail($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 email_code email + validate(UserValidate::class)->scene('bindEmail')->check($param); + + // 判断验证码 +// $emailCode = $param['email_code']; + $email = $param['email']; +// $cacheCodeKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheSmsCode = Cache::store('redis')->get($cacheCodeKey); +// if(empty($emailCode) || $emailCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('email,user_id', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 判读是否已经绑定 + if (!empty($user['email'])) { + return $this->toData('100400', 'You have already bound your email', []); + } + + //判断手机号是否已经被别人绑定 + $emailExits = UserModel::checkEmailExists($email); + if ($emailExits) { + return $this->toData('100400', 'The email has been bound', []); + } + + // 执行入库操作 + UserModel::updateFieldsByUserId(['email' => $email], $userId); + + // 返回结果 + return $this->toData('0', 'Binding successful', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + /** + * @desc 修改已经绑定的手机号 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updateEmail($userId, $param): array + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 nation phone sms_code + validate(UserValidate::class)->scene('updateEmail')->check($param); + + // 判断验证码 +// $emailCode = $param['email_code']; + $email = $param['email']; +// $cacheCodeKey = 'USER:sendEmailLoginNoTrade:'.$email; +// $cacheSmsCode = Cache::store('redis')->get($cacheCodeKey); +// if(empty($emailCode) || $emailCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('login_password,email,user_id,salt', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 判读是否已经绑定 需要已经绑定 + if (empty($user['email'])) { + return $this->toData('100400', 'Email is not linked/bound.', []); + } + + //校验登陆密码 + $passwordCheck = (new UnqId())->checkPassword($param['password'], $user['login_password'], $user['salt']); + if (!$passwordCheck) { + return $this->toData('100400', 'Incorrect password.', []); + } + + //判断手机号是否已经被别人绑定 + $emailExits = UserModel::checkEmailExists($email); + if ($emailExits) { + return $this->toData('100400', 'The email has already been linked/bound.', []); + } + + // 执行入库操作 + UserModel::updateFieldsByUserId(['email' => $email], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + + public function bindPhone($userId, $param) + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 nation phone sms_code + validate(UserValidate::class)->scene('bindPhone')->check($param); + + // 判断验证码 +// $smsCode = $param['sms_code']; +// $mobile = $param['nation'].$param['phone']; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('user_id,country_code,phone_number', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 判读是否已经绑定 + if (!empty($user['phone_number'])) { + return $this->toData('100400', 'The phone number has already been linked/bound.', []); + } + + //判断手机号是否已经被别人绑定 + $phoneExits = UserModel::checkPhoneExists($param['phone']); + if ($phoneExits) { + return $this->toData('100400', 'The phone number has already been linked/bound.', []); + } + + // 判断国家码是否存在 + $codeExists = CountryModel::checkCodeExists($param['nation']); + if (!$codeExists) { + return $this->toData('100400', 'Unsupported country or region.', []); + } + + // 执行入库操作 + UserModel::updateFieldsByUserId(['phone_number' => $param['phone'], 'country_code' => $param['nation']], $userId); + + // 返回结果 + return $this->toData('0', 'Binding successful.', []); + + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + /** + * @desc 修改已经绑定的手机号 + * @param $userId + * @param $param + * @return array + * @throws \Psr\SimpleCache\InvalidArgumentException + */ + public function updatePhone($userId, $param): array + { + try { + // user_id + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 参数校验 nation phone sms_code + validate(UserValidate::class)->scene('updatePhone')->check($param); + + // 判断验证码 +// $smsCode = $param['sms_code']; +// $mobile = $param['nation'].$param['phone']; +// $cacheSmsKey = 'USER:sendSmsLoginNoTrade:'.$mobile; +// $cacheSmsCode = Cache::store('redis')->get($cacheSmsKey); +// if(empty($smsCode) || $smsCode != $cacheSmsCode){ +// return $this->toData('100400', 'The verification code is incorrect.', []); +// } + + // 判断国家码是否存在 + $codeExists = CountryModel::checkCodeExists($param['nation']); + if (!$codeExists) { + return $this->toData('100400', 'Unsupported country or region', []); + } + + //判断手机号是否已经被别人绑定 + $phoneExits = UserModel::checkPhoneExists($param['phone']); + if ($phoneExits) { + return $this->toData('100400', 'The phone number has already been linked/bound.', []); + } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('salt,login_password,user_id,country_code,phone_number', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 判读是否已经绑定 需要已经绑定手机 + if (empty($user['phone_number'])) { + return $this->toData('100400', 'The phone number is not linked/bound.', []); + } + + //校验登陆密码 + $passwordCheck = (new UnqId())->checkPassword($param['password'], $user['login_password'], $user['salt']); + if (!$passwordCheck) { + return $this->toData('100400', 'Incorrect password.', []); + } + + // 执行入库操作 + UserModel::updateFieldsByUserId(['phone_number' => $param['phone'], 'country_code' => $param['nation']], $userId); + + // 返回结果 + return $this->toData('0', 'Modification successful.', []); + } catch (ValidateException $validateException) { + // 参数校验失败 异常类 + $message = $validateException->getError(); + return $this->toData('100400', $message); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + } + + /** + * @desc 退出登陆 + * @param $userId + * @return array + */ + public function logout($userId) + { + try { + // 删除缓存 + $this->delUserTokenCache($userId); + return $this->toData('0', 'Modification successful.'); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', [$exception->getMessage()]); + } + + } + + /** + * @desc 获取用户登陆信息 + * @param $userId + * @return array + */ + public function loginLog($userId): array + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + $data = UserLoginLog::getLog($userId); + if (empty($data)) { + return $this->toData('0', 'Modification successful.', []); + } + + $res = []; + foreach ($data as $item) { + $countryCn = ''; + $countryEn = ''; + $cityCn = ''; + $cityEn = ''; + if (!empty($item['country'])) { + $countryArr = json_decode($item['country'], true); + $countryCn = $countryArr['cn']; + $countryEn = $countryArr['en']; + } + + if (!empty($item['city'])) { + $cityArr = json_decode($item['city'], true); + $cityCn = $cityArr['cn']; + $cityEn = $cityArr['en']; + } + + $res[] = [ + 'device' => $item['device'], + 'ip' => $item['ip'], + 'countryCn' => $countryCn, + 'countryEn' => $countryEn, + 'cityCn' => $cityCn, + 'cityEn' => $cityEn, + 'loginDate' => $item['login_date'], + ]; + } + + return $this->toData('0', 'Modification successful.', $res); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', []); + } + } + + /** + * 用户申请使用杠杆 + * @param $userId + * @return array + */ + public function leverApply($userId) + { + try { + if (empty($userId) || $userId <= 0) { + return $this->toData('100403', 'Please log in first.', []); + } + + // 获取用户信息 + $user = UserModel::getFieldsByUserId('lever_status,user_id', $userId); + if (empty($user)) { + return $this->toData('100403', 'Please log in first.', []); + } + + if (in_array($user['lever_status'], [UserModel::LEVER_STATUS_NO, UserModel::LEVER_STATUS_FAIL])) { + UserModel::update(['lever_status' => UserModel::LEVER_STATUS_APPLY, 'update_time' => date('Y-m-d H:i:s')], ['user_id' => $userId]); + return $this->toData('0', 'success.', []); + } + + return $this->toData('0', 'Already submitted.', []); + + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy.', []); + } + } +} diff --git a/app/home/service/UserVerifyService.php b/app/home/service/UserVerifyService.php new file mode 100644 index 0000000..88668bd --- /dev/null +++ b/app/home/service/UserVerifyService.php @@ -0,0 +1,133 @@ +toData('100400','Invalid name'); + } + + if(empty($params['code']) || !is_string($params['code'])){ + return $this->toData('100400','Invalid ID number'); + } + + if(empty($params['country']) || !is_numeric($params['country'])){ + return $this->toData('100400','Invalid country'); + } + + if(empty($params['front_img']) || !is_numeric($params['front_img'])){ + return $this->toData('100400','Invalid front_img'); + } + + if(empty($params['back_img']) || !is_numeric($params['back_img'])){ + //return $this->toData('100400','Invalid back_img'); + } + + // 判断用户状态 + $user = UserModel::where('user_id', $userId)->find(); + if(empty($user)){ + return $this->toData('100400','param error'); + } + + // 判断是是否已经认证 + if($user->is_real == 1){ + return $this->toData('100400','Already real-name authenticated'); + } + + // 是否是未认证或者认证失败状态 + if($user->real_status == 2 || $user->real_status == 3){ + return $this->toData('100400','status error'); + } + + $country = CountryModel::where('id',$params['country'])->find(); + if(empty($country)){ + return $this->toData('100400','country error'); + } + + // 图片记录 + $front = FileModel::where('id',$params['front_img'])->find(); + if(empty($front)){ + return $this->toData('100400','front_img error'); + } + + $back = FileModel::where('id',$params['back_img'])->find(); + if(empty($back)){ + //return $this->toData('100400','back_img error'); + } + + //锁屏密码 + $lockPassword = ''; + if (!empty($params['lock_password'])) { + $lockPassword = $params['lock_password']; +// $salt = env('ENCRYPT.SALT'); +// $enLockPassword = (new UnqId())->encryptPassword($lockPassword, $salt); + } + + + // 写入数据库 + $userVerify = new UserVerifyLogModel; + $userVerify->user_id = $userId; + $userVerify->country = $params['country']; + $userVerify->code = $params['code']; + $userVerify->name = $params['name']; + $userVerify->front_img = $params['front_img']; + $userVerify->back_img = isset($params['back_img']) ? $params['back_img'] :''; + if (!empty($lockPassword)) $userVerify->lock_password = $lockPassword; + $userVerify->create_time = date('Y-m-d H:i:s'); + $userVerify->update_time = date('Y-m-d H:i:s'); + $userVerify->save(); + + // 更改用户状态 + $user->real_status = 2; + $user->save(); + + return $this->toData('0','SUCCESS'); + + }catch (\Exception $exception){ + return $this->toData('100500','The system is busy.'); + } + } + + public function detail($userId) + { + try { + $user = UserModel::where('user_id', $userId)->find(); + if(empty($user)){ + return $this->toData('100400','param error'); + } + + $log = UserVerifyLogModel::where('user_id', $userId)->order('id', 'desc')->find(); + + $data = []; + if(!empty($log)){ + $front = FileModel::where('id', $log->front_img)->value('path'); + $back = FileModel::where('id', $log->back_img)->value('path'); + $country = CountryModel::where('id', $log->country)->find(); + $data = [ + 'name' => $log->name, + 'code' => $log->code, + 'country_data' => $country, + 'front_img' => $front, + 'back_img' => $back, + 'status' => $log->status, + ]; + } + + return $this->toData('0', 'SUCCESS', $data); + }catch (\Exception $exception){ + return $this->toData('100500','The system is busy.'); + } + } +} \ No newline at end of file diff --git a/app/home/service/WalletService.php b/app/home/service/WalletService.php new file mode 100644 index 0000000..293b997 --- /dev/null +++ b/app/home/service/WalletService.php @@ -0,0 +1,1969 @@ +getOldUserAssets($user_id,$account_type); + } + + return $this->toData(0, 'Request successful.', $result); + } + protected function getOldUserAssets(int $user_id, int $account_type){ + switch ($account_type) { + case 1: + $result = [ + 'digital' => $this->getUserDigital([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + case 2: + $result = [ + 'contract' => $this->getUserContract([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + // 美股 + case 3: + $result = [ + 'contract' => $this->getUserUsStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + // 印尼股票 + case 4: + $result = [ + 'contract' => $this->getUserIdnStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + // 马来西亚股票 + case 5: + $result = [ + 'contract' => $this->getUserMysStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + // 泰股股票 + case 6: + $result = [ + 'contract' => $this->getUserThaStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + + case 7: + $result = [ + 'contract' => $this->getUserInStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + // 秒合约 + case 8: + $result = [ + 'contract' => $this->getUserContractSec([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + //新加坡 + case 9: + $result = [ + 'contract' => $this->getUserSgdStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + //基金 + case 10: + $result = [ + 'contract' => $this->getUserFundStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + //印度期权 + case 11: + $result = [ + 'contract' => $this->getUserInOption([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + //港股 + case 12: + $result = [ + 'contract' => $this->getUserHkStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + case 14: + $result = [ + 'contract' => $this->getUserUkStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + case 15: + $result = [ + 'contract' => $this->getUserFurStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + case 16: + $result = [ + 'contract' => $this->getUserEurStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + case 17: + $result = [ + 'contract' => $this->getUserBrlStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + case 18: + $result = [ + 'contract' => $this->getUserJpStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + case 19: + $result = [ + 'contract' => $this->getUserForex([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]) + ]; + break; + default: + $result = [ + 'digital' => $this->getUserDigital([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'contract' => $this->getUserContract([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'forex' => $this->getUserForex([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'contract_sec' => $this->getUserContractSec([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'us_stock' => $this->getUserUsStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'idn_stock' => $this->getUserIdnStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'mys_stock' => $this->getUserMysStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'tha_stock' => $this->getUserThaStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'in_stock' => $this->getUserInStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'sgd_stock' => $this->getUserSgdStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'fund_stock' => $this->getUserFundStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'option_in_stock' => $this->getUserInOption([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'hk_stock' => $this->getUserHkStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'uk_stock' => $this->getUserUkStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'fur_stock' => $this->getUserFurStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'eur_stock' => $this->getUserEurStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'brl_stock' => $this->getUserBrlStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + 'jp_stock' => $this->getUserJpStock([ + 'user_id' => $user_id, + 'account_type' => $account_type + ]), + ]; + break; + } + return $result; + } + protected function getNewUserAssets(int $user_id){ + $res=UserMoneyModel::where('user_id',$user_id)->field('usable_num,frozen_num,stock_id as name')->select(); + $result=[]; + if(!empty($res)){ + $result=$res->toArray(); + } + return $result; + } + + /** + * 获取用户现货资产 + * @param $user_id + * @param int $type 0全部资产,1只获取usdt资产 + * @return array + */ + private function getUserDigital(array $data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserDigitalModel::getUserDigitalList($data['user_id']); + } else { + return UserDigitalModel::getUserDigitalByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户合约资产 + * @param $data + * @return array + */ + private function getUserContract($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserContractModel::getUserContractList($data['user_id']); + } else { + return UserContractModel::getUserContractByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + /** + * 获取用户外汇资产 + * @param $data + * @return array + */ + private function getUserForex($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserForexModel::getUserForexList($data['user_id']); + } else { + return UserForexModel::getUserForexByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户秒合约资产 + * @param $data + * @return array + */ + private function getUserContractSec($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserContractSecModel::getUserContractList($data['user_id']); + } else { + return UserContractSecModel::getUserContractByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户美股资产 + * @param $user_id + * @return array + */ + private function getUserStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockModel::getUserStockList($data['user_id']); + } else { + return UserStockModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户美股资产 + * @param $user_id + * @return array + */ + private function getUserUsStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockModel::getUserStockList($data['user_id']); + } else { + return UserStockModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户印尼股票 资产 + * @param $user_id + * @return array + */ + private function getUserIdnStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockIdnModel::getUserStockList($data['user_id']); + } else { + return UserStockIdnModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + private function getUserSgdStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockSgdModel::getUserStockList($data['user_id']); + } else { + return UserStockSgdModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + private function getUserFundStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockFundModel::getUserStockList($data['user_id']); + } else { + return UserStockFundModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户马来西亚股票 资产 + * @param $user_id + * @return array + */ + private function getUserMysStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockMysModel::getUserStockList($data['user_id']); + } else { + return UserStockMysModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户马股股票 资产 + * @param $user_id + * @return array + */ + private function getUserThaStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockThaModel::getUserStockList($data['user_id']); + } else { + return UserStockThaModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户印度股票 资产 + * @param $user_id + * @return array + */ + private function getUserInStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockInModel::getUserStockList($data['user_id']); + } else { + return UserStockInModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户印度股票 资产 + * @param $user_id + * @return array + */ + private function getUserHkStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockHkdModel::getUserStockList($data['user_id']); + } else { + return UserStockHkdModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + /** + * 获取用户印度股票 资产 + * @param $user_id + * @return array + */ + private function getUserUkStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockGBXModel::getUserStockList($data['user_id']); + } else { + return UserStockGBXModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + private function getUserFurStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockFurModel::getUserStockList($data['user_id']); + } else { + return UserStockFurModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + private function getUserEurStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockEurModel::getUserStockList($data['user_id']); + } else { + return UserStockEurModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + private function getUserBrlStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockBrlModel::getUserStockList($data['user_id']); + } else { + return UserStockBrlModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + private function getUserJpStock($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockJpModel::getUserStockList($data['user_id']); + } else { + return UserStockJpModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户印度期权资产 + * @param $user_id + * @return array + */ + private function getUserInOption($data, int $type = 0): array + { + try { + validate(WalletValidate::class)->scene('getUserBalance')->check($data); + if ($type == 0) { + return UserStockOptionInrModel::getUserStockList($data['user_id']); + } else { + return UserStockOptionInrModel::getUserStockByUserId($data); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户充值列表 + * @param array $data + * @return array + */ + public function getUserRechargeList(array $data): array + { + try { + validate(WalletValidate::class)->scene('getDrawalList')->check($data); + $list = RechargeApplyModel::getUserRecharge($data); + return $this->toData(0, 'Request successful.', $list); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + public function getUserRechargeWallet(array $data): array + { + $list = WalletListModel::getUserWalletList([ + 'wallet_type' => $data['wallet_type'] + ]); + return $this->toData(0, 'Request successful.', $list); + } + + /** + * 用户添加钱包地址 + * @param array $data + * @return array + */ + public function insertWalletAdress(array $data): array + { + try { + validate(BankValidate::class)->scene('setWalletAddress')->check($data); + UserWalletaddressModel::InsertUserWallet($data); + return $this->toData(0, 'Request successful.'); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户钱包地址列表 + * @param array $data + * @return array + */ + public function getUserWalletAddress(array $data): array + { + try { + validate(BankValidate::class)->scene('getWalletAddressList')->check($data); + $address_list = UserWalletaddressModel::getUserWalletList($data); + return $this->toData(0, 'Request successful.', $address_list); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取用户钱包地址详情 + * @param array $data + * @param int $type + * @return array + * + */ + public function getUserWalletAddressInfo(array $data, int $type = 0): array + { + try { + validate(BankValidate::class)->scene('getWalletAddressInfo')->check($data); + $address_info = UserWalletaddressModel::getUserWalletInfoById($data); + if ($type) { + return $address_info; + } else { + return $this->toData(0, 'Request successful.', $address_info); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 删除用户钱包地址 + * @param array $data + * @return array + */ + public function delUserWalletAddress(array $data): array + { + try { + validate(BankValidate::class)->scene('getWalletAddressInfo')->check($data); + UserWalletaddressModel::delUserWalletById($data); + return $this->toData(0, 'Request successful.'); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + /** + * 添加编辑银行卡 + * @param array $data + * @return array + */ + public function insertUserBank(array $data): array + { + try { + validate(BankValidate::class)->scene('setBank')->check($data); + UserBankModel::InsertUserBank($data); + return $this->toData(0, 'Request successful.'); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取银行卡列表 + * @param array $data + * @return array + */ + public function getUserBank(array $data): array + { + try { + validate(BankValidate::class)->scene('getBankList')->check($data); + $bank_list = UserBankModel::getUserBankList($data); + return $this->toData(0, 'Request successful.', $bank_list); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 获取银行卡详情 + * @param array $data + * @return array + */ + public function getUserBankInfo(array $data, int $type = 0): array + { + try { + validate(BankValidate::class)->scene('getBankInfo')->check($data); + $bank_info = UserBankModel::getUserBankInfoById($data); + if ($type) { + return $bank_info; + } else { + return $this->toData(0, 'Request successful.', $bank_info); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 删除银行卡 + * @param array $data + * @return array + */ + public function delUserBank(array $data): array + { + try { + validate(BankValidate::class)->scene('getBankInfo')->check($data); + UserBankModel::delUserBankById($data); + return $this->toData(0, 'Request successful.'); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + /** + * 获取用户账户可用余额 + * @param array $data + * @return array + */ + public function getUserBalance(array $data): array + { + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $usdt_info = UserMoneyModel::getUserUSDByUserId($data); + }else{ + //账户类型:1现货,2合约,3美股 4 印尼股票 5 马来西呀 6 泰股 7印度股 8秒合约 9新加坡股 10基金 11印度期权 12港股 + switch ($data['account_type']) { + case 2: + $usdt_info = $this->getUserContract($data, 1); + break; + case 3: + $usdt_info = $this->getUserUsStock($data, 1); + break; + case 4: + $usdt_info = $this->getUserIdnStock($data, 1); + break; + case 5: + $usdt_info = $this->getUserMysStock($data, 1); + break; + case 6: + $usdt_info = $this->getUserThaStock($data, 1); + break; + case 7: + $usdt_info = $this->getUserInStock($data, 1); + break; + case 8: + $usdt_info = $this->getUserContractSec($data, 1); + break; + case 9: + $usdt_info = $this->getUserSgdStock($data, 1); + break; + case 10: + $usdt_info = $this->getUserFundStock($data, 1); + break; + case 11: + $usdt_info = $this->getUserInOption($data, 1); + break; + case 12: + $usdt_info = $this->getUserHkStock($data, 1); + break; + case 14: + $usdt_info = $this->getUserUkStock($data, 1); + break; + case 15: + $usdt_info = $this->getUserFurStock($data, 1); + break; + case 16: + $usdt_info = $this->getUserEurStock($data, 1); + break; + case 17: + $usdt_info = $this->getUserBrlStock($data, 1); + break; + case 18: + $usdt_info = $this->getUserJpStock($data, 1); + break; + case 19: + $usdt_info = $this->getUserForex($data, 1); + break; + default: + $usdt_info = $this->getUserDigital($data, 1); + break; + } + } + + return $this->toData(0, "ok", $usdt_info); + } + + /** + * 获取手续费用 + * @return array + */ + public function getDrawalFee(int $account_type = 0): array + { + $fee_info = DrawalSettingModel::getDrawalFee(); + $info = FeeSettingModel::where('market_type', $account_type)->field('min_withdrawal_num,min_recharge_num')->find(); + if(!empty($info)){ + $info =$info->toArray(); + $fee_info['min_drawal']=$info['min_withdrawal_num']>0 ? $info['min_withdrawal_num']: $fee_info['min_drawal']; + $fee_info['min_recharge']=$info['min_recharge_num']>0 ? $info['min_recharge_num']: $fee_info['min_recharge']; + } + return $this->toData(0, "ok",$fee_info); + } + + /** + * 处理提款;处理流程: 1.提交提款申请 ->检查余额->将可用余额扣除提款金额及手续费,转入冻结余额 + * @param array $data + * @return array + */ + public function dealDrawalApply(array $data): array + { + //判断账号是否冻结 + $isFrozen = AccountFrozenModel::where('user_id', $data['user_id'])->find(); + if (!empty($isFrozen) && $isFrozen->frozen_withdraw == 1) { + return $this->toData('100110', 'The current account has been frozen', []); + } + //校验交易密码 + $salt = env('ENCRYPT.SALT'); + $name = env('WALLET.NAME'); + $user_info = UserModel::getFieldsByUserId('trade_password,is_real', $data['user_id']); + if (empty($user_info['trade_password'])) { + return $this->toData(3, "Please set a transaction password first."); + } + if ($user_info['is_real'] == 0 && $name == 'STOCK') { + return $this->toData('20150', 'Please authenticate with real name first', []); + } + $check_pwd = (new UnqId())->checkPassword($data['trade_pwd'], $user_info['trade_password'], $salt); + if (!$check_pwd) { + return $this->toData(2, "Transaction password is incorrect."); + } + $flag = $this->checkOnlyOneNotEmpty($data['bank_id'], $data['address_id'], $data['wallet_address']); + if ($flag) { + //手续费 + $fee = $this->getUserDrawalFee($data['apply_num'], $data['drawal_type']); + $pay_info = []; + if ($data['bank_id'] > 0) { + $pay_info = $this->getUserBankInfo(['user_id' => $data['user_id'], 'id' => $data['bank_id']], 1); + } + if ($data['address_id'] > 0) { + $pay_info = $this->getUserWalletAddressInfo(['user_id' => $data['user_id'], 'adr_id' => $data['address_id']], 1); + } + if (!empty($data['wallet_address'])) { + $pay_info['wallet_address'] = $data['wallet_address']; + } + if (empty($pay_info)) { + return $this->toData(1, 'The withdrawal information is incorrect.'); + } + if ($data['account_type'] > 2 && ($data['account_type'] != 8)) { + $market_rate = (new StockMarketModel())->getRate($data['account_type']); + } else { + $market_rate = 1; + } + //提现金额 + $apply_num = ($data['apply_num'] - $fee); + + $apply_usd_num = round($apply_num / $market_rate, 4); + + //印尼通道 + $currency_rate = (new StockMarketModel())->getRate(4); + + //扣手续费 + $total_amount = round($apply_usd_num * $currency_rate, 4); + + //事务开启, 查询用户资金 + Db::startTrans(); + try { + //查询提现资金账户信息 + $from_account = $this->lockUserBalance($data['account_type'], $data['user_id']); + if (empty($from_account)) Db::rollback(); + //换算汇率 + //$change_num=$apply_num*$market_rate; + $change_num = $apply_num; + $cha_num = bcsub($from_account['usable_num'], $data['apply_num'], 18); //$from_account['usable_num']-$data['apply_num']; + if ($cha_num < 0) { + Db::rollback(); + return $this->toData(1, 'Insufficient balance.'); + } + + //插入提款记录表 + $drawal_data['user_id'] = $data['user_id']; + $drawal_data['order_no'] = $this->generateOrderNumber(20); + $drawal_data['account_type'] = $data['account_type']; + $drawal_data['apply_type'] = $data['apply_type']; + $drawal_data['apply_num'] = $apply_usd_num; + $drawal_data['service_fee'] = $fee; + $drawal_data['currency_rate'] = $currency_rate; + $drawal_data['pay_info'] = json_encode($pay_info); + $drawal_data['status'] = 0; + $drawal_data['country'] = $data['country']; + $drawal_data['drawal_type'] = $data['drawal_type']; + $drawal_data['market_amount'] = $data['apply_num']; + $drawal_data['total_amount'] = $apply_num; + UserWithdrawalModel::InsertUserDrawalLog($drawal_data); + + //扣除用户资金 + $from_update['usable_num'] = $cha_num;//round($cha_num,4); + $from_update['frozen_num'] = bcadd($from_account['frozen_num'], $data['apply_num'], 18);// round(($from_account['frozen_num']+$data['apply_num']),4); + $res = $this->updateUserBalance($data['account_type'], $from_update, $data['user_id']); + if (empty($res)) Db::rollback(); + + $log_data['user_id'] = $data['user_id']; + $log_data['change_type'] = 5; //冻结 + $log_data['change_num'] = -$data['apply_num']; + $log_data['before_num'] = $from_account['usable_num']; + $log_data['order_id'] = $drawal_data['order_no']; + $res = $this->addUserBalanceLog($data['account_type'], $log_data); + if (empty($res)) Db::rollback(); + Db::commit(); + return $this->toData(0, 'Request successful.'); + } catch (\Exception $exception) { + // 回滚事务 + Db::rollback(); + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + + } else { + return $this->toData(1, "Please fill in the parameters according to the requirements."); + } + + } + public function canncelDrawalApply(array $data): array + { + $order_info = UserWithdrawalModel::getUserDrawalInfo($data); + if ($order_info['status'] == 0) { + $obj = new AdminBaseService(); + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $updateStatus = $obj->updateUserAssetNew($order_info['user_id'], 6, $order_info['market_amount'], -$order_info['market_amount'], $order_info['order_no']); + }else{ + $updateStatus = $obj->updateUserAsset($order_info['user_id'], $order_info['account_type'], 6, $order_info['market_amount'], -$order_info['market_amount'], $order_info['order_no']); + } + + if (!empty($updateStatus) && $updateStatus['status'] == 200) { + UserWithdrawalModel::where($data)->update([ + 'status' => 5, + 'update_time' => date('Y-m-d H:i:s') + ]); + return $this->toData(0, 'Request successful.'); + }else{ + return $this->toData(500, "System error."); + } + } else { + return $this->toData(300, "Withdrawal orders cannot be cancelled."); + } + } + private function checkOnlyOneNotEmpty($value1, $value2, $value3): bool + { + $count = 0; // 用于计数非空值的个数 + if (!empty($value1)) { + $count++; + } + if (!empty($value2)) { + $count++; + } + if (!empty($value3)) { + $count++; + } + // 如果非空值的个数等于1,则返回 true,否则返回 false + return $count == 1; + } + + public function getDrawalList(array $data): array + { + try { + validate(WalletValidate::class)->scene('getDrawalList')->check($data); + $list = UserWithdrawalModel::getUserDrawalList($data); + return $this->toData(0, 'Request successful.', $list); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + + /** + * 计算用户提现手续费用 + * @param $money + * @param $type 1数字币,2银行卡 + * @return float|int|mixed + */ + private function getUserDrawalFee($money, $type = 0) + { + $fee_info = DrawalSettingModel::getDrawalFee(); + if ($type == 2) { + return $fee_info['bank_drawal_fee'] * $money; + } else { + return $fee_info['digital_drawal_fee']; + } + } + + public function getUserBalanceRecord(array $data): array + { + $record_list = []; + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $record_list=UserMoneyLogModel::getUserBalanceLog($data); + }else{ + //账户类型:1现货,2合约,3美股 + switch ($data['account_type']) { + case 1: + $record_list = UserDigitalLogModel::getUserBalanceLog($data); + break; + case 2: + $record_list = UserContractLogModel::getUserBalanceLog($data); + break; + case 3: + $record_list = UserStockLogModel::getUserBalanceLog($data); + break; + case 4: + // 印尼股票 + $record_list = UserStockIdnLogModel::getUserBalanceLog($data); + break; + case 5: + // 马来股票 + $record_list = UserStockMysLogModel::getUserBalanceLog($data); + break; + case 6: + // 泰国股票 + $record_list = UserStockThaLogModel::getUserBalanceLog($data); + break; + case 7: + // 印度股票 + $record_list = UserStockInLogModel::getUserBalanceLog($data); + break; + case 8: + // 秒合约 + $record_list = UserContractSecLogModel::getUserBalanceLog($data); + break; + case 9: + // 新加坡 + $record_list = UserStockSgdLogModel::getUserBalanceLog($data); + break; + case 10: + // 基金 + $record_list = UserStockFundLogModel::getUserBalanceLog($data); + break; + case 11: + // 印度期权 + $record_list = UserStockOptionInrLogModel::getUserBalanceLog($data); + break; + case 12: + // 香港 + $record_list = UserStockHkdLogModel::getUserBalanceLog($data); + break; + case 14: + // 德国 + $record_list = UserStockGBXLogModel::getUserBalanceLog($data); + break; + case 15: + // 法国 + $record_list = UserStockFurLogModel::getUserBalanceLog($data); + break; + case 16: + // 英国 + $record_list = UserStockEurLogModel::getUserBalanceLog($data); + break; + case 17: + // 巴西 + $record_list = UserStockBrlLogModel::getUserBalanceLog($data); + break; + case 18: + // 巴西 + $record_list = UserStockJpLogModel::getUserBalanceLog($data); + break; + case 19: + // 巴西 + $record_list =UserForexLogModel::getUserBalanceLog($data); + break; + default: + return $this->toData(1, "Please fill in the parameters according to the requirements."); + break; + } + } + return $this->toData(0, "ok", $record_list); + } + + /** + * 处理用户各资金账户相互划转 + * @param array $data + * @return array + */ + public function doUserTransfer(array $data): array + { + try { + validate(WalletValidate::class)->scene('transfer')->check($data); + if ($data['from_account'] == $data['to_account']) { + return $this->toData('2', 'The transfer out and transfer in accounts cannot be the same account.'); + } + //事务开启, 查询用户资金 + Db::startTrans(); + try { + //查询划转资金账户信息 + $from_account = $this->lockUserBalance($data['from_account'], $data['user_id']); + if (empty($from_account)) { + Db::rollback(); + return $this->toData('2', 'error'); + } + + //print_r($from_account); + + $cha_num = $from_account['usable_num'] - $data['change_num']; + if ($cha_num < 0) { + Db::rollback(); + return $this->toData(1, 'Insufficient balance.'); + } + + $to_num = $this->getRateToTransfer([ + 'from_account' => $data['from_account'], + 'to_account' => $data['to_account'], + 'change_num' => $data['change_num'] + ]); + + $to_num_data = $to_num['data']; + if (!isset($to_num_data['to_change_num']) || !is_numeric($to_num_data['to_change_num']) || $to_num_data['to_change_num'] <= 0) { + return $to_num; + } + + //查询转入资金账户信息 + $to_account = $this->lockUserBalance($data['to_account'], $data['user_id']); + if (empty($to_account)) { + Db::rollback(); + return $this->toData('2', 'error to_account '); + } + + + //插入账户资金划转表 + $transfer_data['user_id'] = $data['user_id']; + $transfer_data['from_account'] = $data['from_account']; + $transfer_data['to_account'] = $data['to_account']; + $transfer_data['from_num'] = $data['change_num']; // 转出数量 + $transfer_data['to_num'] = $to_num_data['to_change_num']; // 转入数量 + $transfer_data['from_account_rate'] = $to_num_data['from_usd']; // 转出费率 + $transfer_data['to_account_rate'] = $to_num_data['usd_to']; // 转入费率 + $transfer_data['status'] = 1; + $transfer_data['order_sn'] = $this->generateOrderNumber(20); + UserTransferModel::InsertUserStock($transfer_data); + + //更新划转资金账户余额 + $from_update['usable_num'] = $cha_num; + $res = $this->updateUserBalance($data['from_account'], $from_update, $data['user_id']); + if (empty($res)) { + Db::rollback(); + return $this->toData('2', 'error from_account transfer'); + } + + // 新增转入 + $to_update['usable_num'] = $to_account['usable_num'] + $to_num_data['to_change_num']; + $res = $this->updateUserBalance($data['to_account'], $to_update, $data['user_id']); + if (empty($res)) { + Db::rollback(); + return $this->toData('2', 'error to_account transfer '); + } + + //变动类型:1-充值,2-提现,3-买入,4-卖出,5-冻结,6-解冻,7账户转出,8账户转入 + //插入资金变动日志 + + $from_log['user_id'] = $data['user_id']; + $from_log['change_type'] = 7; + $from_log['change_num'] = -$data['change_num']; + $from_log['before_num'] = $from_account['usable_num']; + $from_log['order_id'] = $transfer_data['order_sn']; + $res = $this->addUserBalanceLog($data['from_account'], $from_log); + if (empty($res)) { + Db::rollback(); + return $this->toData('2', 'error from_log transfer'); + } + + + $to_log['user_id'] = $data['user_id']; + $to_log['change_type'] = 8; + $to_log['change_num'] = $to_num_data['to_change_num']; + $to_log['before_num'] = $to_account['usable_num']; + $to_log['order_id'] = $transfer_data['order_sn']; + $res = $this->addUserBalanceLog($data['to_account'], $to_log); + if (empty($res)) { + Db::rollback(); + return $this->toData('2', 'error to_log transfer'); + } + + Db::commit(); + + return $this->toData(0, 'Request successful.'); + } catch (\Exception $exception) { + // 回滚事务 + Db::rollback(); + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + + } + + public function lockUserBalance(int $account_type, int $user_id): array + { + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + return UserMoneyModel::getUserUSDLock($user_id); + }else{ + switch ($account_type) { + case 1: + return UserDigitalModel::getUserDigitalLock($user_id); + break; + case 2: + return UserContractModel::getUserContractLock($user_id); + break; + case 3: + // 美股 + return UserStockModel::getUserStockLock($user_id); + break; + case 4: + // 印尼 股 + return UserStockIdnModel::getUserStockLock($user_id); + break; + case 5: + // 马来西亚 股 + return UserStockMysModel::getUserStockLock($user_id); + break; + case 6: + // 泰 股 + return UserStockThaModel::getUserStockLock($user_id); + break; + case 7: + // 印度 股 + return UserStockInModel::getUserStockLock($user_id); + break; + case 8: + // 秒合约 + return UserContractSecModel::getUserContractLock($user_id); + break; + case 9: + // 新加坡 + return UserStockSgdModel::getUserStockLock($user_id); + break; + case 10: + // 基金 + return UserStockFundModel::getUserStockLock($user_id); + break; + case 11: + // 印度期权 + return UserStockOptionInrModel::getUserStockLock($user_id); + break; + case 12: + // 香港 + return UserStockHkdModel::getUserStockLock($user_id); + break; + case 14: + // 英国 + return UserStockGBXModel::getUserStockLock($user_id); + break; + case 15: + // 英国 + return UserStockFurModel::getUserStockLock($user_id); + break; + case 16: + // 英国 + return UserStockEurModel::getUserStockLock($user_id); + break; + case 17: + // 巴西 + return UserStockBrlModel::getUserStockLock($user_id); + break; + case 18: + // 巴西 + return UserStockJpModel::getUserStockLock($user_id); + break; + case 19: + // 巴西 + return UserForexModel::getUserForexLock($user_id); + break; + default: + return []; + break; + } + } + + } + + public function updateUserBalance(int $account_type, array $update_data, int $user_id): bool + { + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + return UserMoneyModel::updateUserUSD($update_data,[ + 'user_id' => $user_id, + 'stock_id' => 'USD' + ]); + }else{ + switch ($account_type) { + case 1: + return UserDigitalModel::updateUserDigital($update_data, [ + 'user_id' => $user_id, + 'digital_id' => 'USDT' + ]); + break; + case 2: + return UserContractModel::updateUserContract($update_data, [ + 'user_id' => $user_id, + 'contract_id' => 'USDT' + ]); + break; + case 3: + return UserStockModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'USD' + ]); + break; + case 4: + return UserStockIdnModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'IDR' + ]); + break; + case 5: + return UserStockMysModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'MYR' + ]); + break; + case 6: + return UserStockThaModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'THB' + ]); + break; + case 7: + return UserStockInModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'INR' + ]); + break; + case 8: + return UserContractSecModel::updateUserContract($update_data, [ + 'user_id' => $user_id, + 'contract_id' => 'USDT' + ]); + break; + case 9: + return UserStockSgdModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'SGD' + ]); + break; + case 10: + return UserStockFundModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'USD' + ]); + break; + case 11: + return UserStockOptionInrModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'INR' + ]); + break; + case 12: + return UserStockHkdModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'HKD' + ]); + break; + case 14: + return UserStockGBXModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'GBX' + ]); + break; + case 15: + return UserStockFurModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'EUR' + ]); + break; + case 16: + return UserStockEurModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'EUR' + ]); + break; + case 17: + return UserStockBrlModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'BRL' + ]); + break; + case 18: + return UserStockJpModel::updateUserStock($update_data, [ + 'user_id' => $user_id, + 'stock_id' => 'JPY' + ]); + break; + case 19: + return UserForexModel::updateUserForex($update_data, [ + 'user_id' => $user_id, + 'contract_id' => 'USD' + ]); + break; + default: + return false; + break; + } + } + + } + + public function addUserBalanceLog(int $account_type, array $log_data): bool + { + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $log_data['stock_id'] = 'USD'; + return UserMoneyLogModel::InsertUserBalanceLog($log_data); + }else{ + switch ($account_type) { + case 1: + $log_data['digital_id'] = 'USDT'; + return UserDigitalLogModel::InsertUserBalanceLog($log_data); + break; + case 2: + $log_data['contract_id'] = 'USDT'; + return UserContractLogModel::InsertUserBalanceLog($log_data); + break; + case 3: + $log_data['stock_id'] = 'USD'; + return UserStockLogModel::InsertUserBalanceLog($log_data); + break; + case 4: + $log_data['stock_id'] = 'IDR'; + return UserStockIdnLogModel::InsertUserBalanceLog($log_data); + break; + case 5: + $log_data['stock_id'] = 'MYR'; + return UserStockMysLogModel::InsertUserBalanceLog($log_data); + break; + case 6: + $log_data['stock_id'] = 'THB'; + return UserStockThaLogModel::InsertUserBalanceLog($log_data); + break; + case 7: + $log_data['stock_id'] = 'INR'; + return UserStockInLogModel::InsertUserBalanceLog($log_data); + break; + case 8: + $log_data['contract_id'] = 'USDT'; + return UserContractSecLogModel::InsertUserBalanceLog($log_data); + break; + case 9: + $log_data['stock_id'] = 'SGD'; + return UserStockSgdLogModel::InsertUserBalanceLog($log_data); + break; + case 10: + $log_data['stock_id'] = 'USD'; + return UserStockFundLogModel::InsertUserBalanceLog($log_data); + break; + case 11: + $log_data['stock_id'] = 'INR'; + return UserStockOptionInrLogModel::InsertUserBalanceLog($log_data); + break; + case 12: + $log_data['stock_id'] = 'HKD'; + return UserStockHkdLogModel::InsertUserBalanceLog($log_data); + break; + case 14: + $log_data['stock_id'] = 'GBX'; + return UserStockGBXLogModel::InsertUserBalanceLog($log_data); + break; + case 15: + $log_data['stock_id'] = 'EUR'; + return UserStockFurLogModel::InsertUserBalanceLog($log_data); + break; + case 16: + $log_data['stock_id'] = 'EUR'; + return UserStockEurLogModel::InsertUserBalanceLog($log_data); + break; + case 17: + $log_data['stock_id'] = 'BRL'; + return UserStockBrlLogModel::InsertUserBalanceLog($log_data); + break; + case 18: + $log_data['stock_id'] = 'JPY'; + return UserStockJpLogModel::InsertUserBalanceLog($log_data); + break; + case 19: + $log_data['contract_id'] = 'USD'; + return UserForexLogModel::InsertUserBalanceLog($log_data); + break; + default: + return false; + break; + } + } + + } + + /** + * 获取用户资金划转明细 + * @param array $data + * @return array + */ + public function getUserTransfer(array $data): array + { + try { + validate(WalletValidate::class)->scene('getRechargeList')->check($data); + $list = UserTransferModel::getUserTransferList($data); + return $this->toData(0, 'Request successful.', $list); + } catch (ValidateException $validateException) { + $message = $validateException->getMessage(); + return $this->toData('1', $message, []); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + } + public function userHasNotPay(array $data):array + { + if (!empty($data['market_type'])) { + $table_obj = (new \app\admin\service\setting\IPOService())->getStockModel($data['market_type']); + if (empty($table_obj)) { + return $this->toData(1, 'system error.'); + } + $list = UserArrearsModel::where('user_id', $data['user_id'])->where('status', 0)->where('account_type', $data['market_type'])->select(); + } else { + $list = UserArrearsModel::where('user_id', $data['user_id'])->where('status', 0)->select(); + } + if (empty($list)) { + $list = []; + } else { + $list = $list->toArray(); + foreach ($list as $key => $val) { + $table_obj = (new \app\admin\service\setting\IPOService())->getStockModel($val['account_type']); + $order = Db::table($table_obj['order_table'])->where('order_no', $val['order_no'])->find(); + if ($order) { + $list[$key]['get_num'] = $order['get_num']; + $list[$key]['get_amount'] = $order['get_amount']; + $list[$key]['get_fee'] = $order['get_fee']; + $list[$key]['stock_code'] = Db::table($table_obj['stock_table'])->where('id', $order['pre_stock_id'])->value('stock_code'); + } + + } + } + return $this->toData(0, 'Request successful.', $list); + } + + + public function dealUnPayIPO(array $data):array + { + if(env('ACCOUT_TYPE.ALL_IN_ONE')==1){ + $this->dealUnPayIPOByNew($data); + }else{ + $this->dealUnPayIPOByOld($data); + } + + return $this->toData(0, 'Request successful.',[]); + } + public function dealUnPayIPOByOld($data){ + $total=UserArrearsModel::where('user_id',$data['user_id'])->where('account_type',$data['market_type'])->where('status',0)->sum('num'); + $table_obj=(new \app\admin\service\setting\IPOService())->getStockModel($data['market_type']); + $res=Db::table($table_obj['user_table'])->where('user_id',$data['user_id'])->where('stock_id',$table_obj['stock_id']) + ->where('usable_num','>=',$total)->find(); + if(empty($res)){ + return $this->toData(1, 'The balance is not enough.'); + } + + $order_list=UserArrearsModel::where('user_id',$data['user_id'])->where('account_type',$data['market_type'])->select(); + $nowDate=date('Y-m-d H:i:s'); + Db::startTrans(); + //扣钱 + $update_bool = Db::table($table_obj['user_table'])->where('stock_id', $table_obj['stock_id'])->where('user_id', $data['user_id']) + ->dec('usable_num', $total) + ->update(['update_time' => $nowDate]); + if(!$update_bool){ + Db::rollback(); + return $this->toData('1', 'system error0', []); + } + + + foreach ($order_list as $order){ + //生成支付流水 + $insertStockLogArr = [ + 'user_id' => $order['user_id'], + 'change_type' => 15, // 新股申购扣减费用 + 'stock_id' => $table_obj['stock_id'], + 'before_num' => 0, + 'change_num' => '-' . Db::table($table_obj['order_table'])->where('order_no',$order['order_no'])->value('get_amount'), + 'order_id' => $order['order_no'], + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $log_bool = Db::table($table_obj['log_table'])->insert($insertStockLogArr); + if(!$log_bool){ + Db::rollback(); + return $this->toData('1', 'system error1', []); + } + // 生成扣手续流水 + $insertStockLogArrFee = [ + 'user_id' => $order['user_id'], + 'change_type' => 16, // 新股申购扣减费用 + 'stock_id' => $table_obj['stock_id'], + 'before_num' => 0, + 'change_num' => '-' . Db::table($table_obj['order_table'])->where('order_no',$order['order_no'])->value('get_fee'), + 'order_id' => $order['order_no'], + 'create_time' => $nowDate, + 'update_time' => $nowDate + ]; + $fee_bool = Db::table($table_obj['log_table'])->insert($insertStockLogArrFee); + if (!$fee_bool) { + Db::rollback(); + return $this->toData('1', 'system error2', []); + } + //更新状态 + $status_bool=UserArrearsModel::where('user_id',$order['user_id'])->where('order_no',$order['order_no'])->update([ + 'status'=>1, + 'update_time'=>$nowDate + ]); + if (!$status_bool) { + Db::rollback(); + return $this->toData('1', 'system error2', []); + } + //更新订单状态 + if(env('USER_ARREARS.HAS_USER_ARREARS')==3){ + $sign_status=Db::table($table_obj['stock_table'])->where('id',$order['pre_stock_id'])->value('sign_status'); + $order_bool=Db::table($table_obj['order_table'])->where('order_no',$order['order_no'])->where('user_id',$order['user_id']) + ->update([ + 'status'=> $sign_status==1 ? 2:3, + 'update_time'=>$nowDate + ]); + if (!$order_bool) { + Db::rollback(); + return $this->toData('1', 'system error3'.Db::table($table_obj['order_table'])->getLastSql(), []); + } + } + + //删除缓存订单 + $key="USER:ARREAR:ORDER:".$order['order_no']; + Cache::store('redis')->delete($key); + } + + Db::commit(); + + } + public function dealUnPayIPOByNew($data){ + $total=UserArrearsModel::where('user_id',$data['user_id'])->where('account_type',$data['market_type'])->where('status',0)->sum('num'); + $table_obj=(new \app\admin\service\setting\IPOService())->getStockModel($data['market_type']); + $usd_total=0; + $rate = (new StockMarketModel())->getRate($data['market_type']); + $usd_total=$total/$rate; + $res=UserMoneyModel::where('user_id',$data['user_id'])->where('stock_id','USD') + ->where('usable_num','>=',$usd_total)->find(); + if(empty($res)){ + return $this->toData(1, 'The balance is not enough.'); + } + + $order_list=UserArrearsModel::where('user_id',$data['user_id'])->where('account_type',$data['market_type'])->select(); + $nowDate=date('Y-m-d H:i:s'); + Db::startTrans(); + //扣钱 + $update_bool = UserMoneyModel::where('stock_id', 'USD')->where('user_id', $data['user_id']) + ->dec('usable_num', $usd_total) + ->update(['update_time' => $nowDate]); + if(!$update_bool){ + Db::rollback(); + return $this->toData('1', 'system error0', []); + } + + + foreach ($order_list as $order){ + //生成支付流水 + $amount= Db::table($table_obj['order_table'])->where('order_no',$order['order_no'])->value('get_amount'); + $usd_amount=$amount/$rate; + $insertStockLogArr = [ + 'user_id' => $order['user_id'], + 'change_type' => 15, // 新股申购扣减费用 + 'stock_id' => $table_obj['stock_id'], + 'before_num' => 0, + 'change_num' => '-' .$usd_amount, + 'order_id' => $order['order_no'], + 'create_time' => $nowDate, + 'update_time' => $nowDate, + 'market_type' => $data['market_type'] + ]; + $log_bool = UserMoneyLogModel::InsertUserBalanceLog($insertStockLogArr); + if(!$log_bool){ + Db::rollback(); + return $this->toData('1', 'system error1', []); + } + // 生成扣手续流水 + $fee=Db::table($table_obj['order_table'])->where('order_no',$order['order_no'])->value('get_fee'); + $usd_fee= $fee/$rate; + $insertStockLogArrFee = [ + 'user_id' => $order['user_id'], + 'change_type' => 16, // 新股申购扣减费用 + 'stock_id' => $table_obj['stock_id'], + 'before_num' => 0, + 'change_num' => '-' . $usd_fee, + 'order_id' => $order['order_no'], + 'create_time' => $nowDate, + 'update_time' => $nowDate, + 'market_type' => $data['market_type'] + ]; + $fee_bool =UserMoneyLogModel::InsertUserBalanceLog($insertStockLogArrFee); + if (!$fee_bool) { + Db::rollback(); + return $this->toData('1', 'system error2', []); + } + + //更新状态 + $status_bool=UserArrearsModel::where('user_id',$order['user_id'])->where('order_no',$order['order_no'])->update([ + 'status'=>1, + 'update_time'=>$nowDate + ]); + if (!$status_bool) { + Db::rollback(); + return $this->toData('1', 'system error2', []); + } + //更新订单状态 + if(env('USER_ARREARS.HAS_USER_ARREARS')==3){ + $sign_status=Db::table($table_obj['stock_table'])->where('id',$order['pre_stock_id'])->value('sign_status'); + $order_bool=Db::table($table_obj['order_table'])->where('order_no',$order['order_no'])->where('user_id',$order['user_id']) + ->update([ + 'status'=> $sign_status==1 ? 2:3, + 'update_time'=>$nowDate + ]); + if (!$order_bool) { + Db::rollback(); + return $this->toData('1', 'system error3'.Db::table($table_obj['order_table'])->getLastSql(), []); + } + } + + //删除缓存订单 + $key="USER:ARREAR:ORDER:".$order['order_no']; + Cache::store('redis')->delete($key); + } + + Db::commit(); + } + // 获取账户之间划转手续费 + public function getRateToTransfer($data) + { + try { + // 1 现货 2 合约 3 美股 4 印尼股 5 马股 6 泰股 7 印度 + $fromAccount = $data['from_account']; + $toAccount = $data['to_account']; + + if($fromAccount <1 || $fromAccount > 20){ + return $this->toData('2', 'Transfer out account type is incorrect.'); + } + if($toAccount <1 || $toAccount > 20){ + return $this->toData('2', 'Transfer out account type is incorrect.'); + } + + if ($fromAccount == $toAccount) { + return $this->toData('2', 'The transfer out and transfer in accounts cannot be the same account.'); + } + + // 转出地址对美元的汇率 + $fromRate = (new StockMarketModel())->getRate($fromAccount); + $toRate = (new StockMarketModel())->getRate($toAccount); + + if ($fromRate <= 0) { + return $this->toData('2', 'Transfer out account type is incorrect.'); + } + + if ($toRate <= 0) { + return $this->toData('2', 'Transfer in account type is incorrect.'); + } + + // 是否传递转账数量 + $toChangeNum = '-'; + if (!empty($data['change_num']) && is_numeric($data['change_num']) && $data['change_num'] > 0) { + // 转出数量计算 change_num / from_rate * to_rate + $toChangeNum = bcmul(bcdiv($data['change_num'], $fromRate, 6), $toRate, 6); + } + return $this->toData('0', 'SUCCESS', [ + 'from_usd' => $fromRate, + 'usd_to' => $toRate, + 'to_change_num' => $toChangeNum + ]); + } catch (\Exception $exception) { + return $this->toData('100500', 'The system is busy. Please try again later.', [$exception->getMessage(), $exception->getTrace()]); + } + + } +} \ No newline at end of file diff --git a/app/home/service/XdPayService.php b/app/home/service/XdPayService.php new file mode 100644 index 0000000..f0c012a --- /dev/null +++ b/app/home/service/XdPayService.php @@ -0,0 +1,192 @@ +merchant; + $post_data['payCode']=$this->payCode; + $post_data['amount']=$amount; + $post_data['orderId']=$orderId; + $post_data['notifyUrl']=$notify_url.url('xdpay_notify'); + $sign=$this->generateQueryString($post_data,$this->key); + $post_data['sign']=$sign; + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res=$this->curlPost($this->pay_url,$post_data,10,$header); + $result=json_decode($res,true); + return $result; + } + public function xdpayNotify($data){ + Log::info('收到xdpay异步回调:'.json_encode($data)); + $data['reverse']=$data['reverse'] ? 'true':'false'; + $sign=$this->generateQueryString($data,$this->key); + if($sign==strtolower($data['sign'])){ + if($data['status']==1){ + $order_info=RechargeApplyModel::getOrderByNo([ + 'order_no'=>$data['orderId'] + ]); + if($order_info && $data['amount']==$order_info['total_amount']){ + if($order_info['status']==0){ + return (new PayService())->dealPayNotify($order_info); + } + }else{ + Log::info('xdpay支付订单不存在:'.json_encode($data)); + } + }else{ + Log::info('xdpay支付订单支付失败:'.json_encode($data)); + } + }else{ + Log::info('xdpay签名校验失败:'.json_encode($data)); + } + } + public function apply_pay($orderId,$amount,$ifsc,$bank_account,$nike_name) + { + $notify_url=env('PAY.NOTIFY_URL'); + $post_data['merchant']=$this->merchant; + $post_data['payCode']=$this->payAppCode; + $post_data['amount']=$amount; + $post_data['orderId']=$orderId; + $post_data['notifyUrl']=$notify_url.'/bs/xdpay_anotify'; + $post_data['bankAccount']=$bank_account; + $post_data['customName']=$nike_name; + $post_data['remark']=$ifsc; + $sign=$this->generateQueryString($post_data,$this->key); + $post_data['sign']=$sign; + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res=$this->curlPost($this->app_url,$post_data,10,$header); + $result=json_decode($res,true); + if($result['code']==200){ + return [ + 'code'=>200, + 'msg'=>'ok', + 'order_idx'=>$result['data']['platOrderId'], + 'content'=>$res + ]; + }else{ + return [ + 'code'=>300, + 'msg'=>$res, + 'order_idx'=>'', + 'content'=>$res + ]; + } + } + public function xdpayApplyNotify($data){ + Log::info('收到xdpay代付异步回调:'.json_encode($data)); + $data['reverse']=$data['reverse'] ? 'true':'false'; + $sign=$this->generateQueryString($data,$this->key); + if($sign==strtolower($data['sign'])){ + if($data['status']==1){ + $order_info=UserWithdrawalModel::getUserDrawalInfo([ + 'order_no'=>$data['orderId'] + ]); + if($order_info && $order_info['status']==3){ + UserWithdrawalModel::where([ + 'id'=>$order_info['id'] + ])->update([ + 'status'=>4, + 'deal_time'=>date('Y-m-d H:i:s') + ]); + Log::info('xdpay代付支付成功:'.json_encode($data)); + }else{ + Log::info('xdpay代付订单不存在:'.json_encode($data)); + } + }else{ + UserWithdrawalModel::where([ + 'order_no'=>$data['orderId'] + ])->update([ + 'status'=>1, + ]); + Log::info('xdpay代付失败:'.json_encode($data)); + } + }else{ + Log::info('xdpay代付签名校验失败:'.json_encode($data)); + } + } + public function getBalance() + { + $post_data['merchant']=$this->merchant; + $sign=$this->generateQueryString($post_data,$this->key); + $post_data['sign']=$sign; + $header = array("Content-Type:application/x-www-form-urlencoded"); + $res=$this->curlPost($this->bla_url,$post_data,10,$header); + $result=json_decode($res,true); + if($result['code']==200){ + return [ + 'amount'=>$result['data']['balanceUsable'] + ]; + }else{ + return [ + 'amount'=>0 + ]; + } + } + private function curlPost($url, $post_data = array(), $timeout = 5, $header = "", $data_type = "") { + $header = empty($header) ? '' : $header; + //支持json数据数据提交 + if($data_type == 'json'){ + $post_string = json_encode($post_data); + }elseif($data_type == 'array') { + $post_string = $post_data; + }elseif(is_array($post_data)){ + $post_string = http_build_query($post_data, '', '&'); + } + + $ch = curl_init(); // 启动一个CURL会话 + curl_setopt($ch, CURLOPT_URL, $url); // 要访问的地址 + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 对认证证书来源的检查 // https请求 不验证证书和hosts + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 从证书中检查SSL加密算法是否存在 + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器 + //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转 + //curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer + curl_setopt($ch, CURLOPT_POST, true); // 发送一个常规的Post请求 + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string); // Post提交的数据包 + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 设置超时限制防止死循环 + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + //curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 获取的信息以文件流的形式返回 + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); //模拟的header头 + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + private function generateQueryString($fields, $privateKey) { + // 按ASCII顺序对字段名进行自然排序 + ksort($fields); + + // 将字段按 k=v 格式拼接成字符串 + $query = ''; + foreach($fields as $key => $value) { + if($key!='sign'){ + $query .= $key . '=' . strval($value) . '&'; + } + } + // 去除末尾的 '&' + $query = rtrim($query, '&'); + // 在字符串末尾拼接私钥 + $query .= '&key=' . $privateKey; + $sign=md5($query); + return $sign; + } + + +} \ No newline at end of file diff --git a/app/home/validate/BankValidate.php b/app/home/validate/BankValidate.php new file mode 100644 index 0000000..29c83d7 --- /dev/null +++ b/app/home/validate/BankValidate.php @@ -0,0 +1,57 @@ + 'require|number', + 'adr_id' => 'require|number', + 'user_id' => 'require|number', + 'true_name' => 'require|isString', + 'identity_card' => 'require|isString', + 'bank_name' => 'require|isString', + 'bank_card' => 'require|isString', + 'bank_phone' => 'require|isString', + 'bank_email' => 'require|email', + + 'wallet_type' => 'require', + 'wallet_address' => 'require', + 'remark' => 'require', + + 'is_default' => 'require|in:0,1', + 'page' => 'require|number', + 'page_size' => 'require|number', + ]; + + protected $message = [ + 'id.require' => 'Please fill in the ID.', + 'adr_id.require' => 'Please fill in the ID.', + 'user_id.require' => 'Please fill in the user ID.', + 'true_name.require' => 'Please fill in the account name', + 'identity_card.require' => 'Please fill in the ID card number.', + 'bank_name.require' => 'Please fill in the bank name.', + 'bank_card.require' => 'Please fill in the bank card number.', + 'bank_phone.require' => 'Please fill in the phone number.', + 'bank_email.require' => 'Please fill in the email address.', + 'wallet_type.require' => 'Please fill in the wallet type.', + 'wallet_address.require' => 'Please fill in the wallet address.', + 'remark.require' => 'Please fill in the wallet remark.', + 'is_default.require' => 'Is it set as the default', + 'is_default.in' => 'data is error', + 'page.number' => 'Please enter the page number.', + 'page_size.number' => 'Please enter the page size number.', + ]; + + protected $scene = [ + //'setBank' => ['id','user_id','true_name','identity_card','bank_name','bank_card','bank_phone','bank_email','is_default'], + 'setBank' => ['id','user_id','true_name','bank_name','bank_card','is_default'], + 'getBankList' => ['user_id','page','page_size'], + 'getBankInfo' => ['user_id','id'], + + 'setWalletAddress'=>['adr_id','user_id','wallet_type','wallet_address','is_default'], + 'getWalletAddressList' => ['user_id','page','page_size'], + 'getWalletAddressInfo' => ['user_id','adr_id'], + 'delWalletAddress' => ['user_id','adr_id'], + ]; +} diff --git a/app/home/validate/BaseHomeValidate.php b/app/home/validate/BaseHomeValidate.php new file mode 100644 index 0000000..0f377ea --- /dev/null +++ b/app/home/validate/BaseHomeValidate.php @@ -0,0 +1,21 @@ + 'require|email|length:5,40', + 'email_code' => 'require|number', + 'password' => 'require|isString|length:5,40', + 'invite_code' => 'alphaDash', + 'phone' => 'require|isString|length:5,40', + 'nation' => 'require|isString', + 'sms_code' => 'require|isString', + 'device' => 'require|isString|length:2,100', + ]; + + protected $message = [ + 'email.require' => 'The email is required.', + 'email.email' => 'The email format is incorrect.', + 'email.length' => 'The email length must be between 5 and 40 characters.', + 'email_code.require' => 'The email verification code is required.', + 'email_code.number' => 'The email verification code format is incorrect.', + 'password.require' => 'The password is required.', + 'password.isString' => 'The password is invalid.', + 'password.length' => 'The password length is invalid.', + 'invite_code.alphaDash' => 'The invitation code is invalid.', + 'phone.require' => 'The phone number is required.', + 'phone.number' => 'The phone number is invalid.', + 'phone.length' => 'The phone number length must be between 5 and 40 characters.', + 'nation.require' => 'The country code is required.', + 'nation.number' => 'The country code is invalid.', + 'sms_code.require' => 'The SMS verification code is required.', + 'sms_code.number' => 'The SMS verification code format is incorrect.', + 'device.require' => 'The device type is required.', + 'device.isString' => 'The device type format is incorrect.', + 'device.length' => 'The device type parameter is incorrect.', + ]; + + protected $scene = [ + 'sendEmail' => ['email'], + 'emailRegister' => ['email', 'email_code', 'password', 'invite_code'], + 'emailLogin' => ['email', 'password','device'], + 'sendSms' => ['phone', 'nation'], + 'smsRegister' => ['phone', 'nation','sms_code', 'password', 'invite_code'], + 'smsLogin' => ['phone', 'nation','sms_code','device'], + 'emailForget' => ['email', 'email_code', 'password'], + 'smsForget' => ['phone', 'nation','sms_code', 'password'], + 'smsPasswordLogin' => ['phone', 'nation','password','device'], + ]; +} \ No newline at end of file diff --git a/app/home/validate/MarketValidate.php b/app/home/validate/MarketValidate.php new file mode 100644 index 0000000..294ff45 --- /dev/null +++ b/app/home/validate/MarketValidate.php @@ -0,0 +1,36 @@ + 'require|number', + 'trade_name' => 'require|isString', + 'market_name' => 'require|isString', + 'page' => 'number', + 'page_size' => 'number', + ]; + + protected $message = [ + 'user_id.require' => 'Please fill in the user ID.', + 'market_type.require' => 'Please fill in the market type.', + 'trade_name.require' => 'Please fill in the trading pair.', + 'market_name.require' => 'Please fill in the name of the trading pair.', + 'trade_name.isString' => 'The trading pair format is incorrect.', + 'market_type.in' => 'The market type is incorrect.', + 'page.number' => 'Please enter the page number.', + 'page_size.number' => 'Please enter the page size number.', + ]; + + protected $scene = [ + 'setMarket' => ['user_id','market_type','trade_name','market_name','trade_numeric_code'], + 'delMarket' => ['user_id','market_type','trade_name'], + 'getMarket' => ['user_id','market_type','page','page_size'], + 'getMarketList' => ['market_type'], + 'getTradeFee' => ['market_type'], + 'getTrade' => ['market_type','trade_name'], + ]; +} diff --git a/app/home/validate/UploadValidate.php b/app/home/validate/UploadValidate.php new file mode 100644 index 0000000..b4ba85f --- /dev/null +++ b/app/home/validate/UploadValidate.php @@ -0,0 +1,20 @@ + 'require|fileSize:10485760|fileExt:jpg,jpeg,png', + ]; + + protected $message = [ + 'image.require' => 'Please select a file.', + 'image.fileSize' => 'Please ensure that the file size is within 10 MB.', + 'image.fileExt' => 'Please upload the image in jpg, jpeg, or png format.', + ]; + + protected $scene = [ + 'uploadImage' => ['image'], + ]; +} \ No newline at end of file diff --git a/app/home/validate/UserValidate.php b/app/home/validate/UserValidate.php new file mode 100644 index 0000000..2318f60 --- /dev/null +++ b/app/home/validate/UserValidate.php @@ -0,0 +1,124 @@ + 'require|isString', + 'file_id' => 'require|integer', + 'day' => 'require|integer', + 'num' => 'require|integer', + 'email_code' => 'require|isString', + 'sms_code' => 'require|isString', + 'email_type' => 'require|in:1,2', // 1 给已经绑定的号发 2 给未绑定的号发 + 'email' => 'requireIf:email_type,2|email|length:5,40', + 'business' => 'require|in:1,2', // 1 非交易业务 2交易业务 + 'nation' => 'requireIf:phone_type,2|isString', + 'phone' => 'requireIf:phone_type,2|isString|length:5,40', + 'phone_type' => 'require|in:1,2',// 1 给已经绑定的号发 2 给未绑定的号发 + 'pay_password' => 'require|isString', + 'pay_password_new' => 'require|isString|length:6,150', + 'password' => 'require|isString', + 'password_new' => 'require|isString|length:6,150', + 'nick_name' => 'require|isString|length:2,100', + 'first_name' => 'isString|length:1,100', + 'last_name' => 'isString|length:1,100', + 'gender' => 'isString|in:0,1,2', + ]; + + protected $message = [ + 'num.require' => 'The num is required.', + 'day.require' => 'The day is required.', + 'country_id.require' => 'The country code is required.', + 'country_id.isString' => 'The country code format is incorrect.', + 'file_id.isString' => 'The file is required.', + 'file_id.integer' => 'The file is missing.', + 'email_type.require' => 'The email sending type is required.', + 'email_type.in' => 'The email sending type format is incorrect.', + 'email.requireIf' => 'The email is required.', + 'email.email' => 'The email format is incorrect.', + 'email.length' => 'The email should be between 5 and 40 characters.', + 'business.require' => 'The business type is required.', + 'business.in' => 'The business type is incorrect.', + 'nation.requireIf' => 'The country code is required.', + 'phone.requireIf' => 'The phone number is required.', + 'phone.isString' => 'The phone number format is incorrect.', + 'phone.length' => 'The phone number should be between 5 and 40 characters.', + 'nation.isString' => 'The country code format is incorrect.', + 'phone_type.require' => 'The phone message sending type is required.', + 'phone_type.in' => 'The phone message sending type is incorrect.', + 'email_code.require' => 'The email verification code is required.', + 'email_code.isString' => 'The email verification code format is incorrect.', + 'pay_password.isString' => 'The collection password format is incorrect.', + 'pay_password.require' => 'The collection password is required.', + 'pay_password_new.require' => 'The new collection password is required.', + 'pay_password_new.isString' => 'The new collection password format is incorrect.', + 'pay_password_new.length' => 'The new collection password length format is incorrect.', + 'password.isString' => 'The login password format is incorrect.', + 'password.require' => 'The login password is required.', + 'password_new.isString' => 'The new login password format is incorrect.', + 'password_new.require' => 'The new login password is required', + 'password_new.length' => 'The new login length format is incorrect.', + 'sms_code.require' => 'The SMS verification code is required.', + 'sms_code.isString' => 'The SMS verification code format is incorrect.', + 'nick_name.require' => 'Nickname is required.', + 'nick_name.isString' => 'The name format is incorrect.', + 'nick_name.length' => 'The name should be between 2 and 100 characters.', + 'first_name.isString' => 'The name format is incorrect.', + 'first_name.length' => 'The name should be between 2 and 100 characters.', + 'last_name.isString' => 'The name format is incorrect.', + 'last_name.length' => 'The name should be between 2 and 100 characters.', + 'gender.isString' => 'The gender format is incorrect.', + 'gender.in' => 'The gender format is incorrect.', + ]; + + protected $scene = [ + 'setCountry' => ['country_id'], + 'updateHeadImg' => ['file_id'], + 'sendEmail' => ['email_type', 'email', 'business'], + 'sendSms' => ['phone_type', 'phone', 'business', 'nation'], +// 'setPayPasswordByEmail' => ['email_code', 'pay_password'], +// 'setPayPasswordBySms' => ['sms_code', 'phone', 'pay_password', 'nation'], + 'setPayPasswordByEmail' => ['pay_password'], + 'setPayPasswordBySms' => ['phone', 'pay_password', 'nation'], + + 'updateInfo' => ['nick_name', 'first_name', 'last_name', 'gender'], + +// 'updatePayPasswordBySms' => ['sms_code','pay_password', 'pay_password_new'], + 'updatePayPasswordBySms' => ['pay_password', 'pay_password_new'], + +// 'updatePayPasswordByEmail' => ['email_code','pay_password','pay_password_new'], + 'updatePayPasswordByEmail' => ['pay_password', 'pay_password_new'], + +// 'resetPayPasswordBySms' => ['sms_code', 'pay_password_new'], +// 'resetPayPasswordByEmail' => ['email_code', 'pay_password_new'], + 'resetPayPasswordBySms' => ['pay_password_new'], + 'resetPayPasswordByEmail' => ['pay_password_new'], + +// 'updatePasswordBySms' => ['sms_code', 'password', 'password_new'], +// 'updatePasswordByEmail' => ['email_code', 'password', 'password_new'], +// 'resetPasswordBySms' => ['sms_code', 'password_new'], +// 'resetPasswordByEmail' => ['email_code', 'password_new'], + 'updatePasswordBySms' => ['password', 'password_new'], + 'updatePasswordByEmail' => ['password', 'password_new'], + 'resetPasswordBySms' => ['password_new'], + 'resetPasswordByEmail' => ['password_new'], + + +// 'bindEmail' => ['email', 'email_code'], // 绑定邮箱 + 'bindEmail' => ['email'], // 绑定邮箱 + +// 'updateEmail' => ['email', 'email_code', 'password'], // 修改绑定邮箱 + 'updateEmail' => ['email', 'password'], // 修改绑定邮箱 + + +// 'bindPhone' => ['phone', 'nation','sms_code'], // 绑定手机号 + 'bindPhone' => ['phone', 'nation'], // 绑定手机号 + +// 'updatePhone' => ['phone', 'nation','sms_code','password'], // 修改绑定手机号 + 'updatePhone' => ['phone', 'nation', 'password'], // 修改绑定手机号 + 'apply_loan' => ['num', 'day'], // 修改绑定手机号 + + ]; +} \ No newline at end of file diff --git a/app/home/validate/WalletValidate.php b/app/home/validate/WalletValidate.php new file mode 100644 index 0000000..8bfaf66 --- /dev/null +++ b/app/home/validate/WalletValidate.php @@ -0,0 +1,45 @@ + 'require|number', + 'recharge_type' => 'require|in:1,2', + 'recharge_channel' => 'require|isString', + 'recharge_num' => 'require|number', + 'change_num' => 'require|gt:0', + 'page' => 'number', + 'page_size' => 'number', + ]; + + protected $message = [ + 'user_id.require' => 'Please fill in the user ID.', + 'account_type.require' => 'Please fill in the market type.', + 'from_account.require' => 'Please select the transfer out account.', + 'to_account.require' => 'Please select the transfer in account.', + 'account_type.in' => 'Account type is incorrect.', + 'from_account.in' => 'Transfer out account type is incorrect.', + 'to_account.in' => 'Transfer in account type is incorrect.', + 'recharge_type.require' => 'Please fill in the recharge method.', + 'recharge_type.in' => 'The recharge method is incorrect.', + 'recharge_channel.require' => 'Please fill in the recharge channel.', + 'recharge_num.require' => 'Please fill in the recharge amount.', + 'change_num.gt' => 'The quantity must be greater than 0.', + 'page.number' => 'Please enter the page number.', + 'page_size.number' => 'Please enter the page size number.', + ]; + + protected $scene = [ + 'recharge' => ['user_id','account_type','recharge_type','recharge_channel','recharge_num'], + 'transfer' => ['user_id','from_account','to_account','change_num'], + + 'getRechargeList'=>['user_id','page','page_size'], + 'getDrawalList'=>['user_id','account_type','page','page_size'], + 'getUserBalance'=>['user_id','account_type'], + + + + ]; +} diff --git a/app/middleware.php b/app/middleware.php new file mode 100644 index 0000000..a6b39f9 --- /dev/null +++ b/app/middleware.php @@ -0,0 +1,10 @@ +column('user_id'); + if(empty($firstUserIds)){ + return []; + } + + // 查询父级下面的用户 + $userIds = UserModel::where('origin_user_id','in',$firstUserIds)->column('user_id'); + return array_merge($firstUserIds, $userIds); +// return UserModel::where('origin_user_id','in',$firstUserIds)->column('user_id'); + } + + // 判断操作用户是否是代理商 + public static function checkUserIsAgent($adminId) + { + // 代理角色 + $roleId = 10; + $admin = self::where('id', $adminId)->find(); + if($admin && $admin['role_id'] == $roleId){ + return true; + } + + return false; +// $agentGroupId = env('AGENT.AGENT_GROUP_ID'); +// $authGroupAccess = AuthGroupAccessModel::where('uid', $adminId)->find(); +// if($authGroupAccess && $authGroupAccess['group_id'] == $agentGroupId){ +// return true; +// } +// return false; + } + + /** + * @desc 根据用户id 查询指定字段 + * @param $fields + * @param $userId + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public static function getFieldsByUserId($fields, $userId): array + { + $self = self::where('id', $userId)->field($fields)->find(); + if(empty($self)){ + return []; + } + return $self->toArray(); + } + + /** + * @desc 获取邀请码用户 + * @param $inviteCode + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public static function getIdByInviteCode($inviteCode): int + { + $self = self::where('invite_code', $inviteCode)->value('id'); + + if(empty($self)){ + return 0; + } + return $self; + }} \ No newline at end of file diff --git a/app/model/AnnouncementModel.php b/app/model/AnnouncementModel.php new file mode 100644 index 0000000..33d8468 --- /dev/null +++ b/app/model/AnnouncementModel.php @@ -0,0 +1,19 @@ + '上架', + self::STATUS_OFF => '下架', + ]; + + const IS_DELETE_NO = 1; + const IS_DELETE_YES = 2; +} \ No newline at end of file diff --git a/app/model/AuthGroupAccessModel.php b/app/model/AuthGroupAccessModel.php new file mode 100644 index 0000000..d14cc27 --- /dev/null +++ b/app/model/AuthGroupAccessModel.php @@ -0,0 +1,9 @@ +field($fields)->find(); + if(empty($self)){ + return []; + } + return $self->toArray(); + } +} \ No newline at end of file diff --git a/app/model/AuthRuleModel.php b/app/model/AuthRuleModel.php new file mode 100644 index 0000000..7055db6 --- /dev/null +++ b/app/model/AuthRuleModel.php @@ -0,0 +1,31 @@ +field($fields)->find(); + if(empty($self)){ + return []; + } + return $self->toArray(); + } +} \ No newline at end of file diff --git a/app/model/BannerModel.php b/app/model/BannerModel.php new file mode 100644 index 0000000..23ec5d6 --- /dev/null +++ b/app/model/BannerModel.php @@ -0,0 +1,18 @@ + '上架', + self::STATUS_OFF => '下架', + ]; + + const IS_DELETE_NO = 1; + const IS_DELETE_YES = 2; +} \ No newline at end of file diff --git a/app/model/BaseModel.php b/app/model/BaseModel.php new file mode 100644 index 0000000..408cfed --- /dev/null +++ b/app/model/BaseModel.php @@ -0,0 +1,10 @@ +field('brok_type,parent_fee,grandpa_fee,top_fee,pay_type,remark')->select(); + return $list->toArray(); + } + + + +} \ No newline at end of file diff --git a/app/model/ConfigModel.php b/app/model/ConfigModel.php new file mode 100644 index 0000000..5a74297 --- /dev/null +++ b/app/model/ConfigModel.php @@ -0,0 +1,15 @@ +count(); + $list = self::where($where)->field('trade_name as name,trade_name as code')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function existMarket($trade_name):bool + { + $id=self::where('trade_name',$trade_name)->value('id'); + return $id >0; + } + public static function getMarketFaceList($type=0) + { + $list=self::where('status',1)->field('face_value,trade_name as name,trade_name as code,sort,max_pry,min_pry')->select(); + if(empty($list)){ + return []; + } + $list=$list->toArray(); + if($type==1){ + foreach ($list as $val){ + $face_list[$val['name']]=$val['face_value']; + } + }else{ + $face_list=$list; + } + + return $face_list; + } + + + +} \ No newline at end of file diff --git a/app/model/ContractMarketModel.php b/app/model/ContractMarketModel.php new file mode 100644 index 0000000..10caaf8 --- /dev/null +++ b/app/model/ContractMarketModel.php @@ -0,0 +1,11 @@ +$user_id, + 'status'=>1, + 'contract_id'=>$contract_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + $con_list=ContractListMode::getMarketFaceList(1); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'face_value'=>isset($con_list[$contract_id]) ? $con_list[$contract_id]:0, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type,contract_id,face_value')->select(); + + //$con_list=ContractListMode::getMarketFaceList(1); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if(empty($val['face_value'])){ + $face_value=1; + }else{ + $face_value=$val['face_value']; + } + if($val['trade_type']==1){ + //$order_num=$val['order_number']*($val['closing_price']-$val['deal_price'])-$val['closing_cost']-$val['service_cost']; + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price'])*$face_value; + }else{ + //$order_num=$val['order_number']*($val['deal_price']-$val['closing_price'])-$val['closing_cost']-$val['service_cost']; + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price'])*$face_value; + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['contract_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + + +} \ No newline at end of file diff --git a/app/model/ContractSettingModel.php b/app/model/ContractSettingModel.php new file mode 100644 index 0000000..c105bf1 --- /dev/null +++ b/app/model/ContractSettingModel.php @@ -0,0 +1,13 @@ +', 0)->field('time_step,earnings_num')->order('time_step', 'asc')->select()->toArray(); + } +} \ No newline at end of file diff --git a/app/model/ContractTradeModel.php b/app/model/ContractTradeModel.php new file mode 100644 index 0000000..a2226c8 --- /dev/null +++ b/app/model/ContractTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'contract_id'=>$contract_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + $con_list=ContractListMode::getMarketFaceList(1); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'face_value'=>isset($con_list[$contract_id]) ? $con_list[$contract_id]:0, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type,contract_id,face_value')->select(); + + //$con_list=ContractListMode::getMarketFaceList(1); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if(empty($val['face_value'])){ + $face_value=1; + }else{ + $face_value=$val['face_value']; + } + if($val['trade_type']==1){ + //$order_num=$val['order_number']*($val['closing_price']-$val['deal_price'])-$val['closing_cost']-$val['service_cost']; + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price'])*$face_value; + }else{ + //$order_num=$val['order_number']*($val['deal_price']-$val['closing_price'])-$val['closing_cost']-$val['service_cost']; + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price'])*$face_value; + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['contract_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + + +} \ No newline at end of file diff --git a/app/model/CountryModel.php b/app/model/CountryModel.php new file mode 100644 index 0000000..a11d3df --- /dev/null +++ b/app/model/CountryModel.php @@ -0,0 +1,64 @@ +find(); + if(empty($self)){ + return []; + } + return $self->toArray(); + } + + public static function getAll() + { + return self::where('id', '>', 0)->order('sort', 'desc')->select(); + } + + /** + * @desc 判断国家码是否存在 + * @param $code + * @return bool + * @throws \think\db\exception\DbException + */ + public static function checkCodeExists($code): bool + { + $count = self::where('code', $code)->count(); + return $count > 0; + } + public static function getNameById($id, $lang = 'en') + { + $self = self::where('id', $id)->find(); + if(empty($self)){ + return ''; + } + if($lang == 'cn'){ + return $self->name_cn; + } + + return $self->name_en; + } +} \ No newline at end of file diff --git a/app/model/DigitalListModel.php b/app/model/DigitalListModel.php new file mode 100644 index 0000000..2b6bc2a --- /dev/null +++ b/app/model/DigitalListModel.php @@ -0,0 +1,67 @@ +count(); + $list = self::where($where)->field('trade_name as name,exchange_name as code,logo_link,sort')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + $list=$list->toArray(); + + foreach ($list as $key=>$val){ + $list[$key]['code']=$val['name'].'-'.$val['code']; + } + + return [ + 'total'=>$count, + 'list'=>$list, + ]; + } + public static function existMarket($trade_name):bool + { + $id=self::where('trade_name',$trade_name)->value('id'); + return $id >0; + } + + +} \ No newline at end of file diff --git a/app/model/DigitalTradeModel.php b/app/model/DigitalTradeModel.php new file mode 100644 index 0000000..1bb355e --- /dev/null +++ b/app/model/DigitalTradeModel.php @@ -0,0 +1,162 @@ +$user_id, + 'status'=>1 + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] + $val['service_cost']; + $num+=$order_num; + } + } + return $num; + } + + /** + * 买入成本 + */ + public static function getTradeOrderPrice(int $user_id,string $digital_id,int $trade_type) + { + $num=0; + $buy_num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3, + 'digital_id'=>$digital_id, + 'trade_type'=>$trade_type + ])->field('order_number,closing_price,service_cost,closing_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['closing_price'] + $val['service_cost']; + $num+=$order_num; + $buy_num+=$val['order_number']; + } + } + return [ + 'order_money'=>$num, //订单总额 + 'order_num'=>$buy_num //订单数量 + ]; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->sum('closing_cost'); + return $info; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price'])-$val['closing_cost']-$val['service_cost']; + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['digital_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['closing_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['closing_price']; + $trade_data['order_time']=strtotime($val['closing_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + + +} \ No newline at end of file diff --git a/app/model/DocumentModel.php b/app/model/DocumentModel.php new file mode 100644 index 0000000..c84e9ee --- /dev/null +++ b/app/model/DocumentModel.php @@ -0,0 +1,39 @@ + '平台介绍', + '2' => '功能介绍', + '3' => '资金风控', + '4' => '关于我们', + '5' => 'H5首页文章', + '6' => '投资理念', + '7' => '管理团队' + ]; + + // pc 页脚展示的文章 + const TYPE_FOOTER_PC = [ + '1' => '平台介绍', + '2' => '功能介绍', + '3' => '资金风控', + '4' => '关于我们', +// '5' => 'H5首页文章', + '6' => '投资理念', + '7' => '管理团队' + ]; + + const STATUS_ON = '1'; + const STATUS_OFF = '2'; + const STATUS_MAP = [ + self::STATUS_ON => '上架', + self::STATUS_OFF => '下架', + ]; + + + const IS_DELETE_NO = 1; + const IS_DELETE_YES = 2; +} \ No newline at end of file diff --git a/app/model/DrawalSettingModel.php b/app/model/DrawalSettingModel.php new file mode 100644 index 0000000..d00dad4 --- /dev/null +++ b/app/model/DrawalSettingModel.php @@ -0,0 +1,26 @@ +field('bank_drawal_fee,digital_drawal_fee,min_recharge,min_drawal')->find(); + if(empty($info)){ + return []; + } + return $info->toArray(); + } + + + +} \ No newline at end of file diff --git a/app/model/FaqModel.php b/app/model/FaqModel.php new file mode 100644 index 0000000..6788d97 --- /dev/null +++ b/app/model/FaqModel.php @@ -0,0 +1,18 @@ + '上架', + self::STATUS_OFF => '下架', + ]; + + const IS_DELETE_NO = 1; + const IS_DELETE_YES = 2; +} \ No newline at end of file diff --git a/app/model/FeeSettingModel.php b/app/model/FeeSettingModel.php new file mode 100644 index 0000000..dd66b21 --- /dev/null +++ b/app/model/FeeSettingModel.php @@ -0,0 +1,61 @@ + '现货', + '2' => '合约', + '3' => '美股', + '4' => '印尼股票', // 5 马股 6 泰股 + '5' => '马股', + '6' => '泰股', + '7' => '印度股票', + '8' => '秒合约', + '9' => '新加坡股票', + '10' => '基金', + '11' => '印度期权', + '12' => '港股', + '14' => '英股' + ]; + + public static $payTypeList = [ + '0' => '固定费用', + '1' => '按比例结算', + '2' => '按张结算', + ]; + + public static function getTradeFeeById($market_type):array + { + if($market_type>0){ + $info = self::where('market_type', $market_type)->field('market_type,buy_fee,sale_fee,pay_type,min_buy_num,min_sale_num,purchase_fee')->find(); + if(empty($info)){ + return []; + } + return $info->toArray(); + }else{ + $info = self::where(1)->field('market_type,buy_fee,sale_fee,pay_type,min_buy_num,min_sale_num,purchase_fee')->select(); + if(empty($info)){ + return []; + } + return $info->toArray(); + } + } + + + +} \ No newline at end of file diff --git a/app/model/FileModel.php b/app/model/FileModel.php new file mode 100644 index 0000000..4d5096e --- /dev/null +++ b/app/model/FileModel.php @@ -0,0 +1,67 @@ +find(); + if(empty($self)){ + return []; + } + return $self->toArray(); + } + + /** + * @desc 获取文件路径 + * @param $id + * @return mixed|string + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public static function getFilePath($id) + { + $self = self::where('id', $id)->find(); + if(!empty($self)){ + return $self->path; + } + + return ''; + } + /** + * @desc 将文件入库 + * @param $path + * @param int $type + * @return int + */ + public static function insertFile($path, int $type = 1) + { + $self = new self; + $self->type = $type; + $self->path = $path; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + return $self->id; + } +} \ No newline at end of file diff --git a/app/model/ForexListModel.php b/app/model/ForexListModel.php new file mode 100644 index 0000000..c421f41 --- /dev/null +++ b/app/model/ForexListModel.php @@ -0,0 +1,79 @@ +count(); + $list = self::where($where)->field('trade_name as name,trade_name as code')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function existMarket($trade_name):bool + { + $id=self::where('trade_name',$trade_name)->value('id'); + return $id >0; + } + public static function getMarketFaceList($type=0) + { + $list=self::where('status',1)->field('face_value,trade_name as name,trade_name as code,sort,max_pry,min_pry')->select(); + if(empty($list)){ + return []; + } + $list=$list->toArray(); + if($type==1){ + foreach ($list as $val){ + $face_list[$val['name']]=$val['face_value']; + } + }else{ + $face_list=$list; + } + + return $face_list; + } + + + +} \ No newline at end of file diff --git a/app/model/ForexMarketModel.php b/app/model/ForexMarketModel.php new file mode 100644 index 0000000..69286ae --- /dev/null +++ b/app/model/ForexMarketModel.php @@ -0,0 +1,11 @@ +$user_id, + 'status'=>1, + 'contract_id'=>$contract_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + $con_list=ContractListMode::getMarketFaceList(1); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'face_value'=>isset($con_list[$contract_id]) ? $con_list[$contract_id]:0, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type,contract_id,face_value')->select(); + + //$con_list=ContractListMode::getMarketFaceList(1); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if(empty($val['face_value'])){ + $face_value=1; + }else{ + $face_value=$val['face_value']; + } + if($val['trade_type']==1){ + //$order_num=$val['order_number']*($val['closing_price']-$val['deal_price'])-$val['closing_cost']-$val['service_cost']; + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price'])*$face_value; + }else{ + //$order_num=$val['order_number']*($val['deal_price']-$val['closing_price'])-$val['closing_cost']-$val['service_cost']; + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price'])*$face_value; + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['contract_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + + +} \ No newline at end of file diff --git a/app/model/HistoryFundStockModel.php b/app/model/HistoryFundStockModel.php new file mode 100644 index 0000000..f519206 --- /dev/null +++ b/app/model/HistoryFundStockModel.php @@ -0,0 +1,17 @@ +field('language_name,language_code')->select(); + if(empty($list)){ + return []; + } + return $list->toArray(); + } + + + +} \ No newline at end of file diff --git a/app/model/MoneyTradeModel.php b/app/model/MoneyTradeModel.php new file mode 100644 index 0000000..6a395cd --- /dev/null +++ b/app/model/MoneyTradeModel.php @@ -0,0 +1,143 @@ +$user_id, + 'status'=>1, + 'contract_id'=>$contract_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + $con_list=ContractListMode::getMarketFaceList(1); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'face_value'=>isset($con_list[$contract_id]) ? $con_list[$contract_id]:0, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type,contract_id,face_value')->select(); + + //$con_list=ContractListMode::getMarketFaceList(1); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if(empty($val['face_value'])){ + $face_value=1; + }else{ + $face_value=$val['face_value']; + } + if($val['trade_type']==1){ + //$order_num=$val['order_number']*($val['closing_price']-$val['deal_price'])-$val['closing_cost']-$val['service_cost']; + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price'])*$face_value; + }else{ + //$order_num=$val['order_number']*($val['deal_price']-$val['closing_price'])-$val['closing_cost']-$val['service_cost']; + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price'])*$face_value; + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['contract_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } +} diff --git a/app/model/PaymentListModel.php b/app/model/PaymentListModel.php new file mode 100644 index 0000000..6fc8026 --- /dev/null +++ b/app/model/PaymentListModel.php @@ -0,0 +1,56 @@ +select(); + if ($list) { + return $list->toArray(); + } else { + return []; + } + } + + public static function getPaymentInfo($where): array + { + $list = self::where($where)->find(); + if ($list) { + return $list->toArray(); + } else { + return []; + } + } + + const BANK = 1; + const IND_PAY = 2; + const MO_PAY = 3; + const HT_PAY = 4; + const XD_PAY = 5; + const QEAE_PAY = 6; + const NICE_PAY = 7; + const CLICK_PAY = 8; + const STAR_PAY = 9; + const TPYE_LIST = [ + self::IND_PAY => 'IND PAY', + self::MO_PAY => 'MO PAY', + self::HT_PAY => 'HT PAY', + self::XD_PAY => 'XD PAY', + self::QEAE_PAY => 'QEAE PAY', + self::NICE_PAY => 'NICE PAY', + self::CLICK_PAY => 'CLICK PAY', + self::STAR_PAY => 'STAR PAY', + ]; + +} \ No newline at end of file diff --git a/app/model/PreBrlStockModel.php b/app/model/PreBrlStockModel.php new file mode 100644 index 0000000..1995f86 --- /dev/null +++ b/app/model/PreBrlStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreEurStockModel.php b/app/model/PreEurStockModel.php new file mode 100644 index 0000000..993bcdb --- /dev/null +++ b/app/model/PreEurStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreFundStockModel.php b/app/model/PreFundStockModel.php new file mode 100644 index 0000000..5c47f0a --- /dev/null +++ b/app/model/PreFundStockModel.php @@ -0,0 +1,118 @@ + '固定收益', + ]; + + public static $stockTypeEnList = [ + self::STOCK_TYPE_ONE => 'FIXED INCOME', //固定收益 + ]; + + public static $openStatusList = [ + self::OPEN_STATUS_NO => '未上市', + self::OPEN_STATUS_HAD => '已上市', + self::OPEN_STATUS_OUT => '退市', + ]; + + public static $openStatusEnList = [ + self::OPEN_STATUS_NO => 'Unlisted', + self::OPEN_STATUS_HAD => 'BE LISTED', + self::OPEN_STATUS_OUT => 'BE DELISTED', + ]; + + public static $cycleTypeList = [ + self::DAY => '天', +// self::MONTH => '月', +// self::YEAR => '年', + ]; + + public static $interestTypeList = [ + self::ONE_TIME_PRINCIPAL_INTEREST => '一次性本息', + ]; + + public function getStockTypeTextAttr($value, $data) + { + $status = PreFundStockModel::$stockTypeList[$data['stock_type']]; + return $status; + } + + public function getStockTypeEnTextAttr($value, $data) + { + $status = PreFundStockModel::$stockTypeEnList[$data['stock_type']]; + return $status; + } + + public function getOpenStatusTextAttr($value, $data) + { + $status = PreFundStockModel::$openStatusList[$data['open_status']]; + return $status; + } + + public function getOpenStatusEnTextAttr($value, $data) + { + $status = PreFundStockModel::$openStatusEnList[$data['open_status']]; + return $status; + } + + public function history() + { + return $this->belongsTo(HistoryFundStockModel::class, 'stock_code', 'stock_code'); + } +} \ No newline at end of file diff --git a/app/model/PreFundStockReferModel.php b/app/model/PreFundStockReferModel.php new file mode 100644 index 0000000..1ace7c1 --- /dev/null +++ b/app/model/PreFundStockReferModel.php @@ -0,0 +1,11 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreGBXStockModel.php b/app/model/PreGBXStockModel.php new file mode 100644 index 0000000..8a083ac --- /dev/null +++ b/app/model/PreGBXStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreHkdStockModel.php b/app/model/PreHkdStockModel.php new file mode 100644 index 0000000..f924bce --- /dev/null +++ b/app/model/PreHkdStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreIdnStockModel.php b/app/model/PreIdnStockModel.php new file mode 100644 index 0000000..e572d47 --- /dev/null +++ b/app/model/PreIdnStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreInStockModel.php b/app/model/PreInStockModel.php new file mode 100644 index 0000000..fff175e --- /dev/null +++ b/app/model/PreInStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreJpStockModel.php b/app/model/PreJpStockModel.php new file mode 100644 index 0000000..ea1256a --- /dev/null +++ b/app/model/PreJpStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreMysStockModel.php b/app/model/PreMysStockModel.php new file mode 100644 index 0000000..c3722ca --- /dev/null +++ b/app/model/PreMysStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreSgdStockModel.php b/app/model/PreSgdStockModel.php new file mode 100644 index 0000000..faf4976 --- /dev/null +++ b/app/model/PreSgdStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreThaStockModel.php b/app/model/PreThaStockModel.php new file mode 100644 index 0000000..9dba43b --- /dev/null +++ b/app/model/PreThaStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/PreUsStockModel.php b/app/model/PreUsStockModel.php new file mode 100644 index 0000000..3c4e664 --- /dev/null +++ b/app/model/PreUsStockModel.php @@ -0,0 +1,67 @@ + 'Common Stock', + self::STOCK_TYPE_PREFERRED => 'Preferred Stock', + ]; +} \ No newline at end of file diff --git a/app/model/RechargeApplyModel.php b/app/model/RechargeApplyModel.php new file mode 100644 index 0000000..6d70326 --- /dev/null +++ b/app/model/RechargeApplyModel.php @@ -0,0 +1,121 @@ + '处理中(待审核)', + self::STATUS_ONE => '充值成功', + self::STATUS_TWO => '充值失败', + ]; + + public static function getUserRecharge(array $data) + { + $where['user_id']=$data['user_id']; + if($data['account_type']>0){ + $where['account_type']=$data['account_type']; + } + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $count= self::where($where)->count(); + $list = self::where($where)->field('account_type,market_amount as recharge_num,status,order_no,recharge_type,recharge_channel,service_fee,create_time') + ->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + }else{ + return [ + 'total'=>$count, + 'list'=>$list->toArray() + ]; + } + } + public static function getUserIsRecharge(array $data) + { + $count= self::where([ + 'user_id'=>$data['user_id'], + 'status'=>1 + ])->count(); + return $count > 0; + } + public static function getUserPayNum(array $data) + { + $count= self::where([ + ['user_id','in',$data], + ['status','=',1] + ])->count('DISTINCT user_id'); + return $count; + } + public static function InsertUserRecharge(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->account_type = $data['account_type']; + $self->recharge_type = $data['recharge_type']; + $self->recharge_channel = $data['recharge_channel']; + $self->recharge_num = $data['recharge_num']; + $self->status = 0; + $self->is_check = 0; + $self->country = $data['country']; + $self->order_no = $data['order_no']; + $self->currency_rate = $data['currency_rate']; + $self->market_amount = $data['market_amount']; + $self->service_fee = $data['service_fee']; + $self->total_amount = $data['total_amount']; + $self->is_online=$data['is_online']; + $self->file_id=$data['file_id']; + + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + public static function getOrderByNo(array $where) + { + $order_info=self::where($where)->find(); + if($order_info){ + return $order_info->toArray(); + }else{ + return []; + } + } + public static function AddUserRecharge(array $data) + { + $self = new self; + return $self->save($data); + } + public static function getOrderInfo($where) + { + $order_info=self::where($where)->find(); + if($order_info){ + return $order_info->toArray(); + }else{ + return []; + } + } + +} \ No newline at end of file diff --git a/app/model/ServiceSettingModel.php b/app/model/ServiceSettingModel.php new file mode 100644 index 0000000..0883a1d --- /dev/null +++ b/app/model/ServiceSettingModel.php @@ -0,0 +1,33 @@ + '邮箱', + self::TYPE_TWO => '跳转地址', + ]; + + public static function getServiceList():array + { + $list = self::where(1)->field('server_name,header_photo,server_link,type')->select(); + if(empty($list)){ + return []; + } + return $list->toArray(); + } + + + +} \ No newline at end of file diff --git a/app/model/StockBlockListModel.php b/app/model/StockBlockListModel.php new file mode 100644 index 0000000..fdf4946 --- /dev/null +++ b/app/model/StockBlockListModel.php @@ -0,0 +1,72 @@ + [self::TAPE_NYSE => 'NYSE', + self::TAPE_NYSE_ARCA => 'NYSE ARCA', + self::TAPE_NASDAQ => 'NASDAQ',], + 4 => [1 => 'IDX'], + 5 => [1 => 'MYX'], + 6 => [1 => 'SET'], + 7 => [ + self::TAPE_BSE => 'BSE', + self::TAPE_NSE => 'NSE', + ], + 9 => [1 => 'SGD'], + 12 => [] + ]; + + + public static $typeList = [ + 3 => '美股', + 4 => '印尼股', + 5 => '马股', + 6 => '泰股', + 7 => '印度股', + 9 => '新加坡股', + 12 => '港股', + 14 => '英股', + 15 => '法股', + 16 => '德股', + 17 => '巴股', + 18 => '日股', + + ]; + public static $typeListEn = [ + 3 => 'US', + 4 => 'IDN', + 5 => 'MYS', + 6 => 'THA', + 7 => 'IN', + 9 => 'SGD', + 12 => 'HKD', + 14 => 'UK', + 15 => 'FUR', + 16 => 'EUR', + 17 => 'BRL', + 18 => 'JPY', + ]; + +} \ No newline at end of file diff --git a/app/model/StockBrlListModel.php b/app/model/StockBrlListModel.php new file mode 100644 index 0000000..e846aff --- /dev/null +++ b/app/model/StockBrlListModel.php @@ -0,0 +1,41 @@ + 'BMFBOVESPA', + // self::TAPE_NSE => 'NSE', + ]; + + const SOURCE_TV='1'; + const SOURCE_ECONOMICTIMES='2'; + const SOURCE_LIST = [ + self::SOURCE_TV => 'TV', + self::SOURCE_ECONOMICTIMES => '交易所', + ]; +} \ No newline at end of file diff --git a/app/model/StockBrlTradeModel.php b/app/model/StockBrlTradeModel.php new file mode 100644 index 0000000..ae2a019 --- /dev/null +++ b/app/model/StockBrlTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockEurListModel.php b/app/model/StockEurListModel.php new file mode 100644 index 0000000..79fc870 --- /dev/null +++ b/app/model/StockEurListModel.php @@ -0,0 +1,41 @@ + 'FWB', + // self::TAPE_NSE => 'NSE', + ]; + + const SOURCE_TV='1'; + const SOURCE_ECONOMICTIMES='2'; + const SOURCE_LIST = [ + self::SOURCE_TV => 'TV', + self::SOURCE_ECONOMICTIMES => '交易所', + ]; +} \ No newline at end of file diff --git a/app/model/StockEurTradeModel.php b/app/model/StockEurTradeModel.php new file mode 100644 index 0000000..2b5862d --- /dev/null +++ b/app/model/StockEurTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockFurListModel.php b/app/model/StockFurListModel.php new file mode 100644 index 0000000..327d6bd --- /dev/null +++ b/app/model/StockFurListModel.php @@ -0,0 +1,41 @@ + 'EURONEXT', + //self::TAPE_NSE => 'NSE', + ]; + + const SOURCE_TV='1'; + const SOURCE_ECONOMICTIMES='2'; + const SOURCE_LIST = [ + self::SOURCE_TV => 'TV', + self::SOURCE_ECONOMICTIMES => '交易所', + ]; +} \ No newline at end of file diff --git a/app/model/StockFurTradeModel.php b/app/model/StockFurTradeModel.php new file mode 100644 index 0000000..28b80f8 --- /dev/null +++ b/app/model/StockFurTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockGBXListModel.php b/app/model/StockGBXListModel.php new file mode 100644 index 0000000..5b3502e --- /dev/null +++ b/app/model/StockGBXListModel.php @@ -0,0 +1,41 @@ + 'LSE', +// self::TAPE_NSE => 'NSE', + ]; + + const SOURCE_TV='1'; + const SOURCE_ECONOMICTIMES='2'; + const SOURCE_LIST = [ + self::SOURCE_TV => 'TV', + self::SOURCE_ECONOMICTIMES => '交易所', + ]; +} \ No newline at end of file diff --git a/app/model/StockGBXTradeModel.php b/app/model/StockGBXTradeModel.php new file mode 100644 index 0000000..31ebd02 --- /dev/null +++ b/app/model/StockGBXTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockHkdListModel.php b/app/model/StockHkdListModel.php new file mode 100644 index 0000000..b7cfcc4 --- /dev/null +++ b/app/model/StockHkdListModel.php @@ -0,0 +1,33 @@ + 'HKEX', + ]; +} \ No newline at end of file diff --git a/app/model/StockHkdTradeModel.php b/app/model/StockHkdTradeModel.php new file mode 100644 index 0000000..4bc6279 --- /dev/null +++ b/app/model/StockHkdTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockIdnListModel.php b/app/model/StockIdnListModel.php new file mode 100644 index 0000000..568013b --- /dev/null +++ b/app/model/StockIdnListModel.php @@ -0,0 +1,33 @@ + 'IDX', + ]; +} \ No newline at end of file diff --git a/app/model/StockIdnTradeModel.php b/app/model/StockIdnTradeModel.php new file mode 100644 index 0000000..4417cd5 --- /dev/null +++ b/app/model/StockIdnTradeModel.php @@ -0,0 +1,143 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } +} \ No newline at end of file diff --git a/app/model/StockInListModel.php b/app/model/StockInListModel.php new file mode 100644 index 0000000..4c7724f --- /dev/null +++ b/app/model/StockInListModel.php @@ -0,0 +1,42 @@ + 'BSE', + self::TAPE_NSE => 'NSE', + ]; + + const SOURCE_TV='1'; + const SOURCE_ECONOMICTIMES='2'; + const SOURCE_LIST = [ + self::SOURCE_TV => 'TV', +// self::SOURCE_ECONOMICTIMES => 'ECONOMICTIMES', + self::SOURCE_ECONOMICTIMES => '交易所', + ]; +} \ No newline at end of file diff --git a/app/model/StockInTradeModel.php b/app/model/StockInTradeModel.php new file mode 100644 index 0000000..3771ebb --- /dev/null +++ b/app/model/StockInTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockIndexModel.php b/app/model/StockIndexModel.php new file mode 100644 index 0000000..0c2a4a2 --- /dev/null +++ b/app/model/StockIndexModel.php @@ -0,0 +1,24 @@ + 'TSE', + self::TAPE_IDD => 'NAG', + self::TAPE_FSE => 'FSE', + self::TAPE_SP => 'SAPSE', + ]; +} \ No newline at end of file diff --git a/app/model/StockJpTradeModel.php b/app/model/StockJpTradeModel.php new file mode 100644 index 0000000..ff341fa --- /dev/null +++ b/app/model/StockJpTradeModel.php @@ -0,0 +1,172 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + + /** + * 获取累计交易手续费 + */ + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockListModel.php b/app/model/StockListModel.php new file mode 100644 index 0000000..6b4104c --- /dev/null +++ b/app/model/StockListModel.php @@ -0,0 +1,69 @@ + 'NYSE', + self::TAPE_NYSE_ARCA => 'NYSEARCA', + self::TAPE_NASDAQ => 'NASDAQ', + ]; + + + public static function getMarketList($data): array + { + $where='status=1'; + if(!empty($data['trade_name'])){ + $where.=" and (trade_name like '".strtoupper($data['trade_name'])."%' or stock_code like '".strtoupper($data['trade_name'])."%')"; + } + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + + $count=self::where($where)->count(); + + $list = self::where($where)->field('trade_name as name,stock_code as code')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function existMarket($trade_name):bool + { + $id=self::where('stock_code',$trade_name)->value('id'); + return $id >0; + } + +} \ No newline at end of file diff --git a/app/model/StockMarketModel.php b/app/model/StockMarketModel.php new file mode 100644 index 0000000..d208bfc --- /dev/null +++ b/app/model/StockMarketModel.php @@ -0,0 +1,222 @@ + '现货', + self::CONTRACT_MARKET => '合约', + self::STOCK_MARKET_USA => '美股', + self::STOCK_MARKET_MG => '马股', + self::STOCK_MARKET_TG => '泰股', + self::STOCK_MARKET_YNG => '印尼股', + self::STOCK_MARKET_IN => '印度股', + self::STOCK_MARKET_HY => '秒合约', + self::STOCK_MARKET_SGD => '新加坡股', + self::STOCK_MARKET_FUND => '基金', + self::STOCK_MARKET_OPTION_IN => '印度期权', + self::STOCK_MARKET_HK => '港股', + self::STOCK_MARKET_UK => '英股', + self::STOCK_MARKET_FUR => '法股', + self::STOCK_MARKET_EUR => '德股', + self::STOCK_MARKET_BRL => '巴西股', + self::STOCK_MARKET_JP => '日股', + self::FOREX_MARKET => '外汇', + ]; + + // 状态 + const STATUS_NO = 1; + const STATUS_OFF = 2; + + // 交易日限制 + const TRADE_DAY_TYPE = [ + '1' => 'T+0', + '2' => 'T+1', + '3' => 'T+2', + '4' => 'T+3', + ]; + + const LEVER_STATUS_ON = 1; // 杠杆状态 开启 + const LEVER_STATUS_OFF = 2; // 杠杆状态 关闭 + + + // 获取费率 + public function getRate($accountType) + { + switch ($accountType) + { + case '3': + // 美股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_USA)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '4': + // 印尼股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_YNG)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '5': + // 马来股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_MG)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '6': + // 泰股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_TG)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '7': + // 印度股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_IN)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '9': + // 新加坡 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_SGD)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '10': + // 基金 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_FUND)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '11': + // 印度期权 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_OPTION_IN)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '12': + // 港股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_HK)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '14': + // 港股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_UK)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '15': + // 港股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_FUR)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '16': + // 港股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_EUR)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '17': + // 巴西股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_BRL)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '18': + // 巴西股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::STOCK_MARKET_JP)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + case '19': + // 巴西股 + $rate = StockMarketModel::where('stock_market_type', StockMarketModel::FOREX_MARKET)->value('rate'); + if(empty($rate) || $rate <= 0){ + $rate = 0; + } + break; + default: + $rate = 1; + break; + } + + return $rate; + } + + // + public function getAllTape(){ + return [ + self::STOCK_MARKET_USA => StockListModel::$tapeList, + self::STOCK_MARKET_MG => StockMysListModel::$tapeList, + self::STOCK_MARKET_TG => StockThaListModel::$tapeList, + self::STOCK_MARKET_YNG => StockIdnListModel::$tapeList, + self::STOCK_MARKET_IN => StockInListModel::$tapeList, + self::STOCK_MARKET_SGD => StockSgdListModel::$tapeList, + self::STOCK_MARKET_HK => StockHkdListModel::$tapeList, + self::STOCK_MARKET_EUR => StockEurListModel::$tapeList, + self::STOCK_MARKET_FUR => StockFurListModel::$tapeList, + self::STOCK_MARKET_BRL => StockBrlListModel::$tapeList, + self::STOCK_MARKET_JP => StockJpListModel::$tapeList, + ]; + } +} \ No newline at end of file diff --git a/app/model/StockMysListModel.php b/app/model/StockMysListModel.php new file mode 100644 index 0000000..53b8275 --- /dev/null +++ b/app/model/StockMysListModel.php @@ -0,0 +1,32 @@ + 'MYX', + ]; +} \ No newline at end of file diff --git a/app/model/StockMysTradeModel.php b/app/model/StockMysTradeModel.php new file mode 100644 index 0000000..363be2f --- /dev/null +++ b/app/model/StockMysTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockOptionInrListModel.php b/app/model/StockOptionInrListModel.php new file mode 100644 index 0000000..00a8ed9 --- /dev/null +++ b/app/model/StockOptionInrListModel.php @@ -0,0 +1,62 @@ + '未启用', + self::STATUS_ON => '已启用', + ]; + + + // 交易所类型 + const BSE = 'BSE'; + const NSE = 'NSE'; + public static $tapeList = [ + self::BSE => 1, + self::NSE => 2, + ]; + + public static $tapeListText = [ + 1 => self::BSE, + 2 => self::NSE, + ]; + + public function getStatusTextAttr($value, $data) + { + $result = StockOptionInrListModel::$statusList[$data['status']]??''; + return $result; + } + + public function getTapeTextAttr($value, $data) + { + $result = StockOptionInrListModel::$tapeListText[$data['tape']]??'BSE'; + return $result; + } +} \ No newline at end of file diff --git a/app/model/StockOptionInrTradeModel.php b/app/model/StockOptionInrTradeModel.php new file mode 100644 index 0000000..c6c5e34 --- /dev/null +++ b/app/model/StockOptionInrTradeModel.php @@ -0,0 +1,171 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('service_cost'); + } + +} \ No newline at end of file diff --git a/app/model/StockPricesSettingModel.php b/app/model/StockPricesSettingModel.php new file mode 100644 index 0000000..ebcf7cb --- /dev/null +++ b/app/model/StockPricesSettingModel.php @@ -0,0 +1,24 @@ + 'SGX', + ]; +} \ No newline at end of file diff --git a/app/model/StockSgdTradeModel.php b/app/model/StockSgdTradeModel.php new file mode 100644 index 0000000..578f05f --- /dev/null +++ b/app/model/StockSgdTradeModel.php @@ -0,0 +1,172 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + + /** + * 获取累计交易手续费 + */ + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockThaListModel.php b/app/model/StockThaListModel.php new file mode 100644 index 0000000..c6b2d2f --- /dev/null +++ b/app/model/StockThaListModel.php @@ -0,0 +1,33 @@ + 'SET', + ]; +} \ No newline at end of file diff --git a/app/model/StockThaTradeModel.php b/app/model/StockThaTradeModel.php new file mode 100644 index 0000000..d6a0401 --- /dev/null +++ b/app/model/StockThaTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/StockTradeModel.php b/app/model/StockTradeModel.php new file mode 100644 index 0000000..00a23fa --- /dev/null +++ b/app/model/StockTradeModel.php @@ -0,0 +1,168 @@ +$user_id, + 'status'=>1, + 'stock_id'=>$stock_id, + 'trade_type'=>$trade_type + ])->field('order_number,deal_price,service_cost')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + $order_num=$val['order_number']*$val['deal_price'] ;//+ $val['service_cost']; + $money+=$order_num; + $num+=$val['order_number']; + } + } + return [ + 'buy_num'=>$num, + 'buy_money'=>$money + ]; + } + public static function getUserEarnestMmoney(int $user_id) + { + $num=self::where([ + 'user_id'=>$user_id, + 'status'=>1 + ])->sum('earnest_money'); + return $num >0 ? $num:0; + } + public static function getUserTradeNum(int $user_id) + { + //查询持仓订单总成本 + $count=self::where([ + ['user_id','=',$user_id], + ['status','>',0] + ])->count(); + return $count>0; + } + public static function getTradeOrderFee(int $user_id) + { + $info=self::where([ + ['user_id','=',$user_id], + ['status','in',[1,3]] + ])->field('sum(service_cost+closing_cost) as fee')->find(); + if(empty($info)){ + return 0; + }else{ + $info=$info->toArray(); + return empty($info['fee']) ? 0 : $info['fee']; + } + } + /** + * 获取累计盈亏 + */ + public static function getTradeOrderDailyNum(int $user_id) + { + $num=0; + //查询持仓订单总成本 + $list=self::where([ + 'user_id'=>$user_id, + 'status'=>3 + ])->field('order_number,closing_price,deal_price,closing_cost,service_cost,trade_type')->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['trade_type']==1){ + $order_num=$val['order_number']*($val['closing_price']-$val['deal_price']); + }else{ + $order_num=$val['order_number']*($val['deal_price']-$val['closing_price']); + } + $num+=$order_num; + } + } + return $num; + } + public static function getTradeList($trade_name,$num) + { + $trade_list=[]; + $list=self::where([ + ['status','in','1,3'], + ['stock_id','=',strtoupper($trade_name)] + ])->field('deal_price,order_number,closing_price,open_time,closing_time,status')->order('trade_id desc')->limit($num)->select(); + if(!empty($list)) { + $list_arr=$list->toArray(); + foreach ($list_arr as $val){ + if($val['status']==1){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + } + if($val['status']==3){ + $trade_data['order_number']=$val['order_number']; + $trade_data['deal_price']=$val['deal_price']; + $trade_data['order_time']=strtotime($val['open_time'])*1000; + $trade_data['trade_type']=1; + array_push($trade_list,$trade_data); + + $sale_data['order_number']=$val['order_number']; + $sale_data['deal_price']=$val['closing_price']; + $sale_data['order_time']=strtotime($val['closing_time'])*1000; + $sale_data['trade_type']=2; + array_push($trade_list,$sale_data); + + } + } + } + return $trade_list; + } + + // 获取 挂单 持仓的订单金额 股票价格 * 股数 之和 也就是 market_money 的和 + public static function getAmountForMargin($user_id) + { + $trade = self::where('status', '=', '1')->where('user_id', $user_id)->field('sum(deal_price * order_number) as amount')->find(); + if(empty($trade)){ + return 0; + } + + $trade = $trade->toArray(); + return $trade['amount']?? 0; + } + + + +} \ No newline at end of file diff --git a/app/model/TradeFeeModel.php b/app/model/TradeFeeModel.php new file mode 100644 index 0000000..8fb1f2f --- /dev/null +++ b/app/model/TradeFeeModel.php @@ -0,0 +1,9 @@ +count(); + $list = self::where('user_id', $data['user_id'])->field("id,true_name,bank_name,bank_card,bank_phone,bank_email,is_default,identity_card,ifsc") + ->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + }else{ + return [ + 'total'=>$count, + 'list'=>$list->toArray() + ]; + } + } + public static function getUserBankInfoById(array $data,$file='*'):array + { + $info=self::where($data)->find(); + if(empty($info)){ + return []; + }else{ + return $info->toArray(); + } + } + public static function delUserBankById(array $data) + { + self::where([ + 'id'=>$data['id'], + 'user_id'=>$data['user_id'], + ])->delete(); + } + public static function InsertUserBank(array $data) + { + $self = new self; + + if($data['is_default']==1){ + $self::updateDefault($data['user_id']); + } + if($data['id']>0){ + $self::where([ + 'id'=>$data['id'], + 'user_id'=>$data['user_id'], + ])->save([ + 'true_name'=>$data['true_name'], + 'identity_card'=>isset($data['identity_card']) ? $data['identity_card']:'', + 'bank_card'=>$data['bank_card'], + 'bank_name'=>$data['bank_name'], + 'bank_email'=>isset($data['bank_email']) ? $data['bank_email']:'', + 'bank_phone'=>isset($data['bank_phone']) ? $data['bank_phone']:'', + 'user_address'=>isset($data['user_address']) ? $data['user_address']:'', + 'bank_address'=>isset($data['bank_address']) ? $data['bank_address']:'', + 'ifsc'=>isset($data['ifsc']) ? $data['ifsc']:'', + 'branch_name'=>$data['branch_name'], + 'branch_phone'=>$data['branch_phone'], + 'bank_code'=>$data['bank_code'], + 'bank_country'=>$data['bank_country'], + 'is_default'=>$data['is_default'], + 'update_time'=>date('Y-m-d H:i:s') + ]); + }else{ + $self->user_id = $data['user_id']; + $self->true_name = $data['true_name']; + $self->bank_card = $data['bank_card']; + $self->bank_name = $data['bank_name']; + if(isset($data['bank_email'])){ + $self->bank_email = $data['bank_email']; + } + if(isset($data['identity_card'])){ + $self->identity_card = $data['identity_card']; + } + if(isset($data['bank_phone'])){ + $self->bank_phone = $data['bank_phone']; + } + if(isset($data['ifsc'])){ + $self->ifsc = $data['ifsc']; + } + if(isset($data['bank_address'])){ + $self->bank_address = $data['bank_address']; + } + if(isset($data['user_address'])){ + $self->user_address = $data['user_address']; + } + $self->bank_code = $data['bank_code']; + $self->bank_country = $data['bank_country']; + $self->is_default = $data['is_default']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + } + } + public static function updateDefault(int $user_id){ + self::where([ + 'user_id'=>$user_id + ])->save([ + 'is_default'=>0, + 'update_time'=>date('Y-m-d H:i:s') + ]); + } + + +} \ No newline at end of file diff --git a/app/model/UserBrlGiveStockOrderModel.php b/app/model/UserBrlGiveStockOrderModel.php new file mode 100644 index 0000000..c7f82e0 --- /dev/null +++ b/app/model/UserBrlGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserBrokerageModel.php b/app/model/UserBrokerageModel.php new file mode 100644 index 0000000..2ef68d1 --- /dev/null +++ b/app/model/UserBrokerageModel.php @@ -0,0 +1,63 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('user_id,back_type,brokerage_num,service_fee,create_time')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + $order_list=$list->toArray() ; + + foreach ($order_list as $key=>$val){ + $res=UserModel::where('user_id',$val['user_id'])->find()->toArray(); + $order_list[$key]['user_no']=$res['user_no']; + } + return [ + 'total'=>$count, + 'list'=>$order_list, + ]; + + } + public static function getUserBrokerageNum(array $where,string $field) + { + $num=self::where($where)->sum($field); + return $num; + } + public static function InsertUserBrokerage(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->level_type = $data['level_type']; + $self->back_type = $data['back_type']; + $self->brokerage_num = $data['brokerage_num']; + $self->service_fee = $data['service_fee']; + $self->create_time = $data['create_time']; + return $self->save(); + } + + +} \ No newline at end of file diff --git a/app/model/UserContractLogModel.php b/app/model/UserContractLogModel.php new file mode 100644 index 0000000..ae2722a --- /dev/null +++ b/app/model/UserContractLogModel.php @@ -0,0 +1,55 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,contract_id as name,change_num,create_time')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->contract_id = $data['contract_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserContractModel.php b/app/model/UserContractModel.php new file mode 100644 index 0000000..c10a3fc --- /dev/null +++ b/app/model/UserContractModel.php @@ -0,0 +1,116 @@ +$data['user_id'], + 'contract_id'=>$contract_id + ])->field('usable_num,frozen_num,contract_id as name')->find(); + if(empty($info)){ + return [ + 'usable_num'=>0, + 'frozen_num'=>0, + 'name'=>$contract_id + ]; + } + return $info->toArray(); + } + public static function getUserContractLock(int $user_id,string $contract_id='USDT'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'contract_id'=>$contract_id + ])->lock(true)->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $user_id; + $info->contract_id = $contract_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserContractList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,contract_id as name')->select(); + if(empty($list)){ + return []; + } + foreach ($list as $key=>$val){ + if($val['name']=='USDT'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=ContractTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=ContractTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + + //获取平仓累计盈亏 + $daily_num=ContractTradeModel::getTradeOrderDailyNum($user_id); + $earnest_money=ContractTradeModel::getUserEarnestMmoney($user_id); + $fee_num=ContractTradeModel::getTradeOrderFee($user_id); + return [ + 'earnest_money'=>$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'list'=>$list->toArray() + ]; + + } + + + public static function InsertUserContract(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->contract_id = $data['contract_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserContract(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserContractSecLogModel.php b/app/model/UserContractSecLogModel.php new file mode 100644 index 0000000..b962b8e --- /dev/null +++ b/app/model/UserContractSecLogModel.php @@ -0,0 +1,55 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,contract_id as name,change_num,create_time')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->contract_id = $data['contract_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserContractSecModel.php b/app/model/UserContractSecModel.php new file mode 100644 index 0000000..ed7c495 --- /dev/null +++ b/app/model/UserContractSecModel.php @@ -0,0 +1,132 @@ +$data['user_id'], + 'contract_id'=>$contract_id + ])->field('usable_num,frozen_num,contract_id as name')->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $data['user_id']; + $info->contract_id = $contract_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserContractLock(int $user_id,string $contract_id='USDT'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'contract_id'=>$contract_id + ])->lock(true)->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $user_id; + $info->contract_id = $contract_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserContractList(int $user_id):array + { + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,contract_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->contract_id = 'USDT'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + + foreach ($list as $key=>$val){ + if($val['name']=='USDT'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=ContractSecTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=ContractSecTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=ContractSecTradeModel::getTradeOrderDailyNum($user_id); + $earnest_money=ContractSecTradeModel::getUserEarnestMmoney($user_id); + $fee_num=ContractSecTradeModel::getTradeOrderFee($user_id); + return [ + 'earnest_money'=>$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'list'=>$list->toArray() + ]; + + } + + + public static function InsertUserContract(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->contract_id = $data['contract_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserContract(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserDigitalLogModel.php b/app/model/UserDigitalLogModel.php new file mode 100644 index 0000000..39675d1 --- /dev/null +++ b/app/model/UserDigitalLogModel.php @@ -0,0 +1,56 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,digital_id as name,change_num,create_time')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->digital_id = $data['digital_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserDigitalModel.php b/app/model/UserDigitalModel.php new file mode 100644 index 0000000..14c64ce --- /dev/null +++ b/app/model/UserDigitalModel.php @@ -0,0 +1,126 @@ +$data['user_id'], + 'digital_id'=>$digital_id + ])->field('usable_num,frozen_num,digital_id as name')->find(); + if(empty($info)){ + return [ + 'usable_num'=>0, + 'frozen_num'=>0, + 'name'=>$digital_id + ]; + } + return $info->toArray(); + } + public static function getUserDigitalLock(int $user_id,string $digital_id='USDT'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'digital_id'=>$digital_id + ])->lock(true)->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $user_id; + $info->digital_id = $digital_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserDigitalList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,digital_id as name')->select(); + if(empty($list)){ + return []; + } + $digital_list=DigitalListModel::getMarketList(['page'=>1,'page_size'=>100],$type=1); + //print_r($digital_list); + foreach ($list as $key=>$val){ + foreach ($digital_list['list'] as $item){ + if($item['name']==$val['name']){ + $list[$key]['logo_link']=$item['logo_link']; + } + } + if($val['name']!='USDT'){ + //买入成本 + $buy_info=DigitalTradeModel::getTradeOrderPrice($user_id,$val['name'],1); + if($buy_info['order_num']>0){ + $buy_price=($buy_info['order_money']/$buy_info['order_num']);//平均买入价 + $list[$key]['buy_price']=$buy_price; + }else{ + $list[$key]['buy_price']=0; + } + //累计盈亏 + $sale_info=DigitalTradeModel::getTradeOrderPrice($user_id,$val['name'],2); + if($sale_info['order_num']>0){ + $sale_price=$sale_info['order_money']/$sale_info['order_num']; + $list[$key]['daily_num']=($sale_price-$buy_price)*$sale_info['order_num']; + }else{ + $list[$key]['daily_num']=0; + } + }else{ + $list[$key]['buy_price']=0; + $list[$key]['daily_num']=0; + } + } + + //获取持仓成本 + //$buy_num=DigitalTradeModel::getTradeOrderBuyNum($user_id); + //获取平仓累计盈亏 + //$daily_num=DigitalTradeModel::getTradeOrderDailyNum($user_id); + $fee_num=DigitalTradeModel::getTradeOrderFee($user_id); + return [ + 'fee_num'=>$fee_num,//手续费 + 'list'=>$list->toArray() + ]; + } + + + public static function InsertUserDigital(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->digital_id = $data['digital_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserDigital(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + +} \ No newline at end of file diff --git a/app/model/UserEurGiveStockOrderModel.php b/app/model/UserEurGiveStockOrderModel.php new file mode 100644 index 0000000..3740a3c --- /dev/null +++ b/app/model/UserEurGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserForexLogModel.php b/app/model/UserForexLogModel.php new file mode 100644 index 0000000..d78efef --- /dev/null +++ b/app/model/UserForexLogModel.php @@ -0,0 +1,55 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,contract_id as name,change_num,create_time')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->contract_id = $data['contract_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserForexModel.php b/app/model/UserForexModel.php new file mode 100644 index 0000000..46633d1 --- /dev/null +++ b/app/model/UserForexModel.php @@ -0,0 +1,116 @@ +$data['user_id'], + 'contract_id'=>$contract_id + ])->field('usable_num,frozen_num,contract_id as name')->find(); + if(empty($info)){ + return [ + 'usable_num'=>0, + 'frozen_num'=>0, + 'name'=>$contract_id + ]; + } + return $info->toArray(); + } + public static function getUserForexLock(int $user_id,string $contract_id='USD'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'contract_id'=>$contract_id + ])->lock(true)->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $user_id; + $info->contract_id = $contract_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserForexList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,contract_id as name')->select(); + if(empty($list)){ + return []; + } + foreach ($list as $key=>$val){ + if($val['name']=='USD'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=ContractTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=ContractTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + + //获取平仓累计盈亏 + $daily_num=ContractTradeModel::getTradeOrderDailyNum($user_id); + $earnest_money=ContractTradeModel::getUserEarnestMmoney($user_id); + $fee_num=ContractTradeModel::getTradeOrderFee($user_id); + return [ + 'earnest_money'=>$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'list'=>$list->toArray() + ]; + + } + + + public static function InsertUserForex(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->contract_id = $data['contract_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserForex(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserFundPreStockOrderModel.php b/app/model/UserFundPreStockOrderModel.php new file mode 100644 index 0000000..dfe5cef --- /dev/null +++ b/app/model/UserFundPreStockOrderModel.php @@ -0,0 +1,53 @@ + 'Having', + self::STATUS_TWO => 'Returning', + self::STATUS_THREE => 'Over', + ]; + + public function getStatusEnTextAttr($value, $data) + { + $status = UserFundPreStockOrderModel::$statusEnList[$data['status']]; + return $status; + } + + public function fund() + { + return $this->hasOne(PreFundStockModel::class, 'id', 'pre_stock_id'); + } + + public function interestArr() + { + return $this->hasMany(UserStockFundInterestReceiptModel::class, 'order_id','id'); + } +} \ No newline at end of file diff --git a/app/model/UserFurGiveStockOrderModel.php b/app/model/UserFurGiveStockOrderModel.php new file mode 100644 index 0000000..a57706d --- /dev/null +++ b/app/model/UserFurGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserGBXGiveStockOrderModel.php b/app/model/UserGBXGiveStockOrderModel.php new file mode 100644 index 0000000..a3911f1 --- /dev/null +++ b/app/model/UserGBXGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserHkdGiveStockOrderModel.php b/app/model/UserHkdGiveStockOrderModel.php new file mode 100644 index 0000000..5bc1816 --- /dev/null +++ b/app/model/UserHkdGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserIdnGiveStockOrderModel.php b/app/model/UserIdnGiveStockOrderModel.php new file mode 100644 index 0000000..71967bb --- /dev/null +++ b/app/model/UserIdnGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserInGiveStockOrderModel.php b/app/model/UserInGiveStockOrderModel.php new file mode 100644 index 0000000..b9bb45e --- /dev/null +++ b/app/model/UserInGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserJpGiveStockOrderModel.php b/app/model/UserJpGiveStockOrderModel.php new file mode 100644 index 0000000..6f97dbe --- /dev/null +++ b/app/model/UserJpGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + /** + * 获取新股申购手续费用 + */ + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserLevelModel.php b/app/model/UserLevelModel.php new file mode 100644 index 0000000..6d3d431 --- /dev/null +++ b/app/model/UserLevelModel.php @@ -0,0 +1,115 @@ +find(); + if(empty($info)){ + return []; + } + return $info->toArray(); + } + public static function getUserLevelList():array + { + + $list = self::where(1)->select(); + if(empty($list)){ + return []; + } + return $list->toArray(); + } + public static function getUserTeamList($data):array + { + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $where=[]; + switch ($data['level_type']){ + case 1: + $where['l.parent_id']=$data['user_id']; + break; + case 2: + $where['l.grandpa_id']=$data['user_id']; + break; + case 3: + $where['l.top_id']=$data['user_id']; + break; + } + + $list=Db::table('bot_user_level l')->field('l.user_id,u.user_no,u.create_time as reg_time') + ->leftjoin('bot_users u','u.user_id=l.user_id') + ->where($where)->select(); + $count=Db::table('bot_user_level l')->field('l.user_id,u.user_no,u.create_time as reg_time') + ->leftjoin('bot_users u','u.user_id=l.user_id') + ->where($where)->count(); + if(!empty($list)){ + $list=$list->toArray(); + foreach ($list as $key=>$val){ + $list[$key]['is_pay']=RechargeApplyModel::getUserIsRecharge($val); + $list[$key]['is_trade']=self::getUserIsTrade($val['user_id']); + } + return [ + 'total'=>$count, + 'list'=>$list, + ]; + }else{ + return []; + } + } + public static function getUserLevelCount(array $where){ + $count=self::where($where)->count(); + return $count; + } + public static function InsertUserLevel(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->parent_id = $data['parent_id']; + $self->grandpa_id = $data['grandpa_id']; + $self->top_id = $data['top_id']; + return $self->save(); + } + public static function getUserIsTrade($user_id){ + $dig_res=DigitalTradeModel::getUserTradeNum($user_id); + if($dig_res){ + return true; + } + $sto_res=StockTradeModel::getUserTradeNum($user_id); + if($sto_res){ + return true; + } + $con_res=ContractTradeModel::getUserTradeNum($user_id); + if($con_res){ + return true; + } + return false; + } + public static function getUsers($data) + { + $list=self::where($data)->field('user_id')->select(); + if(!empty($list)){ + return $list->toArray(); + }else{ + return []; + } + + } + + +} \ No newline at end of file diff --git a/app/model/UserLoanModel.php b/app/model/UserLoanModel.php new file mode 100644 index 0000000..3e18a32 --- /dev/null +++ b/app/model/UserLoanModel.php @@ -0,0 +1,22 @@ +count(); + $list = self::where($data['where'])->page($data['page'],$data['size'])->select(); + if(empty($list)){ + return []; + }else{ + return [ + 'total'=>$count, + 'list'=>$list->toArray() + ]; + } + } + +} \ No newline at end of file diff --git a/app/model/UserLoginLog.php b/app/model/UserLoginLog.php new file mode 100644 index 0000000..4b42f12 --- /dev/null +++ b/app/model/UserLoginLog.php @@ -0,0 +1,40 @@ +user_id = $userId; + $self->device = $device; + $self->ip = $ip; + $self->country = $country; + $self->city = $city; + $self->login_date = $loginDate; + $self->save(); + } + + public static function getLog($userId, $limit=10) + { + $list = self::where('user_id', $userId)->limit($limit)->order('id', 'desc')->select(); + if($list->isEmpty()){ + return []; + } + return $list->toArray(); + } +} \ No newline at end of file diff --git a/app/model/UserMarketModel.php b/app/model/UserMarketModel.php new file mode 100644 index 0000000..8788c83 --- /dev/null +++ b/app/model/UserMarketModel.php @@ -0,0 +1,78 @@ +0){ + $where[]=['market_type','=',$data['market_type']]; + } + if(!empty($data['trade_name'])){ + $where[]=['trade_name','like',$data['trade_name'].'%']; + } + $count=self::where($where)->count(); + $list = self::where($where)->field('trade_name as code,market_name as name,market_type,trade_numeric_code')->page($data['page'],$data['page_size'])->order('id desc')->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function checkExistMarket(array $data) : int + { + $id = self::where([ + 'user_id'=>$data['user_id'], + 'market_type'=>$data['market_type'], + 'trade_name'=>$data['trade_name'] + ])->value('id'); + + if(empty($id)){ + return 0; + }else{ + return $id; + } + } + public static function insertUserMarket(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->trade_name = $data['trade_name']; + $self->trade_numeric_code = $data['trade_numeric_code']; + $self->market_name = $data['market_name']; + $self->market_type = $data['market_type']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + return $self->id; + } + public static function delUserMarket(int $id){ + self::where("id",$id)->delete(); + } + + + +} \ No newline at end of file diff --git a/app/model/UserModel.php b/app/model/UserModel.php new file mode 100644 index 0000000..3b3d65b --- /dev/null +++ b/app/model/UserModel.php @@ -0,0 +1,291 @@ + '正常', + self::STATUS_FORBID => '禁止登录', + self::STATUS_BLACK => '黑名单', + ]; + + const IS_TEST_USER_NO = 1; // 正常用户 + const IS_TEST_USER_YES = 2; // 测试用户 + + public static $isTestUserMap = [ + self::IS_TEST_USER_NO => '正常用户', + self::IS_TEST_USER_YES => '测试用户' + ]; + + const LEVER_STATUS_NO = 1; // 未申请 + const LEVER_STATUS_APPLY = 2; // 申请中 + const LEVER_STATUS_PASSED = 3; // 通过 + const LEVER_STATUS_FAIL = 4; // 拒绝 + + /** + * @desc 邮箱是否已经被注册 + * @param $email + * @return bool + * @throws \think\db\exception\DbException + */ + public static function checkEmailExists($email): bool + { + $count = self::where('email', $email)->count(); + return $count > 0; + } + + /** + * @desc 判断手机号是否已经被注册 + * @param $phone + * @return bool + * @throws \think\db\exception\DbException + */ + public static function checkPhoneExists($phone): bool + { + $count = self::where('phone_number', $phone)->count(); + return $count > 0; + } + + /** + * @desc 根据邮箱获取用户id + * @param $email + * @return int|mixed + */ + public static function getUserIdByEmail($email) + { + $userId = self::where('email', $email)->value('user_id'); + return $userId ?? 0; + } + + /** + * @desc 根据用户id获取登陆密码 + * @param $id + * @return mixed + */ + public static function getPasswordById($id) + { + return self::where('user_id', $id)->value('login_password'); + } + + /** + * @desc 根据用户id获取邮箱 + * @param $id + * @return mixed + */ + public static function getEmailById($id) + { + return self::where('user_id', $id)->value('email'); + } + + /** + * @desc 根据国家码和手机号获取用户id + * @param $nation + * @param $phone + * @return int|mixed + */ + public static function getUserIdByNationAndPhone($nation, $phone) + { + $userId = self::where('country_code', $nation) + ->where('phone_number', $phone) + ->value('user_id'); + return $userId ?? 0; + } + /** + * @desc 根据用户id 查询指定字段 + * @param $fields + * @param $userId + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public static function getFieldsByUserId($fields, $userId): array + { + $self = self::where('user_id', $userId)->field($fields)->find(); + if(empty($self)){ + return []; + } + return $self->toArray(); + } + /** + * @desc 获取邀请码用户 + * @param $inviteCode + * @return array + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public static function getUserByInviteCode($inviteCode): array + { + $self = self::where('invite_code', $inviteCode)->field('user_id')->find(); + + if(empty($self)){ + return []; + } + return $self->toArray(); + } + + public static function updateFieldsByUserId($fields, $userId) + { + $self = self::where('user_id', $userId)->find(); + foreach ($fields as $key=>$value) { + $self->$key = $value; + } + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + } + + /** + * @desc 更新登陆密码 + * @param $password + * @param $userId + * @return void + */ + public static function updatePassword($password, $salt, $userId) + { + self::update(['login_password' => $password, 'salt' => $salt], ['user_id' => $userId]); + } + + /** + * @desc 邮箱用户注册 + * + * @param $email + * @param $userNo + * @param $inviteCode + * @param $parentId + * @param $password + * @param $ip + * @return int + */ + public static function emailRegister($email, $userNo, $inviteCode, $parentId, $password, $ip, $salt, $isTestUser, $agentId): int + { + $self = new self; + $self->email = $email; + $self->user_no = $userNo; + $self->invite_code = $inviteCode; + $self->parent_id = $parentId; + $self->agent_id = $agentId; + $self->login_password = $password; + $self->salt = $salt; + $self->reg_ip = $ip; + $self->is_test_user = $isTestUser; + + $self->nick_name = 'user_'.explode('@', $email)[0]; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + + // 查询父级 + $parentIds = ''; + $originUserId = 0; + if($parentId > 0){ + $parentUser = self::where('user_id', $parentId)->findOrEmpty(); + if($parentUser){ + $parentIds = $parentUser['parent_ids']? $parentUser['parent_ids'].','.$parentId : $parentId; + // 如果祖先id = 0 说明这个父级就是祖先id + $originUserId = $parentUser['origin_user_id'] == 0? $parentId : $parentUser['origin_user_id']; + } + } + + $self->origin_user_id = $originUserId; + $self->parent_ids = $parentIds; + + $self->save(); + return $self->user_id; + } + + /** + * @desc 手机号注册 + * @param $nation + * @param $phone + * @param $userNo + * @param $inviteCode + * @param $parentId + * @param $password + * @param $ip + * @param $salt + * @return int + */ + public static function phoneRegister($nation, $phone, $userNo, $inviteCode, $parentId, $password, $ip, $salt, $isTestUser, $agentId): int + { + $self = new self; + $self->country_code = $nation; + $self->phone_number = $phone; + $self->user_no = $userNo; + $self->invite_code = $inviteCode; + $self->parent_id = $parentId; + $self->agent_id = $agentId; + $self->login_password = $password; + $self->salt = $salt; + $self->reg_ip = $ip; + $self->is_test_user = $isTestUser; + + $name = 'user_'.substr($phone, -4); + $self->nick_name = $name; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + + // 查询父级 + $parentIds = ''; + $originUserId = 0; + if($parentId > 0){ + $parentUser = self::where('user_id', $parentId)->findOrEmpty(); + if($parentUser){ + $parentIds = $parentUser['parent_ids']? $parentUser['parent_ids'].','.$parentId : $parentId; + // 如果祖先id = 0 说明这个父级就是祖先id + $originUserId = $parentUser['origin_user_id'] == 0? $parentId : $parentUser['origin_user_id']; + } + } + + $self->origin_user_id = $originUserId; + $self->parent_ids = $parentIds; + + + $self->save(); + return $self->user_id; + } + + /** + * @desc 设置交易密码 + * @param $password + * @param $salt + * @param $userId + * @return void + */ + public static function setPayPassword($password, $salt, $userId) + { + self::update(['trade_password' => $password, 'salt' => $salt], ['user_id' => $userId]); + } +} \ No newline at end of file diff --git a/app/model/UserMoneyLogModel.php b/app/model/UserMoneyLogModel.php new file mode 100644 index 0000000..21baf93 --- /dev/null +++ b/app/model/UserMoneyLogModel.php @@ -0,0 +1,59 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + if(isset($data['martket_type'])){ + $self->martket_type = $data['martket_type']; + } + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } +} \ No newline at end of file diff --git a/app/model/UserMoneyModel.php b/app/model/UserMoneyModel.php new file mode 100644 index 0000000..eeb9303 --- /dev/null +++ b/app/model/UserMoneyModel.php @@ -0,0 +1,81 @@ +field('usable_num,frozen_num,stock_id as name')->select(); + $result=[]; + if(!empty($res)){ + $result=$res->toArray(); + } + if(empty($result)){ + $info = new self; + $info->user_id = $user_id; + $info->stock_id = 'USD'; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + $result=$info->toArray(); + } + return $result; + } + public static function getUserUSDByUserId(array $data):array + { + $info = self::where([ + 'user_id'=>$data['user_id'], + 'stock_id'=>'USD' + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = 'USD'; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function InsertUserMoneyk(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function getUserUSDLock(int $user_id,string $stock_id='USD'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function updateUserUSD(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + +} \ No newline at end of file diff --git a/app/model/UserMysGiveStockOrderModel.php b/app/model/UserMysGiveStockOrderModel.php new file mode 100644 index 0000000..996125b --- /dev/null +++ b/app/model/UserMysGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserSgdGiveStockOrderModel.php b/app/model/UserSgdGiveStockOrderModel.php new file mode 100644 index 0000000..12bfa76 --- /dev/null +++ b/app/model/UserSgdGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + /** + * 获取新股申购手续费用 + */ + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserStockBlockLogModel.php b/app/model/UserStockBlockLogModel.php new file mode 100644 index 0000000..3725074 --- /dev/null +++ b/app/model/UserStockBlockLogModel.php @@ -0,0 +1,54 @@ +count(); +// if($data['page']<1){ +// $data['page']=1; +// } +// if($data['page_size']<1){ +// $data['page_size']=10; +// } +// $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); +// if(empty($list)){ +// return []; +// } +// return [ +// 'total'=>$count, +// 'list'=>$list->toArray(), +// ]; +// } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + +} \ No newline at end of file diff --git a/app/model/UserStockBlockOrderModel.php b/app/model/UserStockBlockOrderModel.php new file mode 100644 index 0000000..5b0f183 --- /dev/null +++ b/app/model/UserStockBlockOrderModel.php @@ -0,0 +1,52 @@ + '挂单(委托)', + self::STATUS_ONE => '持仓订单', + self::STATUS_TWO => '已撤单', + self::STATUS_THREE => '完成订单', + ]; + + public static $typeList = [ + 3 => '美股', + 4 => '印尼股', + 5 => '马股', + 6 => '泰股', + 7 => '印度股', + 9 => '新加坡股', + 12 => '港股', + 14 => '英股', + 15 => '法股', + 16 => '德股', + ]; + +} \ No newline at end of file diff --git a/app/model/UserStockBrlLogModel.php b/app/model/UserStockBrlLogModel.php new file mode 100644 index 0000000..bd82443 --- /dev/null +++ b/app/model/UserStockBrlLogModel.php @@ -0,0 +1,55 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } +} \ No newline at end of file diff --git a/app/model/UserStockBrlModel.php b/app/model/UserStockBrlModel.php new file mode 100644 index 0000000..3c187a9 --- /dev/null +++ b/app/model/UserStockBrlModel.php @@ -0,0 +1,135 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='BRL'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'BRL'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='BRL'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockMysTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockMysTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + $fee_num=StockMysTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserMysPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockEurLogModel.php b/app/model/UserStockEurLogModel.php new file mode 100644 index 0000000..bb89fbc --- /dev/null +++ b/app/model/UserStockEurLogModel.php @@ -0,0 +1,55 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } +} \ No newline at end of file diff --git a/app/model/UserStockEurModel.php b/app/model/UserStockEurModel.php new file mode 100644 index 0000000..70f6193 --- /dev/null +++ b/app/model/UserStockEurModel.php @@ -0,0 +1,135 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='EUR'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'EUR'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='EUR'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockMysTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockMysTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + $fee_num=StockMysTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserMysPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockFundInterestReceiptModel.php b/app/model/UserStockFundInterestReceiptModel.php new file mode 100644 index 0000000..692abb4 --- /dev/null +++ b/app/model/UserStockFundInterestReceiptModel.php @@ -0,0 +1,24 @@ + '待返息', + self::STATUS_TWO => '已结束', + ]; + + public function getStatusTextAttr($value, $data) + { + $status = UserStockFundInterestReceiptModel::$statusList[$data['status']]; + return $status; + } +} diff --git a/app/model/UserStockFundLogModel.php b/app/model/UserStockFundLogModel.php new file mode 100644 index 0000000..4a8ce4b --- /dev/null +++ b/app/model/UserStockFundLogModel.php @@ -0,0 +1,56 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockFundModel.php b/app/model/UserStockFundModel.php new file mode 100644 index 0000000..9266928 --- /dev/null +++ b/app/model/UserStockFundModel.php @@ -0,0 +1,133 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='USD'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'USD'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='USD'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + } + + } + //获取平仓累计盈亏 + $daily_num=0;//StockThaTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockThaTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + $fee_num=0;//StockThaTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = 0;//UserThaPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockFurLogModel.php b/app/model/UserStockFurLogModel.php new file mode 100644 index 0000000..d4172d1 --- /dev/null +++ b/app/model/UserStockFurLogModel.php @@ -0,0 +1,55 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } +} \ No newline at end of file diff --git a/app/model/UserStockFurModel.php b/app/model/UserStockFurModel.php new file mode 100644 index 0000000..5f25bb9 --- /dev/null +++ b/app/model/UserStockFurModel.php @@ -0,0 +1,135 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='EUR'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'EUR'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='EUR'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockMysTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockMysTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + $fee_num=StockMysTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserMysPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockGBXLogModel.php b/app/model/UserStockGBXLogModel.php new file mode 100644 index 0000000..fa65122 --- /dev/null +++ b/app/model/UserStockGBXLogModel.php @@ -0,0 +1,55 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } +} \ No newline at end of file diff --git a/app/model/UserStockGBXModel.php b/app/model/UserStockGBXModel.php new file mode 100644 index 0000000..eb53c43 --- /dev/null +++ b/app/model/UserStockGBXModel.php @@ -0,0 +1,135 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='GBX'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'GBX'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='GBX'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockMysTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockMysTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + $fee_num=StockMysTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserMysPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockHkdLogModel.php b/app/model/UserStockHkdLogModel.php new file mode 100644 index 0000000..3a2d6f1 --- /dev/null +++ b/app/model/UserStockHkdLogModel.php @@ -0,0 +1,54 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + +} \ No newline at end of file diff --git a/app/model/UserStockHkdModel.php b/app/model/UserStockHkdModel.php new file mode 100644 index 0000000..c0784bf --- /dev/null +++ b/app/model/UserStockHkdModel.php @@ -0,0 +1,137 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='HKD'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'HKD'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='SGD'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockHkdTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockHkdTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockHkdTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockIdnTradeModel::getUserEarnestMmoney($user_id); +// $earnest_money=StockIdnTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + + $fee_num=StockHkdTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserHkdPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockIdnLogModel.php b/app/model/UserStockIdnLogModel.php new file mode 100644 index 0000000..433a82e --- /dev/null +++ b/app/model/UserStockIdnLogModel.php @@ -0,0 +1,55 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } +} \ No newline at end of file diff --git a/app/model/UserStockIdnModel.php b/app/model/UserStockIdnModel.php new file mode 100644 index 0000000..ab2a7db --- /dev/null +++ b/app/model/UserStockIdnModel.php @@ -0,0 +1,138 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + + // 印尼股票 + public static function getUserStockLock(int $user_id,string $stock_id='IDR'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'IDR'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='IDR'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockIdnTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockIdnTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockIdnTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockIdnTradeModel::getUserEarnestMmoney($user_id); +// $earnest_money=StockIdnTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + + $fee_num=StockIdnTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserIdnPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } +} \ No newline at end of file diff --git a/app/model/UserStockInLogModel.php b/app/model/UserStockInLogModel.php new file mode 100644 index 0000000..35ae476 --- /dev/null +++ b/app/model/UserStockInLogModel.php @@ -0,0 +1,57 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockInModel.php b/app/model/UserStockInModel.php new file mode 100644 index 0000000..afbf470 --- /dev/null +++ b/app/model/UserStockInModel.php @@ -0,0 +1,135 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='INR'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'INR'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='INR'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockInTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockInTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockInTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockMysTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + $fee_num=StockInTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserInPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockJpLogModel.php b/app/model/UserStockJpLogModel.php new file mode 100644 index 0000000..d92e4b4 --- /dev/null +++ b/app/model/UserStockJpLogModel.php @@ -0,0 +1,56 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockJpModel.php b/app/model/UserStockJpModel.php new file mode 100644 index 0000000..2f2a5cd --- /dev/null +++ b/app/model/UserStockJpModel.php @@ -0,0 +1,138 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + + // 印尼股票 + public static function getUserStockLock(int $user_id,string $stock_id='JPY'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'JPY'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='JOY'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockJpTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockJpTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockJpTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockIdnTradeModel::getUserEarnestMmoney($user_id); +// $earnest_money=StockIdnTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + + $fee_num=StockJpTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserJpPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } +} \ No newline at end of file diff --git a/app/model/UserStockLogModel.php b/app/model/UserStockLogModel.php new file mode 100644 index 0000000..f8ab421 --- /dev/null +++ b/app/model/UserStockLogModel.php @@ -0,0 +1,57 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockModel.php b/app/model/UserStockModel.php new file mode 100644 index 0000000..b787d49 --- /dev/null +++ b/app/model/UserStockModel.php @@ -0,0 +1,116 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + return []; + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='USD'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if(empty($list)){ + return []; + } + foreach ($list as $key=>$val){ + if($val['name']=='USD'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + $fee_num=StockTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserUsPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockMysLogModel.php b/app/model/UserStockMysLogModel.php new file mode 100644 index 0000000..5a3f6e1 --- /dev/null +++ b/app/model/UserStockMysLogModel.php @@ -0,0 +1,57 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockMysModel.php b/app/model/UserStockMysModel.php new file mode 100644 index 0000000..87d8eaa --- /dev/null +++ b/app/model/UserStockMysModel.php @@ -0,0 +1,137 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='MYR'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'MYR'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='MYR'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockMysTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + $numeric_code=StockMysListModel::where('stock_code',$val['name'])->value('numeric_code'); + $list[$key]['numeric_code']=empty($numeric_code) ? 0: $numeric_code; + + } + //获取平仓累计盈亏 + $daily_num=StockMysTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockMysTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + $fee_num=StockMysTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserMysPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockOptionInrLogModel.php b/app/model/UserStockOptionInrLogModel.php new file mode 100644 index 0000000..2c1b19d --- /dev/null +++ b/app/model/UserStockOptionInrLogModel.php @@ -0,0 +1,56 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockOptionInrModel.php b/app/model/UserStockOptionInrModel.php new file mode 100644 index 0000000..e7e7b01 --- /dev/null +++ b/app/model/UserStockOptionInrModel.php @@ -0,0 +1,138 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='INR'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'INR'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='INR'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockOptionInrTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockOptionInrTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockOptionInrTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockThaTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + // 获取新股申购的手续费 + $fee_num=StockOptionInrTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = StockOptionInrTradeModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockSgdLogModel.php b/app/model/UserStockSgdLogModel.php new file mode 100644 index 0000000..106020e --- /dev/null +++ b/app/model/UserStockSgdLogModel.php @@ -0,0 +1,56 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockSgdModel.php b/app/model/UserStockSgdModel.php new file mode 100644 index 0000000..ed738a3 --- /dev/null +++ b/app/model/UserStockSgdModel.php @@ -0,0 +1,138 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + + // 印尼股票 + public static function getUserStockLock(int $user_id,string $stock_id='SGD'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'SGD'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='SGD'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockSgdTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockSgdTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockSgdTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockIdnTradeModel::getUserEarnestMmoney($user_id); +// $earnest_money=StockIdnTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + + $fee_num=StockSgdTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserSgdPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } +} \ No newline at end of file diff --git a/app/model/UserStockThaLogModel.php b/app/model/UserStockThaLogModel.php new file mode 100644 index 0000000..81d4b3a --- /dev/null +++ b/app/model/UserStockThaLogModel.php @@ -0,0 +1,56 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + $list = self::where($where)->field('change_type,stock_id as name,change_num,create_time,order_id')->order('id desc')->page($data['page'],$data['page_size'])->select(); + + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserBalanceLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->change_type = $data['change_type']; + $self->change_num = $data['change_num']; + if(isset($data['order_id'])){ + $self->order_id = $data['order_id']; + } + $self->before_num = $data['before_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserStockThaModel.php b/app/model/UserStockThaModel.php new file mode 100644 index 0000000..27ded7f --- /dev/null +++ b/app/model/UserStockThaModel.php @@ -0,0 +1,137 @@ +$data['user_id'], + 'stock_id'=>$stock_id + ])->field('usable_num,frozen_num,stock_id as name')->find(); + if(empty($info)){ + $info = new self; + $info->user_id = $data['user_id']; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockLock(int $user_id,string $stock_id='THB'):array + { + $info = self::where([ + 'user_id'=>$user_id, + 'stock_id'=>$stock_id + ])->lock(true)->find(); + if(empty($info)){ + // 如果没有则创建 + $info = new self; + $info->user_id = $user_id; + $info->stock_id = $stock_id; + $info->usable_num = 0; + $info->frozen_num = 0; + $info->create_time = date('Y-m-d H:i:s'); + $info->update_time = date('Y-m-d H:i:s'); + $info->save(); + } + return $info->toArray(); + } + public static function getUserStockList(int $user_id):array + { + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + if($list->isEmpty()){ + $self = new self; + $self->user_id = $user_id; + $self->stock_id = 'THB'; + $self->usable_num = '0'; + $self->frozen_num = '0'; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + + $list = self::where([ + 'user_id'=>$user_id, + ])->field('usable_num,frozen_num,stock_id as name')->select(); + } + foreach ($list as $key=>$val){ + if($val['name']=='THB'){ + $list[$key]['buy_up']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + $list[$key]['buy_down']=[ + 'buy_num'=>0, + 'buy_money'=>0 + ]; + }else{ + //获取持仓成本 + $list[$key]['buy_up']=StockThaTradeModel::getTradeOrderBuyNum($user_id,$val['name'],1); + $list[$key]['buy_down']=StockThaTradeModel::getTradeOrderBuyNum($user_id,$val['name'],2); + } + + } + //获取平仓累计盈亏 + $daily_num=StockThaTradeModel::getTradeOrderDailyNum($user_id); + //$earnest_money=StockTradeModel::getUserEarnestMmoney($user_id); + // 保证金 挂单 和 持仓的订单金额 +// $earnest_money=StockThaTradeModel::getAmountForMargin($user_id); + $earnest_money=0; + $fee_num=StockThaTradeModel::getTradeOrderFee($user_id); + // 获取新股申购的手续费 + $pre_fee = UserThaPreStockOrderModel::getRealFee($user_id); + return [ + 'earnest_money'=>(float)$earnest_money,//保证金 + 'daily_num'=>$daily_num,//累计盈亏 + 'fee_num'=>$fee_num,//累计盈亏 + 'pre_fee' => $pre_fee, // 新股手续费 + 'sum_fee' => bcadd($fee_num, $pre_fee, 4), + 'list'=>$list->toArray() + ]; + } + + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->stock_id = $data['stock_id']; + $self->usable_num = $data['usable_num']; + $self->frozen_num = $data['frozen_num']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + public static function updateUserStock(array $update_data,array $where) + { + $update_data['update_time']=date('Y-m-d H:i:s'); + $res=self::where($where)->save($update_data); + //echo self::where($where)->getLastSql(); + return $res; + } + + + + +} \ No newline at end of file diff --git a/app/model/UserThaGiveStockOrderModel.php b/app/model/UserThaGiveStockOrderModel.php new file mode 100644 index 0000000..6c75611 --- /dev/null +++ b/app/model/UserThaGiveStockOrderModel.php @@ -0,0 +1,26 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserTransferModel.php b/app/model/UserTransferModel.php new file mode 100644 index 0000000..71faf24 --- /dev/null +++ b/app/model/UserTransferModel.php @@ -0,0 +1,60 @@ +count(); + if($data['page']<1){ + $data['page']=1; + } + if($data['page_size']<1){ + $data['page_size']=10; + } + + $list = self::where($where)->order('tran_id desc')->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + } + return [ + 'total'=>$count, + 'list'=>$list->toArray(), + ]; + } + public static function InsertUserStock(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->from_account = $data['from_account']; + $self->to_account = $data['to_account']; + $self->from_num = $data['from_num']; + $self->to_num = $data['to_num']; + $self->from_account_rate = $data['from_account_rate']; + $self->to_account_rate = $data['to_account_rate']; + $self->status = $data['status']; + $self->order_sn = $data['order_sn']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/model/UserUsGiveStockOrderModel.php b/app/model/UserUsGiveStockOrderModel.php new file mode 100644 index 0000000..e469598 --- /dev/null +++ b/app/model/UserUsGiveStockOrderModel.php @@ -0,0 +1,32 @@ +hasOne(UserModel::class,'user_id','user_id'); + } +} \ No newline at end of file diff --git a/app/model/UserUsPreStockOrderModel.php b/app/model/UserUsPreStockOrderModel.php new file mode 100644 index 0000000..09a0dfb --- /dev/null +++ b/app/model/UserUsPreStockOrderModel.php @@ -0,0 +1,55 @@ + '申购中', + self::STATUS_SIGNING => '中签',//'已签名', + self::STATUS_SIGNED => '已上市', + self::STATUS_UNSIGNED => '未中签', + self::STATUS_POST_PAY => '申购中(待支付)', + self::STATUS_POST_PAY_BACK => '已上市(未支付)', + self::STATUS_REFUND => '订单退款', + self::STATUS_CLOSED => '订单关闭', + ]; + + const PAY_TYPE_ONE = 1;//正常支付 + const PAY_TYPE_TWO = 2;//后支付 + + public static function getRealFee($userId) + { + return self::where('user_id', $userId)->sum('get_fee'); + } +} \ No newline at end of file diff --git a/app/model/UserVerifyLogModel.php b/app/model/UserVerifyLogModel.php new file mode 100644 index 0000000..1d8492f --- /dev/null +++ b/app/model/UserVerifyLogModel.php @@ -0,0 +1,26 @@ +count(); + $list = self::where($where)->field("adr_id as id,user_id,wallet_type,wallet_address,is_default,remark") + ->page($data['page'],$data['page_size'])->select(); + if(empty($list)){ + return []; + }else{ + return [ + 'total'=>$count, + 'list'=>$list->toArray() + ]; + } + } + public static function getUserWalletInfoById(array $data):array + { + $info=self::where($data)->field("adr_id as id,user_id,wallet_type,wallet_address,is_default,remark")->find(); + if(empty($info)){ + return []; + }else{ + return $info->toArray(); + } + } + public static function delUserWalletById(array $data) + { + self::where([ + 'adr_id'=>$data['adr_id'], + 'user_id'=>$data['user_id'], + ])->delete(); + } + public static function InsertUserWallet(array $data) + { + $self = new self; + if($data['adr_id']>0){ + $self::where([ + 'adr_id'=>$data['adr_id'], + 'user_id'=>$data['user_id'], + ])->save([ + 'wallet_type'=>$data['wallet_type'], + 'wallet_address'=>$data['wallet_address'], + 'remark'=>$data['remark'], + 'is_default'=>$data['is_default'], + 'update_time'=>date('Y-m-d H:i:s') + ]); + }else{ + $self->user_id = $data['user_id']; + $self->wallet_type = $data['wallet_type']; + $self->wallet_address = $data['wallet_address']; + $self->remark = $data['remark']; + $self->is_default = $data['is_default']; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + $self->save(); + } + } + public static function updateDefault(int $user_id){ + self::where([ + 'user_id'=>$user_id + ])->save([ + 'is_default'=>0, + 'update_time'=>date('Y-m-d H:i:s') + ]); + } + +} \ No newline at end of file diff --git a/app/model/UserWithdrawalModel.php b/app/model/UserWithdrawalModel.php new file mode 100644 index 0000000..63f7fb6 --- /dev/null +++ b/app/model/UserWithdrawalModel.php @@ -0,0 +1,100 @@ + '处理中', + self::STATUS_ONE => '已审核', + self::STATUS_TWO => '已拒绝', + self::STATUS_THREE => '支付中', + self::STATUS_FOUR => '支付成功', + self::STATUS_FIVE => '用户取消', + ]; + + public static function getUserDrawalList(array $data) + { + $where['user_id'] = $data['user_id']; + if ($data['account_type'] > 0) { + $where['account_type'] = $data['account_type']; + } + if ($data['page'] < 1) { + $data['page'] = 1; + } + if ($data['page_size'] < 1) { + $data['page_size'] = 10; + } + $count = self::where($where)->count(); + $list = self::where($where)->field('account_type,order_no,service_fee,total_amount as apply_num,apply_type,pay_info,status,beizhu,create_time') + ->page($data['page'], $data['page_size'])->order('id', 'desc')->select(); + + if (empty($list)) { + return []; + } else { + return [ + 'total' => $count, + 'list' => $list->toArray() + ]; + } + + } + + public static function InsertUserDrawalLog(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->order_no = $data['order_no']; + $self->account_type = $data['account_type']; + $self->service_fee = $data['service_fee']; + $self->apply_num = $data['apply_num']; + $self->apply_type = $data['apply_type']; + $self->pay_info = $data['pay_info']; + $self->status = 0; + $self->drawal_type = $data['drawal_type']; + $self->country = $data['country']; + $self->currency_rate = $data['currency_rate']; + $self->total_amount = $data['total_amount']; + $self->market_amount = $data['market_amount']; + $self->deal_admin_id = 0; + $self->create_time = date('Y-m-d H:i:s'); + $self->update_time = date('Y-m-d H:i:s'); + return $self->save(); + } + + public static function getUserDrawalInfo(array $where) + { + $info = self::where($where)->find(); + if ($info) { + return $info->toArray(); + } else { + return []; + } + } + + +} \ No newline at end of file diff --git a/app/model/VoteModel.php b/app/model/VoteModel.php new file mode 100644 index 0000000..a7710b5 --- /dev/null +++ b/app/model/VoteModel.php @@ -0,0 +1,11 @@ +field('wallet_address,wallet_type')->find(); + if(empty($list)){ + $wallet_info=self::where([ + 'user_id'=>0, + 'wallet_type'=>$data['wallet_type'] + ])->order('id','asc')->find(); + if($wallet_info){ + $wallet_info=$wallet_info->toArray(); + self::where('id',$wallet_info['id'])->update([ + 'user_id'=>$data['user_id'] + ]); + } + $list=$wallet_info; + }else{ + $list=$list->toArray(); + } + return $list; + } + public static function getUidByWallet(array $data) + { + $info=self::where($data)->find(); + if(!empty($info)){ + $wallet_info=$info->toArray(); + return $wallet_info['user_id']; + }else{ + return ''; + } + } + public static function getUserWalletAddress(array $data) + { + $info=self::where($data)->find(); + if(!empty($info)){ + $wallet_info=$info->toArray(); + return $wallet_info['wallet_address']; + }else{ + return ''; + } + } + public static function InsertUserWalletAddress(array $data) + { + $self = new self; + $self->user_id = $data['user_id']; + $self->wallet_address = $data['wallet_address']; + $self->wallet_type = $data['wallet_type']; + $self->create_time = date('Y-m-d H:i:s'); + $self->save(); + } + + + + +} \ No newline at end of file diff --git a/app/provider.php b/app/provider.php new file mode 100644 index 0000000..f50c367 --- /dev/null +++ b/app/provider.php @@ -0,0 +1,9 @@ + Request::class, + 'think\exception\Handle' => ExceptionHandle::class, +]; diff --git a/app/service.php b/app/service.php new file mode 100644 index 0000000..f08a935 --- /dev/null +++ b/app/service.php @@ -0,0 +1,9 @@ + + + + + sorry + + +There have been some issues with the service. If you need to use it, please contact customer service. + + \ No newline at end of file diff --git a/app/utility/Base64Utility.php b/app/utility/Base64Utility.php new file mode 100644 index 0000000..1fd14f5 --- /dev/null +++ b/app/utility/Base64Utility.php @@ -0,0 +1,36 @@ + '+' + * '_' -> '/' + * The remainder of the string length %4, supplemented with '=' + * @param base64 $string + */ + public static function Decode($string) { + $data = str_replace(array('-','_'),array('+','/'),$string); + $mod4 = strlen($data) % 4; + if ($mod4) { + $data .= substr('====', $mod4); + } + return base64_decode($data); + } + + /** + * URL base64 encoding + * '+' -> '-' + * '/' -> '_' + * '=' -> '' + * @param raw $string + */ + public static function Encode($string) { + $data = base64_encode($string); + $data = str_replace(array('+','/','='),array('-','_',''),$data); + return $data; + } +} \ No newline at end of file diff --git a/app/utility/BusinessLog.php b/app/utility/BusinessLog.php new file mode 100644 index 0000000..edf59da --- /dev/null +++ b/app/utility/BusinessLog.php @@ -0,0 +1,12 @@ +request("POST", $url, [ + 'json' => [ + 'code' => $code, + 'id' => $id, + 'stock' => $marketType, + ], + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + Log::info('给交易推送数据 ' . json_encode([$res, [ + 'code' => $code, + 'id' => $id, + 'stock' => $marketType, + ]])); + + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + return false; + } catch (\Exception $exception) { + Log::error('给交易推送数据异常1 ' . $exception->getMessage()); + } catch (GuzzleException $e) { + Log::error('给交易推送数据异常2 ' . $e->getMessage()); + } + + return false; + } + + // 给 go 行情 发送 source + public function updateIndiaSource($country, $stockCode, $source = 0) + { + try { + + $responseArr = [ + 'new_ticker' => $stockCode, //新的股票代码 + 'locale' => $country, + 'source' => $source, + 'token' => 'asdfsnl123jlknl3nksdf32345ln98sdfsfs8891232nsdfsdfsdfsdxcfvbhnfgh', + ]; + + $client = new Client(); + $url = env('QUOTE.BASE_URL') . '/spots/php/update'; + $response = $client->request("POST", $url, [ + 'json' => $responseArr + ]); + + $body = $response->getBody()->getContents(); + $res = json_decode($body, true); + + $responseArr['url'] = $url; + trace('---给行情推送数据---' . json_encode([$res, $responseArr]), 'error'); + + if (isset($res['code']) && $res['code'] == 200) { + return true; + } + + trace('---给行情推送数据异常---' . json_encode([$res, $responseArr]), 'error'); + return false; + } catch (\Exception $exception) { + trace('---给行情推送数据异常1---' . $exception->getMessage(), 'error'); + + } catch (GuzzleException $e) { + trace('---给行情推送数据异常2---' . $e->getMessage(), 'error'); + } + + return false; + } + +} \ No newline at end of file diff --git a/app/utility/DesEn.php b/app/utility/DesEn.php new file mode 100644 index 0000000..28a9356 --- /dev/null +++ b/app/utility/DesEn.php @@ -0,0 +1,125 @@ +key = $key; + $this->method = $method; + $this->output = $output; + $this->iv = $iv; + $this->options = $options; + } + + /** + * 加密 + * + * @param $str + * @return string + */ + public function encrypt($str) + { + $str = $this->padding($str, 8); + $sign = openssl_encrypt($str, $this->method, $this->key, $this->options, $this->iv); + if ($this->output == self::OUTPUT_BASE64) { + $sign = base64_encode($sign); + } else if ($this->output == self::OUTPUT_HEX) { + $sign = bin2hex($sign); + } + + return $sign; + } + + /** + * 填充 + * + * @param $str + * @param $blockSize + * @return string + * @internal param $blocksize + */ + private function padding($str, $blockSize) + { + $pad = $blockSize - (strlen($str) % $blockSize); + return $str . str_repeat(chr($pad), $pad); + } + + /** + * 解密 + * + * @param $encrypted + * @return string + */ + public function decrypt($encrypted) + { + if ($this->output == self::OUTPUT_BASE64) { + $encrypted = base64_decode($encrypted); + } else if ($this->output == self::OUTPUT_HEX) { + $encrypted = hex2bin($encrypted); + } + $sign = @openssl_decrypt($encrypted, $this->method, $this->key, $this->options, $this->iv); + $sign = $this->unPadding($sign); + $sign = rtrim($sign); + return $sign; + } + + /** + * 去填充 + * + * @param $str + * @return string + */ + private function unPadding($str) + { + $pad = ord($str[strlen($str) - 1]); + if ($pad > strlen($str)) { + return false; + } + return substr($str, 0, -1 * $pad); + } + +} \ No newline at end of file diff --git a/app/utility/Jwt.php b/app/utility/Jwt.php new file mode 100644 index 0000000..c6dd2af --- /dev/null +++ b/app/utility/Jwt.php @@ -0,0 +1,99 @@ + [ + 'userId' =>$userId + ], + 'iss' => 'qwueiqnyuqjezchiw', // 随机 + 'aud' => '', + 'iat' =>time() + ]; + + return 'Bear' . \Firebase\JWT\JWT::encode($payload, $key, 'HS256'); + } + + /** + * 后端生成token + * @param $userId // 用户id + * @return string + */ + function generateToken($userId) + { + //获取当前时间戳 + $currentTime = time(); + $data = array( + "iss" => 'coinwerqwerasdf', //签发者 可以为空 + "aud" => '', //面象的用户,可以为空 + "iat" => $currentTime, //签发时间 + "nbf" => $currentTime, //立马生效 + "exp" => $currentTime + 3600*24, //token 过期时间 1天 + "data" => [ //记录的userid的信息 + 'user_id' => $userId, + ] + ); + //生成token + $token = \Firebase\JWT\JWT::encode($data, env('ENCRYPT.ADMINSALT'), "HS256"); + + return 'Bear'.$token; + } + + /** + * 检查token有效性 + * @param $token + * @return array|int[] + */ + public function chekToken($token) + { + $status=array("code"=>2); + if(!$token){ + $status['msg']="token缺失"; + return $status; + } + + $len=4; + $bear=substr($token,0,6); + if($bear=='Bearer'){ + $len=6; + } + $token = trim(substr_replace($token,'',0,$len)," "); + try { + \Firebase\JWT\JWT::$leeway = 60;//当前时间减去60 + $decoded = \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key(env('ENCRYPT.ADMINSALT'), 'HS256')); + $arr = (array)$decoded; + $res['code']=1; + $res['data']=$arr['data']; + return $res; + + } catch(\Firebase\JWT\SignatureInvalidException $e) { //签名不正确 + $status['msg']="token签名不正确"; + return $status; + }catch(\Firebase\JWT\BeforeValidException $e) { // 签名在某个时间点之后才能用 + $status['msg']="token失效"; + return $status; + }catch(\Firebase\JWT\ExpiredException $e) { // token过期 + $status['msg']="token失效"; + + return $status; + }catch(\Exception $e) { //其他错误 + $status['msg']="未知错误"; + return $status; + } + } + + + + +} \ No newline at end of file diff --git a/app/utility/RsaUtility.php b/app/utility/RsaUtility.php new file mode 100644 index 0000000..8f3e1fd --- /dev/null +++ b/app/utility/RsaUtility.php @@ -0,0 +1,74 @@ +pub_key); + return $decrypted; + } +} \ No newline at end of file diff --git a/app/utility/SendEmail.php b/app/utility/SendEmail.php new file mode 100644 index 0000000..d946e14 --- /dev/null +++ b/app/utility/SendEmail.php @@ -0,0 +1,53 @@ +phpEmail = new PHPMailer(); + $this->phpEmail->SMTPDebug = 0; // 关闭调试功能 + $this->phpEmail->CharSet = 'UTF-8'; + $this->phpEmail->isSMTP(); // 设定使用SMTP服务 + //$this->phpEmail->Host = 'smtpdm-ap-southeast-1.aliyun.com'; + $this->phpEmail->Host = empty( env('EMAIL.Host')) ? 'smtpdm-ap-southeast-1.aliyun.com': env('EMAIL.Host'); + $this->phpEmail->Port = 465; // SMTP服务器的端口号 + $this->phpEmail->SMTPAuth = true; + $this->phpEmail->Username = env('EMAIL.Username'); // 发件地址 + $this->phpEmail->Password = env('EMAIL.Password'); // SMTP密码 + $this->phpEmail->SMTPSecure = 'ssl'; + $this->phpEmail->From = env('EMAIL.From'); + } + + /** + * @desc 发送邮箱服务 + * @param $toAddress // 收件地址 + * @param $title // 标题 + * @param $content // 内容 + * @return bool + */ + public function sendEmail($toAddress, $title, $content): bool + { + try { + $this->phpEmail->addAddress($toAddress); + $this->phpEmail->Subject = $title; + $this->phpEmail->Body = $content; + $status = $this->phpEmail->send(); + if ($status) { + return true; + } + trace('---异常-----'.$this->phpEmail->ErrorInfo, 'info'); + + return false; + }catch (\Exception $exception) { + trace('---异常-----'.$exception->getMessage(), 'info'); + return false; + } + + } +} \ No newline at end of file diff --git a/app/utility/SendSms.php b/app/utility/SendSms.php new file mode 100644 index 0000000..fdb0076 --- /dev/null +++ b/app/utility/SendSms.php @@ -0,0 +1,55 @@ +regionId('ap-southeast-1') + ->asDefaultClient(); + + $result = AlibabaCloud::rpcRequest() + ->product('Dysmsapi') + ->host('dysmsapi.ap-southeast-1.aliyuncs.com') + ->version('2018-05-01') + ->action('SendMessageToGlobe') + ->method('POST') + ->options([ + 'query' => [ + "To" => $toNum, + "Message" => $content, + ], + ]) + ->request(); + + $res = $result->toArray(); + + Log::error("----sms_send-----".json_encode([$res])); + if(!isset($res['ResponseCode']) || $res['ResponseCode'] != 'OK'){ + trace('短信发送失败00_'.json_encode([$res]), 'error'); + } + return true; + + }catch (ClientException $clientException) { + trace('短信发送失败01_'.$clientException->getMessage(), 'error'); + }catch (ServerException $serverException) { + trace('短信发送失败02_'.$serverException->getMessage(), 'error'); + }catch (\Exception $exception) { + trace('短信发送失败03_'.$exception->getMessage(), 'error'); + } + + return false; + } +} \ No newline at end of file diff --git a/app/utility/Tool.php b/app/utility/Tool.php new file mode 100644 index 0000000..9179ad1 --- /dev/null +++ b/app/utility/Tool.php @@ -0,0 +1,21 @@ + $length) { + $orderNumber = substr($orderNumber, 0, $length); + } + return $orderNumber; + } +} \ No newline at end of file diff --git a/app/utility/UnqId.php b/app/utility/UnqId.php new file mode 100644 index 0000000..c7e6f49 --- /dev/null +++ b/app/utility/UnqId.php @@ -0,0 +1,38 @@ +encryptPassword($string, $salt); + return $encryptPassword == $password; + } +} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..6933e14 --- /dev/null +++ b/composer.json @@ -0,0 +1,62 @@ +{ + "name": "topthink/think", + "description": "the new thinkphp framework", + "type": "project", + "keywords": [ + "framework", + "thinkphp", + "ORM" + ], + "homepage": "https://www.thinkphp.cn/", + "license": "Apache-2.0", + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "require": { + "php": ">=7.2.5", + "topthink/framework": "6.1.3", + "topthink/think-orm": "2.0.61", + "topthink/think-filesystem": "1.0.3", + "topthink/think-multi-app": "1.0.17", + "phpmailer/phpmailer": "6.8.0", + "alibabacloud/client": "1.5.32", + "firebase/php-jwt": "^6.8", + "topthink/think-queue": "^3.0", + "itinysun/tp-model-helper": "^1.0", + "geoip2/geoip2": "2.13", + "guzzlehttp/guzzle": "^7.7", + "lcobucci/jwt": "^4.0", + "phpoffice/phpspreadsheet": "^1.29" + }, + "require-dev": { + "symfony/var-dumper": "^4.2", + "topthink/think-trace": "^1.0" + }, + "autoload": { + "psr-4": { + "app\\": "app" + }, + "psr-0": { + "": "extend/" + } + }, + "config": { + "preferred-install": "dist", + "allow-plugins": { + "topthink/think-installer": true + } + }, + "scripts": { + "post-autoload-dump": [ + "@php think service:discover", + "@php think vendor:publish" + ] + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..506c24c --- /dev/null +++ b/composer.lock @@ -0,0 +1,3714 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "1a568d2f898357e67a9223da2d6c2877", + "packages": [ + { + "name": "adbario/php-dot-notation", + "version": "2.5.0", + "source": { + "type": "git", + "url": "https://github.com/adbario/php-dot-notation.git", + "reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae", + "reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^5.5 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7|^6.6|^7.5|^8.5|^9.5", + "squizlabs/php_codesniffer": "^3.6" + }, + "type": "library", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Adbar\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Riku Särkinen", + "email": "riku@adbar.io" + } + ], + "description": "PHP dot notation access to arrays", + "homepage": "https://github.com/adbario/php-dot-notation", + "keywords": [ + "ArrayAccess", + "dotnotation" + ], + "support": { + "issues": "https://github.com/adbario/php-dot-notation/issues", + "source": "https://github.com/adbario/php-dot-notation/tree/2.5.0" + }, + "time": "2022-10-14T20:31:46+00:00" + }, + { + "name": "alibabacloud/client", + "version": "1.5.32", + "source": { + "type": "git", + "url": "https://github.com/aliyun/openapi-sdk-php-client.git", + "reference": "5bc6f6d660797dcee2c3aef29700ab41ee764f4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/openapi-sdk-php-client/zipball/5bc6f6d660797dcee2c3aef29700ab41ee764f4d", + "reference": "5bc6f6d660797dcee2c3aef29700ab41ee764f4d", + "shasum": "" + }, + "require": { + "adbario/php-dot-notation": "^2.4.1", + "clagiordano/weblibs-configmanager": "^1.0", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "mtdowling/jmespath.php": "^2.5", + "php": ">=5.5" + }, + "require-dev": { + "composer/composer": "^1.8", + "drupal/coder": "^8.3", + "ext-dom": "*", + "ext-pcre": "*", + "ext-sockets": "*", + "ext-spl": "*", + "league/climate": "^3.2.4", + "mikey179/vfsstream": "^1.6", + "monolog/monolog": "^1.24", + "phpunit/phpunit": "^5.7|^6.6|^7.5|^8.5|^9.5", + "psr/cache": "^1.0", + "symfony/dotenv": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "AlibabaCloud\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com", + "homepage": "http://www.alibabacloud.com" + } + ], + "description": "Alibaba Cloud Client for PHP - Use Alibaba Cloud in your PHP project", + "homepage": "https://www.alibabacloud.com/", + "keywords": [ + "alibaba", + "alibabacloud", + "aliyun", + "client", + "cloud", + "library", + "sdk", + "tool" + ], + "support": { + "issues": "https://github.com/aliyun/openapi-sdk-php-client/issues", + "source": "https://github.com/aliyun/openapi-sdk-php-client" + }, + "time": "2022-12-09T04:05:55+00:00" + }, + { + "name": "carbonphp/carbon-doctrine-types", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git", + "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", + "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "doctrine/dbal": "<3.7.0 || >=4.0.0" + }, + "require-dev": { + "doctrine/dbal": "^3.7.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2023-12-11T17:09:12+00:00" + }, + { + "name": "clagiordano/weblibs-configmanager", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/clagiordano/weblibs-configmanager.git", + "reference": "5c8ebcc62782313b1278afe802b120d18c07a059" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clagiordano/weblibs-configmanager/zipball/5c8ebcc62782313b1278afe802b120d18c07a059", + "reference": "5c8ebcc62782313b1278afe802b120d18c07a059", + "shasum": "" + }, + "require": { + "php": ">=5.4" + }, + "require-dev": { + "clagiordano/phpunit-result-printer": "^1", + "phpunit/phpunit": "^4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "clagiordano\\weblibs\\configmanager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Claudio Giordano", + "email": "claudio.giordano@autistici.org", + "role": "Developer" + } + ], + "description": "weblibs-configmanager is a tool library for easily read and access to php config array file and direct read/write configuration file / object", + "keywords": [ + "clagiordano", + "configuration", + "manager", + "tool", + "weblibs" + ], + "support": { + "issues": "https://github.com/clagiordano/weblibs-configmanager/issues", + "source": "https://github.com/clagiordano/weblibs-configmanager/tree/v1.2.0" + }, + "time": "2021-05-18T17:55:57+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", + "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.5.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-03-15T14:00:32+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.17.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/bbc513d79acf6691fa9cf10f192c90dd2957f18c", + "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.17.0" + }, + "time": "2023-11-17T15:01:25+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v6.10.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "a49db6f0a5033aef5143295342f1c95521b075ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/a49db6f0a5033aef5143295342f1c95521b075ff", + "reference": "a49db6f0a5033aef5143295342f1c95521b075ff", + "shasum": "" + }, + "require": { + "php": "^7.4||^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^6.5||^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^1.0||^2.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.10.0" + }, + "time": "2023-12-01T16:26:39+00:00" + }, + { + "name": "geoip2/geoip2", + "version": "v2.13.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/GeoIP2-php.git", + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/6a41d8fbd6b90052bc34dff3b4252d0f88067b23", + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23", + "shasum": "" + }, + "require": { + "ext-json": "*", + "maxmind-db/reader": "~1.8", + "maxmind/web-service-common": "~0.8", + "php": ">=7.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^8.0 || ^9.0", + "squizlabs/php_codesniffer": "3.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "GeoIp2\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "description": "MaxMind GeoIP2 PHP API", + "homepage": "https://github.com/maxmind/GeoIP2-php", + "keywords": [ + "IP", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], + "support": { + "issues": "https://github.com/maxmind/GeoIP2-php/issues", + "source": "https://github.com/maxmind/GeoIP2-php/tree/v2.13.0" + }, + "time": "2022-08-05T20:32:58+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.8.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.1", + "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.8.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2023-12-03T20:35:24+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2023-12-03T20:19:20+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.6.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.6.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-12-03T20:05:35+00:00" + }, + { + "name": "itinysun/tp-model-helper", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/Itinysun/tp-model-helper.git", + "reference": "ab280d3ad6321ef4c3951690153520d34497323f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Itinysun/tp-model-helper/zipball/ab280d3ad6321ef4c3951690153520d34497323f", + "reference": "ab280d3ad6321ef4c3951690153520d34497323f", + "shasum": "" + }, + "require": { + "phpdocumentor/reflection-docblock": "^3.1", + "symfony/class-loader": "^2.3|^3.0", + "topthink/framework": "^6.0", + "topthink/think-helper": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.6" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "itinysun\\model\\helper\\Service" + ], + "config": { + "model_help": "config/config.php" + } + } + }, + "autoload": { + "psr-4": { + "itinysun\\model\\helper\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Itinysun", + "email": "860760361@qq.com" + } + ], + "description": "a vendor for thinkphp6.*,help generate phpdocs for model class", + "support": { + "issues": "https://github.com/Itinysun/tp-model-helper/issues", + "source": "https://github.com/Itinysun/tp-model-helper/tree/v1.0.2" + }, + "time": "2021-11-03T13:21:13+00:00" + }, + { + "name": "lcobucci/clock", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/clock.git", + "reference": "353d83fe2e6ae95745b16b3d911813df6a05bfb3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/353d83fe2e6ae95745b16b3d911813df6a05bfb3", + "reference": "353d83fe2e6ae95745b16b3d911813df6a05bfb3", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "infection/infection": "^0.17", + "lcobucci/coding-standard": "^6.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/php-code-coverage": "9.1.4", + "phpunit/phpunit": "9.3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "description": "Yet another clock abstraction", + "support": { + "issues": "https://github.com/lcobucci/clock/issues", + "source": "https://github.com/lcobucci/clock/tree/2.0.x" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2020-08-27T18:56:02+00:00" + }, + { + "name": "lcobucci/jwt", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "55564265fddf810504110bd68ca311932324b0e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/55564265fddf810504110bd68ca311932324b0e9", + "reference": "55564265fddf810504110bd68ca311932324b0e9", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-openssl": "*", + "lcobucci/clock": "^2.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "infection/infection": "^0.20", + "lcobucci/coding-standard": "^6.0", + "mikey179/vfsstream": "^1.6", + "phpbench/phpbench": "^0.17", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/php-invoker": "^3.1", + "phpunit/phpunit": "^9.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2021-09-28T19:18:28+00:00" + }, + { + "name": "league/flysystem", + "version": "1.1.10", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.1.10" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "time": "2022-10-04T09:16:37+00:00" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "support": { + "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues", + "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master" + }, + "time": "2020-07-25T15:56:04+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.15.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301", + "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-01-28T23:22:08+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "2.2.6", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "30ad6f93cf3efe4192bc7a4c9cad11ff8f4f237f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/30ad6f93cf3efe4192bc7a4c9cad11ff8f4f237f", + "reference": "30ad6f93cf3efe4192bc7a4c9cad11ff8f4f237f", + "shasum": "" + }, + "require": { + "myclabs/php-enum": "^1.5", + "php": "^7.4 || ^8.0", + "psr/http-message": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.9", + "guzzlehttp/guzzle": "^6.5.3 || ^7.2.0", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.4", + "phpunit/phpunit": "^8.5.8 || ^9.4.2", + "vimeo/psalm": "^4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/2.2.6" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + }, + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], + "time": "2022-11-25T18:57:19+00:00" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "time": "2022-12-06T16:21:08+00:00" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "time": "2022-12-02T22:17:43+00:00" + }, + { + "name": "maxmind-db/reader", + "version": "v1.11.1", + "source": { + "type": "git", + "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", + "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/1e66f73ffcf25e17c7a910a1317e9720a95497c7", + "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "conflict": { + "ext-maxminddb": "<1.11.1,>=2.0.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "php-coveralls/php-coveralls": "^2.1", + "phpstan/phpstan": "*", + "phpunit/phpcov": ">=6.0.0", + "phpunit/phpunit": ">=8.0.0,<10.0.0", + "squizlabs/php_codesniffer": "3.*" + }, + "suggest": { + "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" + }, + "type": "library", + "autoload": { + "psr-4": { + "MaxMind\\Db\\": "src/MaxMind/Db" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "description": "MaxMind DB Reader API", + "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php", + "keywords": [ + "database", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], + "support": { + "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", + "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.11.1" + }, + "time": "2023-12-02T00:09:23+00:00" + }, + { + "name": "maxmind/web-service-common", + "version": "v0.9.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/web-service-common-php.git", + "reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/4dc5a3e8df38aea4ca3b1096cee3a038094e9b53", + "reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0.3", + "ext-curl": "*", + "ext-json": "*", + "php": ">=7.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^8.0 || ^9.0", + "squizlabs/php_codesniffer": "3.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "MaxMind\\Exception\\": "src/Exception", + "MaxMind\\WebService\\": "src/WebService" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory Oschwald", + "email": "goschwald@maxmind.com" + } + ], + "description": "Internal MaxMind Web Service API", + "homepage": "https://github.com/maxmind/web-service-common-php", + "support": { + "issues": "https://github.com/maxmind/web-service-common-php/issues", + "source": "https://github.com/maxmind/web-service-common-php/tree/v0.9.0" + }, + "time": "2022-03-28T17:43:20+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/bbb69a935c2cbb0c03d7f481a238027430f6440b", + "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.7.0" + }, + "time": "2023-08-25T10:54:48+00:00" + }, + { + "name": "myclabs/php-enum", + "version": "1.8.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "a867478eae49c9f59ece437ae7f9506bfaa27483" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/a867478eae49c9f59ece437ae7f9506bfaa27483", + "reference": "a867478eae49c9f59ece437ae7f9506bfaa27483", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^4.6.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + }, + "classmap": [ + "stubs/Stringable.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "http://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "support": { + "issues": "https://github.com/myclabs/php-enum/issues", + "source": "https://github.com/myclabs/php-enum/tree/1.8.4" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "time": "2022-08-04T09:53:51+00:00" + }, + { + "name": "nesbot/carbon", + "version": "2.72.3", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/0c6fd108360c562f6e4fd1dedb8233b423e91c83", + "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "*", + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "psr/clock": "^1.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0", + "doctrine/orm": "^2.7 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.0", + "kylekatarnls/multi-tester": "^2.0", + "ondrejmirtes/better-reflection": "*", + "phpmd/phpmd": "^2.9", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.99 || ^1.7.14", + "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", + "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", + "squizlabs/php_codesniffer": "^3.4" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-3.x": "3.x-dev", + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/briannesbitt/Carbon/issues", + "source": "https://github.com/briannesbitt/Carbon" + }, + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2024-01-25T10:35:09+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master" + }, + "time": "2017-09-11T18:02:19+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2", + "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/3.x" + }, + "time": "2017-11-10T14:09:06+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/master" + }, + "time": "2017-07-14T14:27:02+00:00" + }, + { + "name": "phpmailer/phpmailer", + "version": "v6.8.0", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "df16b615e371d81fb79e506277faea67a1be18f1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/df16b615e371d81fb79e506277faea67a1be18f1", + "reference": "df16b615e371d81fb79e506277faea67a1be18f1", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2", + "doctrine/annotations": "^1.2.6 || ^1.13.3", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.7.1", + "yoast/phpunit-polyfills": "^1.0.4" + }, + "suggest": { + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "ext-openssl": "Needed for secure SMTP sending and DKIM signing", + "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", + "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.0" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "time": "2023-03-06T14:43:22+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.29.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fde2ccf55eaef7e86021ff1acce26479160a0fa0", + "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.15", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": "^7.4 || ^8.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^1.0 || ^2.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.3", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5 || ^9.0 || ^10.0", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.0" + }, + "time": "2023-06-14T22:48:31+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "time": "2021-11-05T16:50:12+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "time": "2023-04-04T09:50:52+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/class-loader", + "version": "v3.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/class-loader.git", + "reference": "a22265a9f3511c0212bf79f54910ca5a77c0e92c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/class-loader/zipball/a22265a9f3511c0212bf79f54910ca5a77c0e92c", + "reference": "a22265a9f3511c0212bf79f54910ca5a77c0e92c", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "require-dev": { + "symfony/finder": "~2.8|~3.0|~4.0", + "symfony/polyfill-apcu": "~1.1" + }, + "suggest": { + "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ClassLoader\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ClassLoader Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/class-loader/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": true, + "time": "2020-10-24T10:57:07+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "80d075412b557d41002320b96a096ca65aa2c98d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d", + "reference": "80d075412b557d41002320b96a096ca65aa2c98d", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-24T14:02:46+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-29T20:11:03+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-29T20:11:03+00:00" + }, + { + "name": "symfony/process", + "version": "v5.4.39", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "85a554acd7c28522241faf2e97b9541247a0d3d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/85a554acd7c28522241faf2e97b9541247a0d3d5", + "reference": "85a554acd7c28522241faf2e97b9541247a0d3d5", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.4.39" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T08:26:06+00:00" + }, + { + "name": "symfony/translation", + "version": "v5.4.39", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "0fabede35e3985c4f96089edeeefe8313e15ca3a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/0fabede35e3985c4f96089edeeefe8313e15ca3a", + "reference": "0fabede35e3985c4f96089edeeefe8313e15ca3a", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation-contracts": "^2.3" + }, + "conflict": { + "symfony/config": "<4.4", + "symfony/console": "<5.3", + "symfony/dependency-injection": "<5.0", + "symfony/http-kernel": "<5.0", + "symfony/twig-bundle": "<5.0", + "symfony/yaml": "<4.4" + }, + "provide": { + "symfony/translation-implementation": "2.3" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/http-client-contracts": "^1.1|^2.0|^3.0", + "symfony/http-kernel": "^5.0|^6.0", + "symfony/intl": "^4.4|^5.0|^6.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/service-contracts": "^1.1.2|^2|^3", + "symfony/yaml": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v5.4.39" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T08:26:06+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v2.5.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "b0073a77ac0b7ea55131020e87b1e3af540f4664" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b0073a77ac0b7ea55131020e87b1e3af540f4664", + "reference": "b0073a77ac0b7ea55131020e87b1e3af540f4664", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v2.5.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-23T13:51:25+00:00" + }, + { + "name": "topthink/framework", + "version": "v6.1.3", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "7c324e7011246f0064b055b62ab9c3921cf0a041" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/7c324e7011246f0064b055b62ab9c3921cf0a041", + "reference": "7c324e7011246f0064b055b62ab9c3921cf0a041", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=7.2.5", + "psr/container": "~1.0", + "psr/http-message": "^1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1.1", + "topthink/think-orm": "^2.0|^3.0" + }, + "require-dev": { + "guzzlehttp/psr7": "^2.1.0", + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP Framework.", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "support": { + "issues": "https://github.com/top-think/framework/issues", + "source": "https://github.com/top-think/framework/tree/v6.1.3" + }, + "time": "2023-05-22T03:02:08+00:00" + }, + { + "name": "topthink/think-filesystem", + "version": "v1.0.3", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-filesystem.git", + "reference": "29f19f140a9267c717fecd7ccb22c84c2d72382e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-filesystem/zipball/29f19f140a9267c717fecd7ccb22c84c2d72382e", + "reference": "29f19f140a9267c717fecd7ccb22c84c2d72382e", + "shasum": "" + }, + "require": { + "league/flysystem": "^1.1.4", + "league/flysystem-cached-adapter": "^1.0", + "php": ">=7.2.5", + "topthink/framework": "^6.1|^8.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6.1 Filesystem Package", + "support": { + "issues": "https://github.com/top-think/think-filesystem/issues", + "source": "https://github.com/top-think/think-filesystem/tree/v1.0.3" + }, + "time": "2023-02-08T01:25:15+00:00" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.6", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/769acbe50a4274327162f9c68ec2e89a38eb2aff", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/helper.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/v3.1.6" + }, + "time": "2021-12-15T04:27:55+00:00" + }, + { + "name": "topthink/think-multi-app", + "version": "v1.0.17", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-multi-app.git", + "reference": "4055a6187296ac16c0bc7bbab4ed5d92f82f791c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-multi-app/zipball/4055a6187296ac16c0bc7bbab4ed5d92f82f791c", + "reference": "4055a6187296ac16c0bc7bbab4ed5d92f82f791c", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0|^8.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\app\\Service" + ] + } + }, + "autoload": { + "psr-4": { + "think\\app\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp multi app support", + "support": { + "issues": "https://github.com/top-think/think-multi-app/issues", + "source": "https://github.com/top-think/think-multi-app/tree/v1.0.17" + }, + "time": "2023-03-29T02:04:29+00:00" + }, + { + "name": "topthink/think-orm", + "version": "v2.0.61", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "10528ebf4a5106b19c3bac9c6deae7a67ff49de6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/10528ebf4a5106b19c3bac9c6deae7a67ff49de6", + "reference": "10528ebf4a5106b19c3bac9c6deae7a67ff49de6", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pdo": "*", + "php": ">=7.1.0", + "psr/log": "^1.0|^2.0", + "psr/simple-cache": "^1.0|^2.0", + "topthink/think-helper": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9.5" + }, + "type": "library", + "autoload": { + "files": [ + "stubs/load_stubs.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "think orm", + "keywords": [ + "database", + "orm" + ], + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v2.0.61" + }, + "time": "2023-04-20T14:27:51+00:00" + }, + { + "name": "topthink/think-queue", + "version": "v3.0.9", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-queue.git", + "reference": "654812b47dd7c708c4443deed27f212f8382e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-queue/zipball/654812b47dd7c708c4443deed27f212f8382e8da", + "reference": "654812b47dd7c708c4443deed27f212f8382e8da", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nesbot/carbon": "^2.16", + "symfony/process": ">=4.2", + "topthink/framework": "^6.0 || ^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^6.2", + "topthink/think-migration": "^3.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\queue\\Service" + ], + "config": { + "queue": "src/config.php" + } + } + }, + "autoload": { + "files": [ + "src/common.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Queue Package", + "support": { + "issues": "https://github.com/top-think/think-queue/issues", + "source": "https://github.com/top-think/think-queue/tree/v3.0.9" + }, + "time": "2023-07-03T05:42:01+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "packages-dev": [ + { + "name": "symfony/polyfill-php72", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-29T20:11:03+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.47", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" + }, + { + "name": "topthink/think-trace", + "version": "v1.6", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-trace.git", + "reference": "136cd5d97e8bdb780e4b5c1637c588ed7ca3e142" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-trace/zipball/136cd5d97e8bdb780e4b5c1637c588ed7ca3e142", + "reference": "136cd5d97e8bdb780e4b5c1637c588ed7ca3e142", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0|^8.0" + }, + "type": "library", + "extra": { + "think": { + "services": [ + "think\\trace\\Service" + ], + "config": { + "trace": "src/config.php" + } + } + }, + "autoload": { + "psr-4": { + "think\\trace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp debug trace", + "support": { + "issues": "https://github.com/top-think/think-trace/issues", + "source": "https://github.com/top-think/think-trace/tree/v1.6" + }, + "time": "2023-02-07T08:36:32+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.2.5" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/config/app.php b/config/app.php new file mode 100644 index 0000000..ae79370 --- /dev/null +++ b/config/app.php @@ -0,0 +1,43 @@ + env('app.host', ''), + // 应用的命名空间 + 'app_namespace' => '', + // 是否启用路由 + 'with_route' => true, + // 默认应用 + 'default_app' => 'index', + // 默认时区 + 'default_timezone' => 'Asia/Singapore', + + // 应用映射(自动多应用模式有效) + 'app_map' => [ + 'bs' => 'home', + 'XwkjlLbDcG' => 'admin', + ], + 'cross_origin' => true, //允许跨域 + // 域名绑定(自动多应用模式有效) + 'domain_bind' => [], + // 禁止URL访问的应用列表(自动多应用模式有效) + 'deny_app_list' => [], + + // 异常页面的模板文件 + //'exception_tmpl' => app()->getThinkPath() . 'tpl/think_exception.tpl', + 'exception_tmpl' => base_path().'sorry.html', + + // 错误显示信息,非调试模式有效 + 'error_message' => '页面错误!请稍后再试~', + // 显示错误信息 + 'show_error_msg' => false, + 'fields_cache'=>true, + 'http_exception_template' => [ + // '404' => base_path().'404.html', + ], + //多语言 + 'lang_switch_on'=>true, +]; diff --git a/config/cache.php b/config/cache.php new file mode 100644 index 0000000..cdae60e --- /dev/null +++ b/config/cache.php @@ -0,0 +1,37 @@ + env('cache.driver', 'file'), + + // 缓存连接方式配置 + 'stores' => [ + 'file' => [ + // 驱动方式 + 'type' => 'File', + // 缓存保存目录 + 'path' => '', + // 缓存前缀 + 'prefix' => '', + // 缓存有效期 0表示永久缓存 + 'expire' => 0, + // 缓存标签前缀 + 'tag_prefix' => 'tag:', + // 序列化机制 例如 ['serialize', 'unserialize'] + 'serialize' => [], + ], + // 更多的缓存连接 + 'redis' => [ + 'type' => 'redis', + 'host' => env('REDIS.HOST', '172.31.120.245'), + 'port' => env('REDIS.PORT', '6378'), + 'select' => env('REDIS.SELECT', '0'), + 'password' => env('REDIS.PASSWORD', 'rfvtyujnbhg56'), + ], + ], + +]; diff --git a/config/console.php b/config/console.php new file mode 100644 index 0000000..061c755 --- /dev/null +++ b/config/console.php @@ -0,0 +1,9 @@ + [ + ], +]; diff --git a/config/cookie.php b/config/cookie.php new file mode 100644 index 0000000..5d4b881 --- /dev/null +++ b/config/cookie.php @@ -0,0 +1,20 @@ + 0, + // cookie 保存路径 + 'path' => '/', + // cookie 有效域名 + 'domain' => '', + // cookie 启用安全传输 + 'secure' => false, + // httponly设置 + 'httponly' => false, + // 是否使用 setcookie + 'setcookie' => true, + // samesite 设置,支持 'strict' 'lax' + 'samesite' => '', +]; diff --git a/config/database.php b/config/database.php new file mode 100644 index 0000000..a842e91 --- /dev/null +++ b/config/database.php @@ -0,0 +1,63 @@ + env('database.driver', 'mysql'), + + // 自定义时间查询规则 + 'time_query_rule' => [], + + // 自动写入时间戳字段 + // true为自动识别类型 false关闭 + // 字符串则明确指定时间字段类型 支持 int timestamp datetime date + 'auto_timestamp' => true, + + // 时间字段取出后的默认时间格式 + 'datetime_format' => 'Y-m-d H:i:s', + + // 时间字段配置 配置格式:create_time,update_time + 'datetime_field' => '', + + // 数据库连接配置信息 + 'connections' => [ + 'mysql' => [ + // 数据库类型 + 'type' => env('database.type', 'mysql'), + // 服务器地址 + 'hostname' => env('database.hostname', 'dbtest.crsocbk1nt38.ap-southeast-1.rds.amazonaws.com'), + // 数据库名 + 'database' => env('database.database', 'bourse'), + // 用户名 + 'username' => env('database.username', 'admin'), + // 密码 + 'password' => env('database.password', '123456'), + // 端口 + 'hostport' => env('database.hostport', '3306'), + // 数据库连接参数 + 'params' => [], + // 数据库编码默认采用utf8 + 'charset' => env('database.charset', 'utf8'), + // 数据库表前缀 + 'prefix' => env('database.prefix', 'bot_'), + + // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'deploy' => 0, + // 数据库读写是否分离 主从式有效 + 'rw_separate' => false, + // 读写分离后 主服务器数量 + 'master_num' => 1, + // 指定从服务器序号 + 'slave_no' => '', + // 是否严格检查字段是否存在 + 'fields_strict' => true, + // 是否需要断线重连 + 'break_reconnect' => false, + // 监听SQL + 'trigger_sql' => env('app_debug', true), + // 开启字段缓存 + 'fields_cache' => false, + ], + + // 更多的数据库配置信息 + ], +]; diff --git a/config/filesystem.php b/config/filesystem.php new file mode 100644 index 0000000..ee4c38c --- /dev/null +++ b/config/filesystem.php @@ -0,0 +1,25 @@ + env('filesystem.driver', 'local'), + // 磁盘列表 + 'disks' => [ + 'local' => [ + 'type' => 'local', + //'root' => app()->getRuntimePath() . 'storage', + 'root' => app()->getRootPath() . 'public/bs/image' + ], + 'public' => [ + // 磁盘类型 + 'type' => 'local', + // 磁盘路径 + 'root' => app()->getRootPath() . 'public/storage', + // 磁盘路径对应的外部URL路径 + 'url' => '/storage', + // 可见性 + 'visibility' => 'public', + ], + // 更多的磁盘配置信息 + ], +]; diff --git a/config/lang.php b/config/lang.php new file mode 100644 index 0000000..5c3bf62 --- /dev/null +++ b/config/lang.php @@ -0,0 +1,31 @@ + env('lang.default_lang', 'zh-cn'), + // 允许的语言列表 + 'allow_lang_list' => [ + 'zh-cn', + 'en-us', + ], + // 多语言自动侦测变量名 + 'detect_var' => 'lang', + // 是否使用Cookie记录 + 'use_cookie' => true, + // 多语言cookie变量 + 'cookie_var' => 'think_lang', + // 多语言header变量 + 'header_var' => 'think-lang', + // 扩展语言包 + 'extend_list' => [], + // Accept-Language转义为对应语言包名称 + 'accept_language' => [ + 'zh-hans-cn' => 'zh-cn', + ], + // 是否支持语言分组 + 'allow_group' => false, + +]; diff --git a/config/log.php b/config/log.php new file mode 100644 index 0000000..cc2020a --- /dev/null +++ b/config/log.php @@ -0,0 +1,45 @@ + env('log.channel', 'file'), + // 日志记录级别 + 'level' => ['error','info'], + // 日志类型记录的通道 ['error'=>'email',...] + 'type_channel' => [], + // 关闭全局日志写入 + 'close' => false, + // 全局日志处理 支持闭包 + 'processor' => null, + + // 日志通道列表 + 'channels' => [ + 'file' => [ + // 日志记录方式 + 'type' => 'File', + // 日志保存目录 + 'path' => '', + // 单文件日志写入 + 'single' => false, + // 独立日志级别 + 'apart_level' => [], + // 最大日志文件数量 + 'max_files' => 0, + // 使用JSON格式记录 + 'json' => false, + // 日志处理 + 'processor' => null, + // 关闭通道日志写入 + 'close' => false, + // 日志输出格式化 + 'format' => '[%s][%s] %s', + // 是否实时写入 + 'realtime_write' => false, + ], + // 其它日志通道配置 + ], + +]; diff --git a/config/middleware.php b/config/middleware.php new file mode 100644 index 0000000..d1dad98 --- /dev/null +++ b/config/middleware.php @@ -0,0 +1,18 @@ + [ + 'admin_auth' => app\admin\middleware\Check::class, + 'admin_log'=> app\admin\middleware\AdminLog::class, + + 'bs_auth' => app\home\middleware\AuthMiddleware::class, + 'bs_repeat' => app\home\middleware\RepeatOperateMiddleware::class, + 'bs_cors' => app\home\middleware\CorsMiddleware::class, + ], + // 优先级设置,此数组中的中间件会按照数组中的顺序优先执行 + 'priority' => [ + \think\middleware\AllowCrossDomain::class, + ], + +]; diff --git a/config/model_help.php b/config/model_help.php new file mode 100644 index 0000000..665e810 --- /dev/null +++ b/config/model_help.php @@ -0,0 +1,53 @@ + true, + + /* + * 开启模型字段schema的写入,开启后无需更新字段缓存 + * https://www.kancloud.cn/manual/thinkphp6_0/1037581 + */ + 'write_schema' => true, + + /* + * 开启模型查询方法的辅助注释 + * 包括 find findOrEmpty select + */ + 'write_select_help' => true, + + /* + * 开启关联模型查询方法的辅助注释 + */ + 'write_relation_model' => true, + + /* + * 是否允许覆盖 + * 注意,这里仅检查原有模型是否含有该字段,并不检测字段是否需要更新 + * 开启后每次都会更新并写入模型,即使没有字段变更,git也可能会刷新版本 + */ + + 'over_write_phpdoc' => false, + 'over_write_schema' => false, + + /* + * 设置读取模型的目录 + * 例如: + * ‘model’ 读取的是 base_path('model') 即 app 目录下的 model 目录 + * 或者直接使用绝对路径 + */ + 'load_dir' => [ + 'model' + ], + + /* + * 忽略更新的模型 + * 例如 + * \think\Model::class + */ + 'ignore_model' => [ + + ], +]; \ No newline at end of file diff --git a/config/queue.php b/config/queue.php new file mode 100644 index 0000000..8cd96dc --- /dev/null +++ b/config/queue.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- + +return [ + 'default' => 'redis', + 'connections' => [ + 'sync' => [ + 'type' => 'sync', + ], + 'redis' => [ + 'type' => 'redis', + 'queue' => 'default', + 'host' => env('REDIS.HOST', '127.0.0.1'), + 'port' => env('REDIS.PORT', '6379'), + 'password' => env('REDIS.PASSWORD', ''), + 'select' => env('REDIS.SELECT', '0'), + 'timeout' => 0, + 'persistent' => false, + ], + ], +]; diff --git a/config/redis.php b/config/redis.php new file mode 100644 index 0000000..f84e7c5 --- /dev/null +++ b/config/redis.php @@ -0,0 +1,15 @@ + [ + 'type' => 'redis', + 'host' => env('REDIS.HOST', '13.251.125.27'), + 'port' => env('REDIS.PORT', '6378'), + 'select' => env('REDIS.SELECT', '0'), + 'password' => env('REDIS.PASSWORD', 'rfvtyujnbhg56'), + ], + +]; diff --git a/config/route.php b/config/route.php new file mode 100644 index 0000000..1a93d4b --- /dev/null +++ b/config/route.php @@ -0,0 +1,45 @@ + '/', + // URL伪静态后缀 + 'url_html_suffix' => 'html', + // URL普通方式参数 用于自动生成 + 'url_common_param' => true, + // 是否开启路由延迟解析 + 'url_lazy_route' => false, + // 是否强制使用路由 + 'url_route_must' => false, + // 合并路由规则 + 'route_rule_merge' => false, + // 路由是否完全匹配 + 'route_complete_match' => false, + // 访问控制器层名称 + 'controller_layer' => 'controller', + // 空控制器名 + 'empty_controller' => 'Error', + // 是否使用控制器后缀 + 'controller_suffix' => false, + // 默认的路由变量规则 + 'default_route_pattern' => '[\w\.]+', + // 是否开启请求缓存 true自动缓存 支持设置请求缓存规则 + 'request_cache_key' => false, + // 请求缓存有效期 + 'request_cache_expire' => null, + // 全局请求缓存排除规则 + 'request_cache_except' => [], + // 默认控制器名 + 'default_controller' => 'Index', + // 默认操作名 + 'default_action' => 'index', + // 操作方法后缀 + 'action_suffix' => '', + // 默认JSONP格式返回的处理方法 + 'default_jsonp_handler' => 'jsonpReturn', + // 默认JSONP处理方法 + 'var_jsonp_handler' => 'callback', +]; diff --git a/config/session.php b/config/session.php new file mode 100644 index 0000000..85858c7 --- /dev/null +++ b/config/session.php @@ -0,0 +1,19 @@ + 'PHPSESSID', + // SESSION_ID的提交变量,解决flash上传跨域 + 'var_session_id' => '', + // 驱动方式 支持file cache + 'type' => 'file', + // 存储连接标识 当type使用cache的时候有效 + 'store' => null, + // 过期时间 + 'expire' => 1440, + // 前缀 + 'prefix' => '', +]; diff --git a/config/trace.php b/config/trace.php new file mode 100644 index 0000000..0fd4b4c --- /dev/null +++ b/config/trace.php @@ -0,0 +1,10 @@ + 'Html', + // 读取的日志通道名 + 'channel' => '', +]; diff --git a/config/view.php b/config/view.php new file mode 100644 index 0000000..b9b7c5c --- /dev/null +++ b/config/view.php @@ -0,0 +1,25 @@ + 'Think', + // 默认模板渲染规则 1 解析为小写+下划线 2 全部转换小写 3 保持操作方法 + 'auto_rule' => 1, + // 模板目录名 + 'view_dir_name' => 'view', + // 模板后缀 + 'view_suffix' => 'html', + // 模板文件名分隔符 + 'view_depr' => DIRECTORY_SEPARATOR, + // 模板引擎普通标签开始标记 + 'tpl_begin' => '{', + // 模板引擎普通标签结束标记 + 'tpl_end' => '}', + // 标签库标签开始标记 + 'taglib_begin' => '{', + // 标签库标签结束标记 + 'taglib_end' => '}', +]; diff --git a/extend/.gitignore b/extend/.gitignore new file mode 100644 index 0000000..a3a0c8b --- /dev/null +++ b/extend/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..e69de29 diff --git a/public/Ubsfim.apk b/public/Ubsfim.apk new file mode 100644 index 0000000..4ce7ce6 Binary files /dev/null and b/public/Ubsfim.apk differ diff --git a/public/bs/.gitignore b/public/bs/.gitignore new file mode 100644 index 0000000..a3a0c8b --- /dev/null +++ b/public/bs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e71815a Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..78b1845 --- /dev/null +++ b/public/index.php @@ -0,0 +1,24 @@ + +// +---------------------------------------------------------------------- + +// [ 应用入口文件 ] +namespace think; + +require __DIR__ . '/../vendor/autoload.php'; + +// 执行HTTP应用并响应 +$http = (new App())->http; + +$response = $http->run(); + +$response->send(); + +$http->end($response); diff --git a/public/logo/1.png b/public/logo/1.png new file mode 100644 index 0000000..4a06e39 Binary files /dev/null and b/public/logo/1.png differ diff --git a/public/logo/2.png b/public/logo/2.png new file mode 100644 index 0000000..90c925b Binary files /dev/null and b/public/logo/2.png differ diff --git a/public/logo/ada.png b/public/logo/ada.png new file mode 100644 index 0000000..08e3e79 Binary files /dev/null and b/public/logo/ada.png differ diff --git a/public/logo/avax.png b/public/logo/avax.png new file mode 100644 index 0000000..b65486b Binary files /dev/null and b/public/logo/avax.png differ diff --git a/public/logo/bch.png b/public/logo/bch.png new file mode 100644 index 0000000..3824c5a Binary files /dev/null and b/public/logo/bch.png differ diff --git a/public/logo/bnb.png b/public/logo/bnb.png new file mode 100644 index 0000000..5bfc3e2 Binary files /dev/null and b/public/logo/bnb.png differ diff --git a/public/logo/btc.png b/public/logo/btc.png new file mode 100644 index 0000000..80272c8 Binary files /dev/null and b/public/logo/btc.png differ diff --git a/public/logo/busd.png b/public/logo/busd.png new file mode 100644 index 0000000..e4b950e Binary files /dev/null and b/public/logo/busd.png differ diff --git a/public/logo/dai.png b/public/logo/dai.png new file mode 100644 index 0000000..7a1afb7 Binary files /dev/null and b/public/logo/dai.png differ diff --git a/public/logo/doge.png b/public/logo/doge.png new file mode 100644 index 0000000..10c0d72 Binary files /dev/null and b/public/logo/doge.png differ diff --git a/public/logo/dot.png b/public/logo/dot.png new file mode 100644 index 0000000..70f1459 Binary files /dev/null and b/public/logo/dot.png differ diff --git a/public/logo/eos.png b/public/logo/eos.png new file mode 100644 index 0000000..34caf0f Binary files /dev/null and b/public/logo/eos.png differ diff --git a/public/logo/eth.png b/public/logo/eth.png new file mode 100644 index 0000000..317228b Binary files /dev/null and b/public/logo/eth.png differ diff --git a/public/logo/ltc.png b/public/logo/ltc.png new file mode 100644 index 0000000..51c4aca Binary files /dev/null and b/public/logo/ltc.png differ diff --git a/public/logo/matic.png b/public/logo/matic.png new file mode 100644 index 0000000..ad93fdb Binary files /dev/null and b/public/logo/matic.png differ diff --git a/public/logo/shib.png b/public/logo/shib.png new file mode 100644 index 0000000..22c2e93 Binary files /dev/null and b/public/logo/shib.png differ diff --git a/public/logo/sol.png b/public/logo/sol.png new file mode 100644 index 0000000..4c5dc47 Binary files /dev/null and b/public/logo/sol.png differ diff --git a/public/logo/tg.png b/public/logo/tg.png new file mode 100644 index 0000000..539175e Binary files /dev/null and b/public/logo/tg.png differ diff --git a/public/logo/ton.png b/public/logo/ton.png new file mode 100644 index 0000000..9a517e8 Binary files /dev/null and b/public/logo/ton.png differ diff --git a/public/logo/trx.png b/public/logo/trx.png new file mode 100644 index 0000000..575be70 Binary files /dev/null and b/public/logo/trx.png differ diff --git a/public/logo/usdc.png b/public/logo/usdc.png new file mode 100644 index 0000000..2bad29e Binary files /dev/null and b/public/logo/usdc.png differ diff --git a/public/logo/usdt.png b/public/logo/usdt.png new file mode 100644 index 0000000..07d8323 Binary files /dev/null and b/public/logo/usdt.png differ diff --git a/public/logo/wbtc.png b/public/logo/wbtc.png new file mode 100644 index 0000000..96e4448 Binary files /dev/null and b/public/logo/wbtc.png differ diff --git a/public/logo/ws.png b/public/logo/ws.png new file mode 100644 index 0000000..a3f9df0 Binary files /dev/null and b/public/logo/ws.png differ diff --git a/public/logo/xrp.png b/public/logo/xrp.png new file mode 100644 index 0000000..4f31676 Binary files /dev/null and b/public/logo/xrp.png differ diff --git a/public/nginx.htaccess b/public/nginx.htaccess new file mode 100644 index 0000000..8356068 --- /dev/null +++ b/public/nginx.htaccess @@ -0,0 +1,5 @@ +location / { + if (!-e $request_filename){ + rewrite ^(.*)$ /index.php?s=/$1 last; + } +} \ No newline at end of file diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 0000000..a82d96e --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/public/router.php b/public/router.php new file mode 100644 index 0000000..ad261d5 --- /dev/null +++ b/public/router.php @@ -0,0 +1,19 @@ + +// +---------------------------------------------------------------------- +// $Id$ + +if (is_file($_SERVER["DOCUMENT_ROOT"] . $_SERVER["SCRIPT_NAME"])) { + return false; +} else { + $_SERVER["SCRIPT_FILENAME"] = __DIR__ . '/index.php'; + + require __DIR__ . "/index.php"; +} diff --git a/public/static/.gitignore b/public/static/.gitignore new file mode 100644 index 0000000..a3a0c8b --- /dev/null +++ b/public/static/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/route/app.php b/route/app.php new file mode 100644 index 0000000..cd855f8 --- /dev/null +++ b/route/app.php @@ -0,0 +1,3 @@ +console->run(); \ No newline at end of file diff --git a/vendor/adbario/php-dot-notation/LICENSE.md b/vendor/adbario/php-dot-notation/LICENSE.md new file mode 100644 index 0000000..fe01323 --- /dev/null +++ b/vendor/adbario/php-dot-notation/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) 2016-2019 Riku Särkinen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/adbario/php-dot-notation/composer.json b/vendor/adbario/php-dot-notation/composer.json new file mode 100644 index 0000000..cea7126 --- /dev/null +++ b/vendor/adbario/php-dot-notation/composer.json @@ -0,0 +1,29 @@ +{ + "name": "adbario/php-dot-notation", + "description": "PHP dot notation access to arrays", + "keywords": ["dotnotation", "arrayaccess"], + "homepage": "https://github.com/adbario/php-dot-notation", + "license": "MIT", + "authors": [ + { + "name": "Riku Särkinen", + "email": "riku@adbar.io" + } + ], + "require": { + "php": "^5.5 || ^7.0 || ^8.0", + "ext-json": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7|^6.6|^7.5|^8.5|^9.5", + "squizlabs/php_codesniffer": "^3.6" + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Adbar\\": "src" + } + } +} diff --git a/vendor/adbario/php-dot-notation/src/Dot.php b/vendor/adbario/php-dot-notation/src/Dot.php new file mode 100644 index 0000000..3cd1c50 --- /dev/null +++ b/vendor/adbario/php-dot-notation/src/Dot.php @@ -0,0 +1,623 @@ + + * @link https://github.com/adbario/php-dot-notation + * @license https://github.com/adbario/php-dot-notation/blob/2.x/LICENSE.md (MIT License) + */ +namespace Adbar; + +use Countable; +use ArrayAccess; +use ArrayIterator; +use JsonSerializable; +use IteratorAggregate; + +/** + * Dot + * + * This class provides a dot notation access and helper functions for + * working with arrays of data. Inspired by Laravel Collection. + */ +class Dot implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable +{ + /** + * The stored items + * + * @var array + */ + protected $items = []; + + + /** + * The delimiter (alternative to a '.') to be used. + * + * @var string + */ + protected $delimiter = '.'; + + + /** + * Create a new Dot instance + * + * @param mixed $items + * @param string $delimiter + */ + public function __construct($items = [], $delimiter = '.') + { + $this->items = $this->getArrayItems($items); + $this->delimiter = strlen($delimiter) ? $delimiter : '.'; + } + + /** + * Set a given key / value pair or pairs + * if the key doesn't exist already + * + * @param array|int|string $keys + * @param mixed $value + */ + public function add($keys, $value = null) + { + if (is_array($keys)) { + foreach ($keys as $key => $value) { + $this->add($key, $value); + } + } elseif (is_null($this->get($keys))) { + $this->set($keys, $value); + } + } + + /** + * Return all the stored items + * + * @return array + */ + public function all() + { + return $this->items; + } + + /** + * Delete the contents of a given key or keys + * + * @param array|int|string|null $keys + */ + public function clear($keys = null) + { + if (is_null($keys)) { + $this->items = []; + + return; + } + + $keys = (array) $keys; + + foreach ($keys as $key) { + $this->set($key, []); + } + } + + /** + * Delete the given key or keys + * + * @param array|int|string $keys + */ + public function delete($keys) + { + $keys = (array) $keys; + + foreach ($keys as $key) { + if ($this->exists($this->items, $key)) { + unset($this->items[$key]); + + continue; + } + + $items = &$this->items; + $segments = explode($this->delimiter, $key); + $lastSegment = array_pop($segments); + + foreach ($segments as $segment) { + if (!isset($items[$segment]) || !is_array($items[$segment])) { + continue 2; + } + + $items = &$items[$segment]; + } + + unset($items[$lastSegment]); + } + } + + /** + * Checks if the given key exists in the provided array. + * + * @param array $array Array to validate + * @param int|string $key The key to look for + * + * @return bool + */ + protected function exists($array, $key) + { + return array_key_exists($key, $array); + } + + /** + * Flatten an array with the given character as a key delimiter + * + * @param string $delimiter + * @param array|null $items + * @param string $prepend + * @return array + */ + public function flatten($delimiter = '.', $items = null, $prepend = '') + { + $flatten = []; + + if (is_null($items)) { + $items = $this->items; + } + + if (!func_num_args()) { + $delimiter = $this->delimiter; + } + + foreach ($items as $key => $value) { + if (is_array($value) && !empty($value)) { + $flatten = array_merge( + $flatten, + $this->flatten($delimiter, $value, $prepend.$key.$delimiter) + ); + } else { + $flatten[$prepend.$key] = $value; + } + } + + return $flatten; + } + + /** + * Return the value of a given key + * + * @param int|string|null $key + * @param mixed $default + * @return mixed + */ + public function get($key = null, $default = null) + { + if (is_null($key)) { + return $this->items; + } + + if ($this->exists($this->items, $key)) { + return $this->items[$key]; + } + + if (strpos($key, $this->delimiter) === false) { + return $default; + } + + $items = $this->items; + + foreach (explode($this->delimiter, $key) as $segment) { + if (!is_array($items) || !$this->exists($items, $segment)) { + return $default; + } + + $items = &$items[$segment]; + } + + return $items; + } + + /** + * Return the given items as an array + * + * @param mixed $items + * @return array + */ + protected function getArrayItems($items) + { + if (is_array($items)) { + return $items; + } elseif ($items instanceof self) { + return $items->all(); + } + + return (array) $items; + } + + /** + * Check if a given key or keys exists + * + * @param array|int|string $keys + * @return bool + */ + public function has($keys) + { + $keys = (array) $keys; + + if (!$this->items || $keys === []) { + return false; + } + + foreach ($keys as $key) { + $items = $this->items; + + if ($this->exists($items, $key)) { + continue; + } + + foreach (explode($this->delimiter, $key) as $segment) { + if (!is_array($items) || !$this->exists($items, $segment)) { + return false; + } + + $items = $items[$segment]; + } + } + + return true; + } + + /** + * Check if a given key or keys are empty + * + * @param array|int|string|null $keys + * @return bool + */ + public function isEmpty($keys = null) + { + if (is_null($keys)) { + return empty($this->items); + } + + $keys = (array) $keys; + + foreach ($keys as $key) { + if (!empty($this->get($key))) { + return false; + } + } + + return true; + } + + /** + * Merge a given array or a Dot object with the given key + * or with the whole Dot object + * + * @param array|string|self $key + * @param array|self $value + */ + public function merge($key, $value = []) + { + if (is_array($key)) { + $this->items = array_merge($this->items, $key); + } elseif (is_string($key)) { + $items = (array) $this->get($key); + $value = array_merge($items, $this->getArrayItems($value)); + + $this->set($key, $value); + } elseif ($key instanceof self) { + $this->items = array_merge($this->items, $key->all()); + } + } + + /** + * Recursively merge a given array or a Dot object with the given key + * or with the whole Dot object. + * + * Duplicate keys are converted to arrays. + * + * @param array|string|self $key + * @param array|self $value + */ + public function mergeRecursive($key, $value = []) + { + if (is_array($key)) { + $this->items = array_merge_recursive($this->items, $key); + } elseif (is_string($key)) { + $items = (array) $this->get($key); + $value = array_merge_recursive($items, $this->getArrayItems($value)); + + $this->set($key, $value); + } elseif ($key instanceof self) { + $this->items = array_merge_recursive($this->items, $key->all()); + } + } + + /** + * Recursively merge a given array or a Dot object with the given key + * or with the whole Dot object. + * + * Instead of converting duplicate keys to arrays, the value from + * given array will replace the value in Dot object. + * + * @param array|string|self $key + * @param array|self $value + */ + public function mergeRecursiveDistinct($key, $value = []) + { + if (is_array($key)) { + $this->items = $this->arrayMergeRecursiveDistinct($this->items, $key); + } elseif (is_string($key)) { + $items = (array) $this->get($key); + $value = $this->arrayMergeRecursiveDistinct($items, $this->getArrayItems($value)); + + $this->set($key, $value); + } elseif ($key instanceof self) { + $this->items = $this->arrayMergeRecursiveDistinct($this->items, $key->all()); + } + } + + /** + * Merges two arrays recursively. In contrast to array_merge_recursive, + * duplicate keys are not converted to arrays but rather overwrite the + * value in the first array with the duplicate value in the second array. + * + * @param array $array1 Initial array to merge + * @param array $array2 Array to recursively merge + * @return array + */ + protected function arrayMergeRecursiveDistinct(array $array1, array $array2) + { + $merged = &$array1; + + foreach ($array2 as $key => $value) { + if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) { + $merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value); + } else { + $merged[$key] = $value; + } + } + + return $merged; + } + + /** + * Return the value of a given key and + * delete the key + * + * @param int|string|null $key + * @param mixed $default + * @return mixed + */ + public function pull($key = null, $default = null) + { + if (is_null($key)) { + $value = $this->all(); + $this->clear(); + + return $value; + } + + $value = $this->get($key, $default); + $this->delete($key); + + return $value; + } + + /** + * Push a given value to the end of the array + * in a given key + * + * @param mixed $key + * @param mixed $value + */ + public function push($key, $value = null) + { + if (is_null($value)) { + $this->items[] = $key; + + return; + } + + $items = $this->get($key); + + if (is_array($items) || is_null($items)) { + $items[] = $value; + $this->set($key, $items); + } + } + + /** + * Replace all values or values within the given key + * with an array or Dot object + * + * @param array|string|self $key + * @param array|self $value + */ + public function replace($key, $value = []) + { + if (is_array($key)) { + $this->items = array_replace($this->items, $key); + } elseif (is_string($key)) { + $items = (array) $this->get($key); + $value = array_replace($items, $this->getArrayItems($value)); + + $this->set($key, $value); + } elseif ($key instanceof self) { + $this->items = array_replace($this->items, $key->all()); + } + } + + /** + * Set a given key / value pair or pairs + * + * @param array|int|string $keys + * @param mixed $value + */ + public function set($keys, $value = null) + { + if (is_array($keys)) { + foreach ($keys as $key => $value) { + $this->set($key, $value); + } + + return; + } + + $items = &$this->items; + + foreach (explode($this->delimiter, $keys) as $key) { + if (!isset($items[$key]) || !is_array($items[$key])) { + $items[$key] = []; + } + + $items = &$items[$key]; + } + + $items = $value; + } + + /** + * Replace all items with a given array + * + * @param mixed $items + */ + public function setArray($items) + { + $this->items = $this->getArrayItems($items); + } + + /** + * Replace all items with a given array as a reference + * + * @param array $items + */ + public function setReference(array &$items) + { + $this->items = &$items; + } + + /** + * Return the value of a given key or all the values as JSON + * + * @param mixed $key + * @param int $options + * @return string + */ + public function toJson($key = null, $options = 0) + { + if (is_string($key)) { + return json_encode($this->get($key), $options); + } + + $options = $key === null ? 0 : $key; + + return json_encode($this->items, $options); + } + + /* + * -------------------------------------------------------------- + * ArrayAccess interface + * -------------------------------------------------------------- + */ + + /** + * Check if a given key exists + * + * @param int|string $key + * @return bool + */ + #[\ReturnTypeWillChange] + public function offsetExists($key) + { + return $this->has($key); + } + + /** + * Return the value of a given key + * + * @param int|string $key + * @return mixed + */ + #[\ReturnTypeWillChange] + public function offsetGet($key) + { + return $this->get($key); + } + + /** + * Set a given value to the given key + * + * @param int|string|null $key + * @param mixed $value + */ + #[\ReturnTypeWillChange] + public function offsetSet($key, $value) + { + if (is_null($key)) { + $this->items[] = $value; + + return; + } + + $this->set($key, $value); + } + + /** + * Delete the given key + * + * @param int|string $key + */ + #[\ReturnTypeWillChange] + public function offsetUnset($key) + { + $this->delete($key); + } + + /* + * -------------------------------------------------------------- + * Countable interface + * -------------------------------------------------------------- + */ + + /** + * Return the number of items in a given key + * + * @param int|string|null $key + * @return int + */ + #[\ReturnTypeWillChange] + public function count($key = null) + { + return count($this->get($key)); + } + + /* + * -------------------------------------------------------------- + * IteratorAggregate interface + * -------------------------------------------------------------- + */ + + /** + * Get an iterator for the stored items + * + * @return \ArrayIterator + */ + #[\ReturnTypeWillChange] + public function getIterator() + { + return new ArrayIterator($this->items); + } + + /* + * -------------------------------------------------------------- + * JsonSerializable interface + * -------------------------------------------------------------- + */ + + /** + * Return items for JSON serialization + * + * @return array + */ + #[\ReturnTypeWillChange] + public function jsonSerialize() + { + return $this->items; + } +} diff --git a/vendor/adbario/php-dot-notation/src/helpers.php b/vendor/adbario/php-dot-notation/src/helpers.php new file mode 100644 index 0000000..bebb952 --- /dev/null +++ b/vendor/adbario/php-dot-notation/src/helpers.php @@ -0,0 +1,24 @@ + + * @link https://github.com/adbario/php-dot-notation + * @license https://github.com/adbario/php-dot-notation/blob/2.x/LICENSE.md (MIT License) + */ + +use Adbar\Dot; + +if (! function_exists('dot')) { + /** + * Create a new Dot object with the given items and optional delimiter + * + * @param mixed $items + * @param string $delimiter + * @return \Adbar\Dot + */ + function dot($items, $delimiter = '.') + { + return new Dot($items, $delimiter); + } +} diff --git a/vendor/alibabacloud/client/CHANGELOG.md b/vendor/alibabacloud/client/CHANGELOG.md new file mode 100644 index 0000000..ad5fcf8 --- /dev/null +++ b/vendor/alibabacloud/client/CHANGELOG.md @@ -0,0 +1,311 @@ +# CHANGELOG + +## 1.5.32 - 2022-12-08 + +- Support PHP versions: From 5.5 up to 8.1 + +## 1.5.31 - 2021-05-13 + +- Deprecate `\GuzzleHttp\Psr7\parse_query` method + +## 1.5.30 - 2021-03-22 +- Fixed incompatibility in PHP 5.6 version. + +## 1.5.29 - 2020-08-03 +- Fixed RPC Signature. + +## 1.5.28 - 2020-08-03 +- Updated `endpoints`. + +## 1.5.27 - 2020-07-17 +- Fixed composer error config. + +## 1.5.26 - 2020-07-17 +- Validate RegionID/EndpointSuffix/Network. + +## 1.5.25 - 2020-07-04 +- Fixed ROA signature. +- Deprecated `LogFormatter`. + +## 1.5.24 - 2020-06-04 +- Fixed Resolve Host. + +## 1.5.23 - 2020-05-22 +- Optimized global product support. + +## 1.5.22 - 2020-05-12 +- Updated Endpoints. + +## 1.5.21 - 2020-02-26 +- Improved Nonce. +- Updated Endpoints. + +## 1.5.20 - 2019-12-30 +- Improved Docs. +- Updated Endpoints. + +## 1.5.19 - 2019-12-17 +- Updated Endpoints. + +## 1.5.18 - 2019-10-11 +- Updated Request link. +- Updated Endpoints data. + +## 1.5.17 - 2019-09-15 +- Improved Host Finder. +- Updated Endpoints Data. + +## 1.5.16 - 2019-08-21 +- Updated Endpoints Data. + +## 1.5.15 - 2019-08-14 +- Improved Client. + + +## 1.5.14 - 2019-07-25 +- Improved Credential Filter. + + +## 1.5.13 - 2019-07-18 +- Improved API Resolver. + + +## 1.5.12 - 2019-06-20 +- Fixed Signature for ROA. + + +## 1.5.11 - 2019-06-14 +- Added endpoint rules. + + +## 1.5.10 - 2019-06-13 +- Improved `Resovler`. +- Updated `endpoints`. + + +## 1.5.9 - 2019-06-04 +- Improved `UUID`. + + +## 1.5.8 - 2019-05-30 +- Improved `Arrays`. + + +## 1.5.7 - 2019-05-29 +- Improved `uuid`. + + +## 1.5.6 - 2019-05-29 +- Fixed `uuid` version lock. + + +## 1.5.5 - 2019-05-23 +- Improved `Signature`. + + +## 1.5.4 - 2019-05-22 +- Updated `Endpoints`. +- Fixed `Content-Type` in header. + + +## 1.5.3 - 2019-05-13 +- Improved `Endpoint` tips. +- Improved `Endpoints` for `STS`. + + +## 1.5.2 - 2019-05-10 +- Improved `Result` object. + + +## 1.5.1 - 2019-05-09 +- Supported `Resolver` for Third-party dependencies. + + +## 1.5.0 - 2019-05-07 +- Improved `Resolver` for products. + + +## 1.4.0 - 2019-05-06 +- Support `Retry` and `Asynchronous` for Request. + + +## 1.3.1 - 2019-04-30 +- Allow timeouts to be set in microseconds. + + +## 1.3.0 - 2019-04-18 +- Improved parameters methods. +- Optimized the logic for body encode. + + +## 1.2.1 - 2019-04-11 +- Improve exception code and message for `Region ID`. + + +## 1.2.0 - 2019-04-11 +- Improve exception message for `Region ID`. + + +## 1.1.1 - 2019-04-02 +- Added endpoints for `batchcomputenew`, `privatelink`. +- Improve Region ID tips. + + +## 1.1.0 - 2019-04-01 +- Updated `composer.json`. + + +## 1.0.27 - 2019-03-31 +- Support `Policy` for `ramRoleArnClient`. + + +## 1.0.26 - 2019-03-27 +- Support `pid`, `cost`, `start_time` for Log. + + +## 1.0.25 - 2019-03-27 +- Updated default log format. +- Add endpoints for `dbs`. + + +## 1.0.24 - 2019-03-26 +- Support Log. + + +## 1.0.23 - 2019-03-23 +- Remove SVG. + + +## 1.0.22 - 2019-03-20 +- Add endpoint `cn-hangzhou` for `idaas` . + + +## 1.0.21 - 2019-03-19 +- Installing by Using the ZIP file. +- Update Docs. + + +## 1.0.20 - 2019-03-13 +- Improve Tests. +- Update Docs. + + +## 1.0.19 - 2019-03-12 +- Add SSL Verify Option `verify()`. + + +## 1.0.18 - 2019-03-11 +- Add endpoints for `acr`. +- Add endpoints for `faas`. +- Add endpoints for `ehs`. +- SSL certificates are not validated by default. + + +## 1.0.17 - 2019-03-08 +- Support Mock for Test. + + +## 1.0.16 - 2019-03-07 +- Support Credential Provider Chain. +- Support `CCC`. +- Add `ap-south-1` for `cas`. +- Add `ap-southeast-1` for `waf`. +- Update Docs. + + +## 1.0.15 - 2019-02-27 +- Add endpoints for `Chatbot`. +- Change endpoints for `drdspost` and `drdspre`. + + +## 1.0.14 - 2019-02-21 +- Enable debug mode by set environment variable `DEBUG=sdk`. + + +## 1.0.13 - 2019-02-18 +- Support Release Script `composer release`. +- Add endpoints for apigateway in `drdspre` in `cn-qingdao`. +- Add endpoints for apigateway in `drdspre` in `cn-beijing`. +- Add endpoints for apigateway in `drdspre` in `cn-hangzhou`. +- Add endpoints for apigateway in `drdspre` in `cn-shanghai`. +- Add endpoints for apigateway in `drdspre` in `cn-shenzhen`. +- Add endpoints for apigateway in `drdspre` in `cn-hongkong`. +- Add endpoints for apigateway in `drdspost` in `ap-southeast-1`. +- Add endpoints for apigateway in `drdspost` in `cn-shanghai`. +- Add endpoints for apigateway in `drdspost` in `cn-hongkong`. +- Add endpoints for apigateway in `vod` in `ap-southeast-1`. +- Add endpoints for apigateway in `vod` in `eu-central-1`. + + +## 1.0.12 - 2019-02-16 +- Support `open_basedir`. + + +## 1.0.11 - 2019-02-13 +- Improve User Agent. + + +## 1.0.10 - 2019-02-12 +- `userAgentAppend` is renamed to `appendUserAgent`. + + +## 1.0.9 - 2019-02-12 +- `userAgent` is renamed to `userAgentAppend`. + + +## 1.0.8 - 2019-02-11 +- `userAgent` - Support DIY User Agent. +- Add endpoints for apigateway in Zhangjiakou. +- Add endpoints for apigateway in Hu He Hao Te. +- Add endpoints for vod in Hu He Hao Te. +- Add endpoints for hsm in Zhangjiakou. +- Add endpoints for luban in Germany. +- Add endpoints for linkwan in Hangzhou. +- Add endpoints for drdspost in Singapore. + + +## 1.0.7 - 2019-01-28 +- Add endpoints for gpdb in Tokyo. +- Add endpoints for elasticsearch in Beijing. + + +## 1.0.6 - 2019-01-23 +- Add endpoints for dysmsapi in Singapore. +- Add endpoints for dybaseapi. +- Add endpoints for dyiotapi. +- Add endpoints for dycdpapi. +- Add endpoints for dyplsapi. +- Add endpoints for dypnsapi. +- Add endpoints for dyvmsapi. +- Add endpoints for snsuapi. + + +## 1.0.5 - 2019-01-21 +- Add endpoints for ApiGateway in Silicon Valley, Virginia. +- Add endpoints for Image Search in Shanghai. + + +## 1.0.4 - 2019-01-17 +- Support fixer all. +- Add Endpoints. + + +## 1.0.3 - 2019-01-15 +- Update Endpoints. +- Update README.md. +- Update Return Result Message. + + +## 1.0.2 - 2019-01-15 +- Optimize the documentation. +- Adjust the CI configuration. + + +## 1.0.1 - 2019-01-09 +- Distinguish credential error. +- Add endpoints for NLS. +- Add not found product tip. + + +## 1.0.0 - 2019-01-07 +- Initial release of the Alibaba Cloud Client for PHP Version 1.0.0 on Packagist See for more information. diff --git a/vendor/alibabacloud/client/CONTRIBUTING.md b/vendor/alibabacloud/client/CONTRIBUTING.md new file mode 100644 index 0000000..a1c52a0 --- /dev/null +++ b/vendor/alibabacloud/client/CONTRIBUTING.md @@ -0,0 +1,30 @@ +# Contributing to the Alibaba Cloud Client for PHP + +We work hard to provide a high-quality and useful SDK for Alibaba Cloud, and +we greatly value feedback and contributions from our community. Please submit +your [issues][issues] or [pull requests][pull-requests] through GitHub. + +## Tips + +- The SDK is released under the [Apache license][license]. Any code you submit + will be released under that license. For substantial contributions, we may + ask you to sign a [Alibaba Documentation Corporate Contributor License + Agreement (CLA)][cla]. +- We follow all of the relevant PSR recommendations from the [PHP Framework + Interop Group][php-fig]. Please submit code that follows these standards. + The [PHP CS Fixer][cs-fixer] tool can be helpful for formatting your code. + Your can use `composer fixer` to fix code. +- We maintain a high percentage of code coverage in our unit tests. If you make + changes to the code, please add, update, and/or remove tests as appropriate. +- If your code does not conform to the PSR standards, does not include adequate + tests, or does not contain a changelog document, we may ask you to update + your pull requests before we accept them. We also reserve the right to deny + any pull requests that do not align with our standards or goals. + +[issues]: https://github.com/aliyun/openapi-sdk-php-client/issues +[pull-requests]: https://github.com/aliyun/openapi-sdk-php-client/pulls +[license]: http://www.apache.org/licenses/LICENSE-2.0 +[cla]: https://alibaba-cla-2018.oss-cn-beijing.aliyuncs.com/Alibaba_Documentation_Open_Source_Corporate_CLA.pdf +[php-fig]: http://php-fig.org +[cs-fixer]: http://cs.sensiolabs.org/ +[docs-readme]: https://github.com/aliyun/openapi-sdk-php-client/blob/master/README.md diff --git a/vendor/alibabacloud/client/LICENSE.md b/vendor/alibabacloud/client/LICENSE.md new file mode 100644 index 0000000..ec13fcc --- /dev/null +++ b/vendor/alibabacloud/client/LICENSE.md @@ -0,0 +1,13 @@ +Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/alibabacloud/client/NOTICE.md b/vendor/alibabacloud/client/NOTICE.md new file mode 100644 index 0000000..db04164 --- /dev/null +++ b/vendor/alibabacloud/client/NOTICE.md @@ -0,0 +1,88 @@ +# Alibaba Cloud Client for PHP + + + +Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"). +You may not use this file except in compliance with the License. +A copy of the License is located at + + + +or in the "license" file accompanying this file. This file is distributed +on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +express or implied. See the License for the specific language governing +permissions and limitations under the License. + +# Guzzle + + + +Copyright (c) 2011-2018 Michael Dowling, https://github.com/mtdowling + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +# jmespath.php + + + +Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +# Dot + + + +Copyright (c) 2016-2019 Riku Särkinen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/alibabacloud/client/README-zh-CN.md b/vendor/alibabacloud/client/README-zh-CN.md new file mode 100644 index 0000000..b27d282 --- /dev/null +++ b/vendor/alibabacloud/client/README-zh-CN.md @@ -0,0 +1,168 @@ +[English](/README.md) | 简体中文 + + +# Alibaba Cloud Client for PHP +[![Latest Stable Version](https://poser.pugx.org/alibabacloud/client/v/stable)](https://packagist.org/packages/alibabacloud/client) +[![composer.lock](https://poser.pugx.org/alibabacloud/client/composerlock)](https://packagist.org/packages/alibabacloud/client) +[![Total Downloads](https://poser.pugx.org/alibabacloud/client/downloads)](https://packagist.org/packages/alibabacloud/client) +[![License](https://poser.pugx.org/alibabacloud/client/license)](https://packagist.org/packages/alibabacloud/client) +[![codecov](https://codecov.io/gh/aliyun/openapi-sdk-php-client/branch/master/graph/badge.svg?token=90Yd5Bne3S)](https://codecov.io/gh/aliyun/openapi-sdk-php-client) +[![PHP Version Require](http://poser.pugx.org/alibabacloud/client/require/php)](https://packagist.org/packages/alibabacloud/client) + + +![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg) + + +Alibaba Cloud Client for PHP 是帮助 PHP 开发者管理凭据、发送请求的客户端工具,[Alibaba Cloud SDK for PHP][SDK] 由本工具提供底层支持。 + + +## 使用诊断 +[Troubleshoot](https://troubleshoot.api.aliyun.com/?source=github_sdk) 提供 OpenAPI 使用诊断服务,通过 `RequestID` 或 `报错信息` ,帮助开发者快速定位,为开发者提供解决方案。 + +## 在线示例 +[阿里云 OpenAPI 开发者门户]https://next.api.aliyun.com/) 提供在线调用阿里云产品,并动态生成 SDK 代码和快速检索接口等能力,能显著降低使用云 API 的难度。 + + +## 先决条件 +您的系统需要满足[先决条件](/docs/zh-CN/0-Prerequisites.md),包括 PHP> = 5.5。 我们强烈建议使用cURL扩展,并使用TLS后端编译cURL 7.16.2+。 + + +## 安装依赖 +如果已在系统上[全局安装 Composer](https://getcomposer.org/doc/00-intro.md#globally),请直接在项目目录中运行以下内容来安装 Alibaba Cloud Client for PHP 作为依赖项: +``` +composer require alibabacloud/client +``` +> 一些用户可能由于网络问题无法安装,可以使用[阿里云 Composer 全量镜像](https://developer.aliyun.com/composer)。 + +请看[安装](/docs/zh-CN/1-Installation.md)有关通过 Composer 和其他方式安装的详细信息。 + + +## 快速使用 +在您开始之前,您需要注册阿里云帐户并获取您的[凭证](https://usercenter.console.aliyun.com/#/manage/ak)。 + +```php +asDefaultClient(); +``` + + +## 请求 +> 请求风格分为 `ROA` 和 `RPC`,不同产品风格不同,使用前,请参考产品文档。推荐使用 [Alibaba Cloud SDK for PHP][SDK] ,细节已被封装,无需关心风格。 + + +### ROA 请求 +```php +regionId('cn-hangzhou') // 指定请求的区域,不指定则使用客户端区域、默认区域 + ->product('CS') // 指定产品 + ->version('2015-12-15') // 指定产品版本 + ->action('DescribeClusterServices') // 指定产品接口 + ->serviceCode('cs') // 设置 ServiceCode 以备寻址,非必须 + ->endpointType('openAPI') // 设置类型,非必须 + ->method('GET') // 指定请求方式 + ->host('cs.aliyun.com') // 指定域名则不会寻址,如认证方式为 Bearer Token 的服务则需要指定 + ->pathPattern('/clusters/[ClusterId]/services') // 指定ROA风格路径规则 + ->withClusterId('123456') // 为路径中参数赋值,方法名:with + 参数 + ->request(); // 发起请求并返回结果对象,请求需要放在设置的最后面 + + print_r($result->toArray()); + +} catch (ClientException $exception) { + print_r($exception->getErrorMessage()); +} catch (ServerException $exception) { + print_r($exception->getErrorMessage()); +} +``` + +### RPC 请求 +```php +product('Cdn') + ->version('2014-11-11') + ->action('DescribeCdnService') + ->method('POST') + ->request(); + + print_r($result->toArray()); + +} catch (ClientException $exception) { + print_r($exception->getErrorMessage()); +} catch (ServerException $exception) { + print_r($exception->getErrorMessage()); +} +``` + + +## 文档 +* [先决条件](/docs/zh-CN/0-Prerequisites.md) +* [安装](/docs/zh-CN/1-Installation.md) +* [客户端和凭证](/docs/zh-CN/2-Client.md) +* [请求](/docs/zh-CN/3-Request.md) +* [结果](/docs/zh-CN/4-Result.md) +* [区域](/docs/zh-CN/5-Region.md) +* [域名](/docs/zh-CN/6-Host.md) +* [SSL 验证](/docs/zh-CN/7-Verify.md) +* [调试](/docs/zh-CN/8-Debug.md) +* [日志](/docs/zh-CN/9-Log.md) +* [测试](/docs/zh-CN/10-Test.md) + + +## 问题 +[提交 Issue](https://github.com/aliyun/openapi-sdk-php-client/issues/new/choose),不符合指南的问题可能会立即关闭。 + + +## 发行说明 +每个版本的详细更改记录在[发行说明](/CHANGELOG.md)中。 + + +## 贡献 +提交 Pull Request 之前请阅读[贡献指南](/CONTRIBUTING.md)。 + + +## 相关 +* [阿里云服务 Regions & Endpoints][endpoints] +* [阿里云 OpenAPI 开发者门户][open-api] +* [Packagist][packagist] +* [Composer][composer] +* [Guzzle中文文档][guzzle-docs] +* [最新源码][latest-release] + + +## 许可证 +[Apache-2.0](/LICENSE.md) + +Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + + +[SDK]: https://github.com/aliyun/openapi-sdk-php +[open-api]: https://next.api.aliyun.com/ +[latest-release]: https://github.com/aliyun/openapi-sdk-php-client +[guzzle-docs]: https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html +[composer]: https://getcomposer.org +[packagist]: https://packagist.org/packages/alibabacloud/sdk +[home]: https://home.console.aliyun.com +[aliyun]: https://www.aliyun.com +[regions]: https://help.aliyun.com/document_detail/40654.html +[endpoints]: https://developer.aliyun.com/endpoints +[cURL]: http://php.net/manual/zh/book.curl.php +[OPCache]: http://php.net/manual/zh/book.opcache.php +[xdebug]: http://xdebug.org +[OpenSSL]: http://php.net/manual/zh/book.openssl.php +[client]: https://github.com/aliyun/openapi-sdk-php-client diff --git a/vendor/alibabacloud/client/README.md b/vendor/alibabacloud/client/README.md new file mode 100644 index 0000000..dacf2bf --- /dev/null +++ b/vendor/alibabacloud/client/README.md @@ -0,0 +1,167 @@ +English | [简体中文](/README-zh-CN.md) + + +# Alibaba Cloud Client for PHP +[![Latest Stable Version](https://poser.pugx.org/alibabacloud/client/v/stable)](https://packagist.org/packages/alibabacloud/client) +[![composer.lock](https://poser.pugx.org/alibabacloud/client/composerlock)](https://packagist.org/packages/alibabacloud/client) +[![Total Downloads](https://poser.pugx.org/alibabacloud/client/downloads)](https://packagist.org/packages/alibabacloud/client) +[![License](https://poser.pugx.org/alibabacloud/client/license)](https://packagist.org/packages/alibabacloud/client) +[![codecov](https://codecov.io/gh/aliyun/openapi-sdk-php-client/branch/master/graph/badge.svg?token=90Yd5Bne3S)](https://codecov.io/gh/aliyun/openapi-sdk-php-client) +[![PHP Version Require](http://poser.pugx.org/alibabacloud/client/require/php)](https://packagist.org/packages/alibabacloud/client) + + +![](https://aliyunsdk-pages.alicdn.com/icons/AlibabaCloud.svg) + + +Alibaba Cloud Client for PHP is a client tool that helps PHP developers manage credentials and send requests, [Alibaba Cloud SDK for PHP][SDK] dependency on this tool. + +## Troubleshoot +[Troubleshoot](https://troubleshoot.api.aliyun.com/?source=github_sdk) Provide OpenAPI diagnosis service to help developers locate quickly and provide solutions for developers through `RequestID` or `error message`. + +## Online Demo +[Alibaba Cloud OpenAPI Developer Portal](https://next.api.aliyun.com/) provides the ability to call the cloud product OpenAPI online, and dynamically generate SDK Example code and quick retrieval interface, which can significantly reduce the difficulty of using the cloud API. + +## Prerequisites +Your system will need to meet the [Prerequisites](/docs/en-US/0-Prerequisites.md), including having PHP >= 5.5. We highly recommend having it compiled with the cURL extension and cURL 7.16.2+. + + +## Installation +If Composer is already [installed globally on your system](https://getcomposer.org/doc/00-intro.md#globally), run the following in the base directory of your project to install Alibaba Cloud Client for PHP as a dependency: +``` +composer require alibabacloud/client +``` +> Some users may not be able to install due to network problems, you can try to switch the Composer mirror. + +Please see the [Installation](/docs/en-US/1-Installation.md) for more detailed information about installing the Alibaba Cloud Client for PHP through Composer and other means. + + +## Quick Examples +Before you begin, you need to sign up for an Alibaba Cloud account and retrieve your [Credentials](https://usercenter.console.aliyun.com/#/manage/ak). + +### Create Client +```php +asDefaultClient(); +``` + + +## Request +> Request styles are divided into `ROA` and `RPC`. Different product styles are different. Please refer to the product documentation before using. It is recommended to use [Alibaba cloud SDK for PHP][SDK], the details have been encapsulated, and you do not need to care about the style. + + +### ROA Request +```php +regionId('cn-hangzhou') // Specify the requested regionId, if not specified, use the client regionId, then default regionId + ->product('CS') // Specify product + ->version('2015-12-15') // Specify product version + ->action('DescribeClusterServices') // Specify product interface + ->serviceCode('cs') // Set ServiceCode for addressing, optional + ->endpointType('openAPI') // Set type, optional + ->method('GET') // Set request method + ->host('cs.aliyun.com') // Location Service will not be enabled if the host is specified. For example, service with a Certification type-Bearer Token should be specified + ->pathPattern('/clusters/[ClusterId]/services') // Specify path rule with ROA-style + ->withClusterId('123456') // Assign values to parameters in the path. Method: with + Parameter + ->request(); // Make a request and return to result object. The request is to be placed at the end of the setting + + print_r($result->toArray()); + +} catch (ClientException $exception) { + print_r($exception->getErrorMessage()); +} catch (ServerException $exception) { + print_r($exception->getErrorMessage()); +} +``` + +### RPC Request +```php +product('Cdn') + ->version('2014-11-11') + ->action('DescribeCdnService') + ->method('POST') + ->request(); + + print_r($result->toArray()); + +} catch (ClientException $exception) { + print_r($exception->getErrorMessage()); +} catch (ServerException $exception) { + print_r($exception->getErrorMessage()); +} +``` + + +## Documentation +* [Prerequisites](/docs/en-US/0-Prerequisites.md) +* [Installation](/docs/en-US/1-Installation.md) +* [Client & Credentials](/docs/en-US/2-Client.md) +* [Request](/docs/en-US/3-Request.md) +* [Result](/docs/en-US/4-Result.md) +* [Region](/docs/en-US/5-Region.md) +* [Host](/docs/en-US/6-Host.md) +* [SSL Verify](/docs/en-US/7-Verify.md) +* [Debug](/docs/en-US/8-Debug.md) +* [Log](/docs/en-US/9-Log.md) +* [Test](/docs/en-US/10-Test.md) + + +## Issues +[Opening an Issue](https://github.com/aliyun/openapi-sdk-php-client/issues/new/choose), Issues not conforming to the guidelines may be closed immediately. + + +## Changelog +Detailed changes for each release are documented in the [release notes](/CHANGELOG.md). + + +## Contribution +Please make sure to read the [Contributing Guide](/CONTRIBUTING.md) before making a pull request. + + +## References +* [Alibaba Cloud Regions & Endpoints][endpoints] +* [Alibaba Cloud OpenAPI Developer Portal][open-api] +* [Packagist][packagist] +* [Composer][composer] +* [Guzzle Documentation][guzzle-docs] +* [Latest Release][latest-release] + + +## License +[Apache-2.0](/LICENSE.md) + +Copyright (c) 2009-present, Alibaba Cloud All rights reserved. + + +[SDK]: https://github.com/aliyun/openapi-sdk-php +[open-api]: https://next.api.aliyun.com/ +[latest-release]: https://github.com/aliyun/openapi-sdk-php-client +[guzzle-docs]: http://docs.guzzlephp.org/en/stable/request-options.html +[composer]: https://getcomposer.org +[packagist]: https://packagist.org/packages/alibabacloud/sdk +[home]: https://home.console.aliyun.com +[alibabacloud]: https://www.alibabacloud.com +[regions]: https://www.alibabacloud.com/help/doc-detail/40654.html +[endpoints]: https://developer.aliyun.com/endpoints +[cURL]: http://php.net/manual/en/book.curl.php +[OPCache]: http://php.net/manual/en/book.opcache.php +[xdebug]: http://xdebug.org +[OpenSSL]: http://php.net/manual/en/book.openssl.php +[client]: https://github.com/aliyun/openapi-sdk-php-client diff --git a/vendor/alibabacloud/client/UPGRADING.md b/vendor/alibabacloud/client/UPGRADING.md new file mode 100644 index 0000000..08c1bb3 --- /dev/null +++ b/vendor/alibabacloud/client/UPGRADING.md @@ -0,0 +1,6 @@ +Upgrading Guide +=============== + +1.x +----------------------- +- This is the first version. See for more information. diff --git a/vendor/alibabacloud/client/autoload.php b/vendor/alibabacloud/client/autoload.php new file mode 100644 index 0000000..e654320 --- /dev/null +++ b/vendor/alibabacloud/client/autoload.php @@ -0,0 +1,17 @@ +=5.5", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-openssl": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "mtdowling/jmespath.php": "^2.5", + "adbario/php-dot-notation": "^2.4.1", + "clagiordano/weblibs-configmanager": "^1.0" + }, + "require-dev": { + "ext-spl": "*", + "ext-dom": "*", + "ext-pcre": "*", + "psr/cache": "^1.0", + "ext-sockets": "*", + "drupal/coder": "^8.3", + "symfony/dotenv": "^3.4", + "league/climate": "^3.2.4", + "phpunit/phpunit": "^5.7|^6.6|^7.5|^8.5|^9.5", + "monolog/monolog": "^1.24", + "composer/composer": "^1.8", + "mikey179/vfsstream": "^1.6", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "autoload": { + "psr-4": { + "AlibabaCloud\\Client\\": "src" + }, + "files": [ + "src/Functions.php" + ] + }, + "autoload-dev": { + "psr-4": { + "AlibabaCloud\\Client\\Tests\\": "tests/" + } + }, + "config": { + "preferred-install": "dist", + "optimize-autoloader": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "scripts-descriptions": { + "cs": "Tokenizes PHP, JavaScript and CSS files to detect violations of a defined coding standard.", + "cbf": "Automatically correct coding standard violations.", + "fixer": "Fixes code to follow standards.", + "test": "Run all tests.", + "unit": "Run Unit tests.", + "feature": "Run Feature tests.", + "clearCache": "Clear cache like coverage.", + "coverage": "Show Coverage html.", + "endpoints": "Update endpoints from OSS." + }, + "scripts": { + "cs": "phpcs --standard=PSR2 -n ./", + "cbf": "phpcbf --standard=PSR2 -n ./", + "fixer": "php-cs-fixer fix ./", + "test": [ + "phpunit --colors=always" + ], + "test4HighVersion": [ + "@clearCache", + "phpunit --testsuite=Test4HighVersion --colors=always" + ], + "test4LowVersion": [ + "@clearCache", + "phpunit --testsuite=Test4LowVersion --colors=always" + ], + "unit4HighVersion": [ + "@clearCache", + "phpunit --testsuite=Unit4HighVersion --colors=always" + ], + "unit4LowVersion": [ + "@clearCache", + "phpunit --testsuite=Unit4LowVersion --colors=always" + ], + "feature4HighVersion": [ + "@clearCache", + "phpunit --testsuite=Feature4HighVersion --colors=always" + ], + "feature4LowVersion": [ + "@clearCache", + "phpunit --testsuite=Feature4LowVersion --colors=always" + ], + "coverage": "open cache/coverage/index.html", + "clearCache": "rm -rf cache/*", + "endpoints": [ + "AlibabaCloud\\Client\\Regions\\LocationService::updateEndpoints", + "@fixer" + ], + "release": [ + "AlibabaCloud\\Client\\Release::release" + ] + } +} diff --git a/vendor/alibabacloud/client/src/Accept.php b/vendor/alibabacloud/client/src/Accept.php new file mode 100644 index 0000000..e7c5261 --- /dev/null +++ b/vendor/alibabacloud/client/src/Accept.php @@ -0,0 +1,53 @@ +format = $format; + } + + /** + * @param $format + * + * @return Accept + */ + public static function create($format) + { + return new static($format); + } + + /** + * @return mixed|string + */ + public function toString() + { + $key = \strtoupper($this->format); + + $list = [ + 'JSON' => 'application/json', + 'XML' => 'application/xml', + 'RAW' => 'application/octet-stream', + 'FORM' => 'application/x-www-form-urlencoded' + ]; + + return isset($list[$key]) ? $list[$key] : $list['RAW']; + } +} diff --git a/vendor/alibabacloud/client/src/AlibabaCloud.php b/vendor/alibabacloud/client/src/AlibabaCloud.php new file mode 100644 index 0000000..16847fa --- /dev/null +++ b/vendor/alibabacloud/client/src/AlibabaCloud.php @@ -0,0 +1,62 @@ +credential = $credential; + $this->signature = $signature; + $this->options['connect_timeout'] = Request::CONNECT_TIMEOUT; + $this->options['timeout'] = Request::TIMEOUT; + $this->options['verify'] = false; + } + + /** + * @return AccessKeyCredential|BearerTokenCredential|CredentialsInterface|EcsRamRoleCredential|RamRoleArnCredential|RsaKeyPairCredential|StsCredential + */ + public function getCredential() + { + return $this->credential; + } + + /** + * @return SignatureInterface|BearerTokenSignature|ShaHmac1Signature|ShaHmac256Signature|ShaHmac256WithRsaSignature + */ + public function getSignature() + { + return $this->signature; + } +} diff --git a/vendor/alibabacloud/client/src/Clients/EcsRamRoleClient.php b/vendor/alibabacloud/client/src/Clients/EcsRamRoleClient.php new file mode 100644 index 0000000..e97cd6c --- /dev/null +++ b/vendor/alibabacloud/client/src/Clients/EcsRamRoleClient.php @@ -0,0 +1,26 @@ +credential)) { + case EcsRamRoleCredential::class: + return (new EcsRamRoleProvider($this))->get(); + case RamRoleArnCredential::class: + return (new RamRoleArnProvider($this))->get($timeout, $connectTimeout); + case RsaKeyPairCredential::class: + return (new RsaKeyPairProvider($this))->get($timeout, $connectTimeout); + default: + return $this->credential; + } + } + + /** + * @return static + * @throws ClientException + * @deprecated + * @codeCoverageIgnore + */ + public function asGlobalClient() + { + return $this->asDefaultClient(); + } + + /** + * Set the current client as the default client. + * + * @return static + * @throws ClientException + */ + public function asDefaultClient() + { + return $this->name(CredentialsProvider::getDefaultName()); + } + + /** + * Naming clients. + * + * @param string $name + * + * @return static + * @throws ClientException + */ + public function name($name) + { + Filter::name($name); + + return AlibabaCloud::set($name, $this); + } + + /** + * @return bool + */ + public function isDebug() + { + if (isset($this->options['debug'])) { + return $this->options['debug'] === true && PHP_SAPI === 'cli'; + } + + return false; + } +} diff --git a/vendor/alibabacloud/client/src/Clients/RamRoleArnClient.php b/vendor/alibabacloud/client/src/Clients/RamRoleArnClient.php new file mode 100644 index 0000000..b7d3087 --- /dev/null +++ b/vendor/alibabacloud/client/src/Clients/RamRoleArnClient.php @@ -0,0 +1,33 @@ +getValue( + \strtolower($configPath), + $defaultValue + ); + } + + /** + * @return ConfigManager + */ + private static function getConfigManager() + { + if (!self::$configManager instanceof ConfigManager) { + self::$configManager = new ConfigManager(__DIR__ . DIRECTORY_SEPARATOR . 'Data.php'); + } + + return self::$configManager; + } + + /** + * @param string $configPath + * @param mixed $newValue + * + * @return ConfigManager + * @throws Exception + */ + public static function set($configPath, $newValue) + { + self::getConfigManager()->setValue(\strtolower($configPath), $newValue); + + return self::getConfigManager()->saveConfigFile(); + } +} diff --git a/vendor/alibabacloud/client/src/Config/Data.php b/vendor/alibabacloud/client/src/Config/Data.php new file mode 100644 index 0000000..883b2f0 --- /dev/null +++ b/vendor/alibabacloud/client/src/Config/Data.php @@ -0,0 +1,3799 @@ + + [ + 'dysmsapi' => + [ + 'cn-hangzhou' => 'dysmsapi.aliyuncs.com', + 'ap-southeast-1' => 'dysmsapi.ap-southeast-1.aliyuncs.com', + ], + 'ccc' => + [ + 'global' => 'ccc.cn-shanghai.aliyuncs.com', + 'cn-shanghai' => 'ccc.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'ccc.cn-hangzhou.aliyuncs.com', + ], + 'dbs' => + [ + 'cn-hangzhou' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'dbs-api.ap-southeast-1.aliyuncs.com', + 'ap-northeast-1' => 'dbs-api.ap-northeast-1.aliyuncs.com', + ], + 'dybaseapi' => + [ + 'global' => 'dybaseapi.aliyuncs.com', + 'cn-hangzhou' => 'dybaseapi.aliyuncs.com', + ], + 'dyiotapi' => + [ + 'global' => 'dyiotapi.aliyuncs.com', + 'cn-hangzhou' => 'dyiotapi.aliyuncs.com', + ], + 'dycdpapi' => + [ + 'global' => 'dycdpapi.aliyuncs.com', + 'cn-hangzhou' => 'dycdpapi.aliyuncs.com', + ], + 'dyplsapi' => + [ + 'global' => 'dyplsapi.aliyuncs.com', + 'cn-hangzhou' => 'dyplsapi.aliyuncs.com', + ], + 'dypnsapi' => + [ + 'global' => 'dypnsapi.aliyuncs.com', + 'cn-hangzhou' => 'dypnsapi.aliyuncs.com', + ], + 'dyvmsapi' => + [ + 'global' => 'dyvmsapi.aliyuncs.com', + 'cn-hangzhou' => 'dyvmsapi.aliyuncs.com', + ], + 'snsuapi' => + [ + 'global' => 'snsuapi.aliyuncs.com', + 'cn-hangzhou' => 'snsuapi.aliyuncs.com', + ], + 'ecs' => + [ + 'jp-fudao-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'me-east-1' => 'ecs.me-east-1.aliyuncs.com', + 'us-east-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'ap-northeast-1' => 'ecs.ap-northeast-1.aliyuncs.com', + 'cn-hangzhou-bj-b01' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-beijing-nu16-b01' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-beijing-am13-c01' => 'ecs-cn-hangzhou.aliyuncs.com', + 'in-west-antgroup-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-guizhou-gov' => 'ecs-cn-hangzhou.aliyuncs.com', + 'in-west-antgroup-2' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'ecs-cn-hangzhou.aliyuncs.com', + 'tw-snowcloud-kaohsiung' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-finance-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-guizhou' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-fujian' => 'ecs-cn-hangzhou.aliyuncs.com', + 'in-mumbai-alipay' => 'ecs-cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-anhui-gov-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-haidian-cm12-c01' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-anhui-gov' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'ecs-cn-hangzhou.aliyuncs.com', + 'ap-southeast-2' => 'ecs.ap-southeast-2.aliyuncs.com', + 'cn-qingdao' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-su18-b02' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-su18-b03' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-su18-b01' => 'ecs-cn-hangzhou.aliyuncs.com', + 'ap-southeast-antgroup-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-henan-am12001' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-gansu-am6' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-ningxiazhongwei' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-ningxia-am7-c01' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-st4-d01' => 'ecs-cn-hangzhou.aliyuncs.com', + 'eu-central-1' => 'ecs.eu-central-1.aliyuncs.com', + 'cn-zhangjiakou' => 'ecs.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'ecs.cn-huhehaote.aliyuncs.com', + 'ap-southeast-3' => 'ecs.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'ecs.ap-southeast-5.aliyuncs.com', + 'eu-west-1' => 'ecs.eu-west-1.aliyuncs.com', + 'ap-south-1' => 'ecs.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'ecs.cn-chengdu.aliyuncs.com', + 'cn-north-2-gov-1' => 'ecs.aliyuncs.com', + 'cn-edge-1' => 'ecs.cn-qingdao-nebula.aliyuncs.com', + 'cn-hangzhou-internal-prod-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-internal-test-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-internal-test-2' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-internal-test-3' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-huhehaote-nebula-1' => 'ecs.cn-qingdao-nebula.aliyuncs.com', + 'cn-qingdao-nebula' => 'ecs.cn-qingdao-nebula.aliyuncs.com', + 'cn-shanghai-internal-test-1' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-zhangbei-na61-b01' => 'ecs-cn-hangzhou.aliyuncs.com', + 'cn-zhengzhou-nebula-1' => 'ecs.cn-qingdao-nebula.aliyuncs.com', + 'eu-west-1-oxs' => 'ecs.cn-shenzhen-cloudstone.aliyuncs.com', + 'cn-heyuan' => 'ecs.cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'ecs.cn-wulanchabu.aliyuncs.com', + ], + 'rds' => + [ + 'me-east-1' => 'rds.me-east-1.aliyuncs.com', + 'us-east-1' => 'rds.aliyuncs.com', + 'ap-northeast-1' => 'rds.ap-northeast-1.aliyuncs.com', + 'cn-hongkong' => 'rds.aliyuncs.com', + 'cn-qingdao-cm9' => 'rds.aliyuncs.com', + 'cn-shanghai-finance-1' => 'rds.aliyuncs.com', + 'cn-beijing-gov-1' => 'rds.aliyuncs.com', + 'cn-shanghai' => 'rds.aliyuncs.com', + 'cn-shenzhen-inner' => 'rds.aliyuncs.com', + 'cn-fujian' => 'rds.aliyuncs.com', + 'us-west-1' => 'rds.aliyuncs.com', + 'cn-shanghai-inner' => 'rds.aliyuncs.com', + 'cn-hangzhou' => 'rds.aliyuncs.com', + 'cn-beijing-inner' => 'rds.aliyuncs.com', + 'cn-haidian-cm12-c01' => 'rds.aliyuncs.com', + 'cn-shenzhen' => 'rds.aliyuncs.com', + 'ap-southeast-2' => 'rds.ap-southeast-2.aliyuncs.com', + 'cn-qingdao' => 'rds.aliyuncs.com', + 'cn-beijing' => 'rds.aliyuncs.com', + 'cn-hangzhou-d' => 'rds.aliyuncs.com', + 'cn-gansu-am6' => 'rds.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'rds.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'rds.aliyuncs.com', + 'ap-southeast-1' => 'rds.aliyuncs.com', + 'eu-central-1' => 'rds.eu-central-1.aliyuncs.com', + 'cn-zhangjiakou' => 'rds.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'rds.cn-huhehaote.aliyuncs.com', + 'ap-southeast-3' => 'rds.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'rds.ap-southeast-5.aliyuncs.com', + 'eu-west-1' => 'rds.eu-west-1.aliyuncs.com', + 'ap-south-1' => 'rds.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'rds.cn-chengdu.aliyuncs.com', + 'cn-north-2-gov-1' => 'rds.aliyuncs.com', + 'cn-yushanfang' => 'rds.aliyuncs.com', + 'cn-huhehaote-nebula-1' => 'rds.cn-chengdu.aliyuncs.com', + 'cn-heyuan' => 'rds.aliyuncs.com', + ], + 'vpc' => + [ + 'me-east-1' => 'vpc.me-east-1.aliyuncs.com', + 'us-east-1' => 'vpc.aliyuncs.com', + 'ap-northeast-1' => 'vpc.ap-northeast-1.aliyuncs.com', + 'cn-hongkong' => 'vpc.aliyuncs.com', + 'cn-beijing-am13-c01' => 'vpc.aliyuncs.com', + 'cn-guizhou-gov' => 'vpc.aliyuncs.com', + 'cn-shanghai-finance-1' => 'vpc.aliyuncs.com', + 'cn-guizhou' => 'vpc.aliyuncs.com', + 'cn-shanghai' => 'vpc.aliyuncs.com', + 'us-west-1' => 'vpc.aliyuncs.com', + 'cn-hangzhou' => 'vpc.aliyuncs.com', + 'cn-haidian-cm12-c01' => 'vpc.aliyuncs.com', + 'cn-anhui-gov' => 'vpc.aliyuncs.com', + 'cn-shenzhen' => 'vpc.aliyuncs.com', + 'ap-southeast-2' => 'vpc.ap-southeast-2.aliyuncs.com', + 'cn-henan-am12001' => 'vpc.aliyuncs.com', + 'cn-beijing' => 'vpc.aliyuncs.com', + 'cn-gansu-am6' => 'vpc.aliyuncs.com', + 'cn-ningxiazhongwei' => 'vpc.aliyuncs.com', + 'cn-ningxia-am7-c01' => 'vpc.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'vpc.aliyuncs.com', + 'ap-southeast-1' => 'vpc.aliyuncs.com', + 'eu-central-1' => 'vpc.eu-central-1.aliyuncs.com', + 'cn-zhangjiakou' => 'vpc.cn-zhangjiakou.aliyuncs.com', + 'cn-qingdao' => 'vpc.aliyuncs.com', + 'cn-huhehaote' => 'vpc.cn-huhehaote.aliyuncs.com', + 'ap-southeast-3' => 'vpc.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'vpc.ap-southeast-5.aliyuncs.com', + 'eu-west-1' => 'vpc.eu-west-1.aliyuncs.com', + 'ap-south-1' => 'vpc.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'vpc.cn-chengdu.aliyuncs.com', + 'cn-north-2-gov-1' => 'vpc.aliyuncs.com', + 'ap-northeast-2-pop' => 'vpc.aliyuncs.com', + 'cn-beijing-finance-1' => 'vpc.aliyuncs.com', + 'cn-beijing-finance-pop' => 'vpc.aliyuncs.com', + 'cn-edge-1' => 'vpc-nebula.cn-qingdao-nebula.aliyuncs.com', + 'cn-hangzhou-internal-test-1' => 'vpc.aliyuncs.com', + 'cn-hangzhou-internal-test-2' => 'vpc.aliyuncs.com', + 'cn-hangzhou-internal-test-3' => 'vpc.aliyuncs.com', + 'cn-hongkong-finance-pop' => 'vpc.aliyuncs.com', + 'cn-huhehaote-nebula-1' => 'vpc-nebula.cn-qingdao-nebula.aliyuncs.com', + 'cn-qingdao-nebula' => 'vpc-nebula.cn-qingdao-nebula.aliyuncs.com', + 'cn-shanghai-et15-b01' => 'vpc.aliyuncs.com', + 'cn-wuhan' => 'vpc.aliyuncs.com', + 'cn-zhangbei-na61-b01' => 'vpc.aliyuncs.com', + 'cn-zhengzhou-nebula-1' => 'vpc-nebula.cn-qingdao-nebula.aliyuncs.com', + 'eu-west-1-oxs' => 'vpc-nebula.cn-shenzhen-cloudstone.aliyuncs.com', + 'rus-west-1-pop' => 'vpc.aliyuncs.com', + 'cn-heyuan' => 'vpc.cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'vpc.cn-wulanchabu.aliyuncs.com', + ], + 'kms' => + [ + 'me-east-1' => 'kms.me-east-1.aliyuncs.com', + 'ap-northeast-1' => 'kms.ap-northeast-1.aliyuncs.com', + 'cn-hongkong' => 'kms.cn-hongkong.aliyuncs.com', + 'cn-shanghai-finance-1' => 'kms.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shanghai' => 'kms.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'kms.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'kms.cn-shenzhen.aliyuncs.com', + 'ap-southeast-2' => 'kms.ap-southeast-2.aliyuncs.com', + 'cn-beijing' => 'kms.cn-beijing.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'kms.cn-shenzhen-finance-1.aliyuncs.com', + 'ap-southeast-1' => 'kms.ap-southeast-1.aliyuncs.com', + 'eu-central-1' => 'kms.eu-central-1.aliyuncs.com', + 'cn-qingdao' => 'kms.cn-qingdao.aliyuncs.com', + 'cn-zhangjiakou' => 'kms.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'kms.cn-huhehaote.aliyuncs.com', + 'ap-southeast-3' => 'kms.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'kms.ap-southeast-5.aliyuncs.com', + 'eu-west-1' => 'kms.eu-west-1.aliyuncs.com', + 'us-west-1' => 'kms.us-west-1.aliyuncs.com', + 'us-east-1' => 'kms.us-east-1.aliyuncs.com', + 'ap-south-1' => 'kms.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'kms.cn-chengdu.aliyuncs.com', + 'cn-hangzhou-finance' => 'kms.cn-hangzhou-finance.aliyuncs.com', + 'cn-north-2-gov-1' => 'kms.cn-north-2-gov-1.aliyuncs.com', + 'cn-hangzhou-internal-test-1' => 'kms.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-internal-test-2' => 'kms.cn-hangzhou.aliyuncs.com', + 'cn-heyuan' => 'kms.cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'kms.cn-wulanchabu.aliyuncs.com', + ], + 'cms' => + [ + 'me-east-1' => 'metrics.cn-hangzhou.aliyuncs.com', + 'us-east-1' => 'metrics.cn-hangzhou.aliyuncs.com', + 'ap-northeast-1' => 'metrics.ap-northeast-1.aliyuncs.com', + 'cn-hongkong' => 'metrics.cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'metrics.aliyuncs.com', + 'cn-shanghai' => 'metrics.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'metrics.aliyuncs.com', + 'us-west-1' => 'metrics.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'metrics.aliyuncs.com', + 'cn-hangzhou' => 'metrics.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'metrics.aliyuncs.com', + 'cn-shenzhen' => 'metrics.cn-hangzhou.aliyuncs.com', + 'ap-southeast-2' => 'metrics.cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'metrics.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'metrics.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'metrics.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'metrics.aliyuncs.com', + 'ap-southeast-1' => 'metrics.cn-hangzhou.aliyuncs.com', + 'eu-central-1' => 'metrics.cn-hangzhou.aliyuncs.com', + 'cn-zhangjiakou' => 'metrics.cn-hangzhou.aliyuncs.com', + 'cn-huhehaote' => 'metrics.cn-huhehaote.aliyuncs.com', + 'ap-southeast-3' => 'metrics.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'metrics.ap-southeast-5.aliyuncs.com', + 'eu-west-1' => 'metrics.eu-west-1.aliyuncs.com', + 'ap-south-1' => 'metrics.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'metrics.cn-chengdu.aliyuncs.com', + 'cn-shanghai-finance-1' => 'metrics.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'metrics.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'metrics.cn-north-2-gov-1.aliyuncs.com', + 'cn-qingdao-nebula' => 'metrics.cn-qingdao-nebula.aliyuncs.com', + 'cn-heyuan' => 'metrics.cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'metrics.cn-wulanchabu.aliyuncs.com', + ], + 'slb' => + [ + 'me-east-1' => 'slb.me-east-1.aliyuncs.com', + 'us-east-1' => 'slb.aliyuncs.com', + 'ap-northeast-1' => 'slb.ap-northeast-1.aliyuncs.com', + 'cn-hongkong' => 'slb.aliyuncs.com', + 'cn-qingdao-cm9' => 'slb.aliyuncs.com', + 'cn-shanghai' => 'slb.aliyuncs.com', + 'cn-shenzhen-inner' => 'slb.aliyuncs.com', + 'us-west-1' => 'slb.aliyuncs.com', + 'cn-shanghai-inner' => 'slb.aliyuncs.com', + 'cn-hangzhou' => 'slb.aliyuncs.com', + 'cn-beijing-inner' => 'slb.aliyuncs.com', + 'cn-shenzhen' => 'slb.aliyuncs.com', + 'ap-southeast-2' => 'slb.ap-southeast-2.aliyuncs.com', + 'cn-qingdao' => 'slb.aliyuncs.com', + 'cn-beijing' => 'slb.aliyuncs.com', + 'cn-hangzhou-d' => 'slb.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'slb.aliyuncs.com', + 'ap-southeast-1' => 'slb.aliyuncs.com', + 'eu-central-1' => 'slb.eu-central-1.aliyuncs.com', + 'cn-zhangjiakou' => 'slb.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'slb.cn-huhehaote.aliyuncs.com', + 'ap-southeast-3' => 'slb.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'slb.ap-southeast-5.aliyuncs.com', + 'eu-west-1' => 'slb.eu-west-1.aliyuncs.com', + 'ap-south-1' => 'slb.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'slb.cn-chengdu.aliyuncs.com', + 'cn-shanghai-finance-1' => 'slb.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'slb.aliyuncs.com', + 'cn-north-2-gov-1' => 'slb.aliyuncs.com', + 'cn-fujian' => 'slb.aliyuncs.com', + 'cn-haidian-cm12-c01' => 'slb.aliyuncs.com', + 'cn-hangzhou-test-306' => 'slb.aliyuncs.com', + 'cn-huhehaote-nebula-1' => 'slb-api.cn-qingdao-nebula.aliyuncs.com', + 'cn-heyuan' => 'slb.cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'slb.cn-wulanchabu.aliyuncs.com', + ], + 'cs' => + [ + 'us-east-1' => 'cs.us-east-1.aliyuncs.com', + 'cn-hongkong' => 'cs.cn-hongkong.aliyuncs.com', + 'cn-qingdao-cm9' => 'cs.aliyuncs.com', + 'cn-shanghai' => 'cs.cn-shanghai.aliyuncs.com', + 'cn-shenzhen-inner' => 'cs.aliyuncs.com', + 'us-west-1' => 'cs.us-west-1.aliyuncs.com', + 'cn-shanghai-inner' => 'cs.aliyuncs.com', + 'cn-hangzhou' => 'cs.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'cs.aliyuncs.com', + 'cn-shenzhen' => 'cs.cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'cs.aliyuncs.com', + 'cn-beijing' => 'cs.cn-beijing.aliyuncs.com', + 'cn-hangzhou-d' => 'cs.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'cs.aliyuncs.com', + 'ap-southeast-1' => 'cs.ap-southeast-1.aliyuncs.com', + 'cn-chengdu' => 'cs.cn-chengdu.aliyuncs.com', + 'cn-zhangjiakou' => 'cs.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'cs.cn-huhehaote.aliyuncs.com', + 'ap-southeast-2' => 'cs.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'cs.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'cs.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'cs.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'cs.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'cs.eu-central-1.aliyuncs.com', + 'me-east-1' => 'cs.me-east-1.aliyuncs.com', + 'ap-south-1' => 'cs.ap-south-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'cs.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'cs.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'cs.cn-north-2-gov-1.aliyuncs.com', + ], + 'push' => + [ + 'us-east-1' => 'cloudpush.aliyuncs.com', + 'cn-hongkong' => 'cloudpush.aliyuncs.com', + 'cn-qingdao-cm9' => 'cloudpush.aliyuncs.com', + 'cn-shanghai' => 'cloudpush.aliyuncs.com', + 'cn-shenzhen-inner' => 'cloudpush.aliyuncs.com', + 'us-west-1' => 'cloudpush.aliyuncs.com', + 'cn-shanghai-inner' => 'cloudpush.aliyuncs.com', + 'cn-hangzhou' => 'cloudpush.aliyuncs.com', + 'cn-beijing-inner' => 'cloudpush.aliyuncs.com', + 'cn-shenzhen' => 'cloudpush.aliyuncs.com', + 'cn-qingdao' => 'cloudpush.aliyuncs.com', + 'cn-beijing' => 'cloudpush.aliyuncs.com', + 'cn-hangzhou-d' => 'cloudpush.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'cloudpush.aliyuncs.com', + 'ap-southeast-1' => 'cloudpush.aliyuncs.com', + ], + 'cos' => + [ + 'us-east-1' => 'cos.aliyuncs.com', + 'cn-hongkong' => 'cos.aliyuncs.com', + 'cn-qingdao-cm9' => 'cos.aliyuncs.com', + 'cn-shanghai' => 'cos.aliyuncs.com', + 'cn-shenzhen-inner' => 'cos.aliyuncs.com', + 'us-west-1' => 'cos.aliyuncs.com', + 'cn-shanghai-inner' => 'cos.aliyuncs.com', + 'cn-hangzhou' => 'cos.aliyuncs.com', + 'cn-beijing-inner' => 'cos.aliyuncs.com', + 'cn-shenzhen' => 'cos.aliyuncs.com', + 'cn-qingdao' => 'cos.aliyuncs.com', + 'cn-beijing' => 'cos.aliyuncs.com', + 'cn-hangzhou-d' => 'cos.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'cos.aliyuncs.com', + 'ap-southeast-1' => 'cos.aliyuncs.com', + ], + 'ess' => + [ + 'us-east-1' => 'ess.aliyuncs.com', + 'cn-hongkong' => 'ess.aliyuncs.com', + 'cn-qingdao-cm9' => 'ess.aliyuncs.com', + 'cn-shanghai' => 'ess.aliyuncs.com', + 'cn-shenzhen-inner' => 'ess.aliyuncs.com', + 'us-west-1' => 'ess.aliyuncs.com', + 'cn-shanghai-inner' => 'ess.aliyuncs.com', + 'cn-hangzhou' => 'ess.aliyuncs.com', + 'cn-beijing-inner' => 'ess.aliyuncs.com', + 'cn-shenzhen' => 'ess.aliyuncs.com', + 'cn-qingdao' => 'ess.aliyuncs.com', + 'cn-beijing' => 'ess.aliyuncs.com', + 'cn-hangzhou-d' => 'ess.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ess.aliyuncs.com', + 'ap-southeast-1' => 'ess.aliyuncs.com', + 'cn-zhangjiakou' => 'ess.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'ess.cn-huhehaote.aliyuncs.com', + 'ap-southeast-2' => 'ess.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'ess.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'ess.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'ess.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'ess.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'ess.eu-central-1.aliyuncs.com', + 'me-east-1' => 'ess.me-east-1.aliyuncs.com', + 'ap-south-1' => 'ess.ap-south-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'ess.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'ess.aliyuncs.com', + 'cn-north-2-gov-1' => 'ess.aliyuncs.com', + 'cn-chengdu' => 'ess.cn-chengdu.aliyuncs.com', + 'cn-haidian-cm12-c01' => 'ess.aliyuncs.com', + 'cn-heyuan' => 'ess.cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'ess.cn-wulanchabu.aliyuncs.com', + ], + 'ace-ops' => + [ + 'us-east-1' => 'ace-ops.cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'ace-ops.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'ace-ops.cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'ace-ops.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'ace-ops.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'ace-ops.cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'ace-ops.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'ace-ops.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ace-ops.cn-hangzhou.aliyuncs.com', + ], + 'billing' => + [ + 'us-east-1' => 'billing.aliyuncs.com', + 'cn-hongkong' => 'billing.aliyuncs.com', + 'cn-qingdao-cm9' => 'billing.aliyuncs.com', + 'cn-shanghai' => 'billing.aliyuncs.com', + 'cn-shenzhen-inner' => 'billing.aliyuncs.com', + 'us-west-1' => 'billing.aliyuncs.com', + 'cn-shanghai-inner' => 'billing.aliyuncs.com', + 'cn-hangzhou' => 'billing.aliyuncs.com', + 'cn-beijing-inner' => 'billing.aliyuncs.com', + 'cn-beijing' => 'billing.aliyuncs.com', + 'cn-hangzhou-d' => 'billing.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'billing.aliyuncs.com', + 'ap-southeast-1' => 'billing.aliyuncs.com', + ], + 'dqs' => + [ + 'us-east-1' => 'dqs.aliyuncs.com', + 'cn-hongkong' => 'dqs.aliyuncs.com', + 'cn-qingdao-cm9' => 'dqs.aliyuncs.com', + 'cn-shanghai' => 'dqs.aliyuncs.com', + 'cn-shenzhen-inner' => 'dqs.aliyuncs.com', + 'us-west-1' => 'dqs.aliyuncs.com', + 'cn-shanghai-inner' => 'dqs.aliyuncs.com', + 'cn-hangzhou' => 'dqs.aliyuncs.com', + 'cn-beijing-inner' => 'dqs.aliyuncs.com', + 'cn-shenzhen' => 'dqs.aliyuncs.com', + 'cn-qingdao' => 'dqs.aliyuncs.com', + 'cn-beijing' => 'dqs.aliyuncs.com', + 'cn-hangzhou-d' => 'dqs.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'dqs.aliyuncs.com', + 'ap-southeast-1' => 'dqs.aliyuncs.com', + ], + 'dds' => + [ + 'us-east-1' => 'mongodb.aliyuncs.com', + 'cn-hongkong' => 'mongodb.aliyuncs.com', + 'cn-qingdao-cm9' => 'mongodb.aliyuncs.com', + 'cn-shanghai' => 'mongodb.aliyuncs.com', + 'cn-shenzhen-inner' => 'mongodb.aliyuncs.com', + 'us-west-1' => 'mongodb.aliyuncs.com', + 'cn-shanghai-inner' => 'mongodb.aliyuncs.com', + 'cn-hangzhou' => 'mongodb.aliyuncs.com', + 'cn-beijing-inner' => 'mongodb.aliyuncs.com', + 'cn-shenzhen' => 'mongodb.aliyuncs.com', + 'cn-qingdao' => 'mongodb.aliyuncs.com', + 'cn-beijing' => 'mongodb.aliyuncs.com', + 'cn-hangzhou-d' => 'mongodb.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'mongodb.aliyuncs.com', + 'ap-southeast-1' => 'mongodb.aliyuncs.com', + 'cn-zhangjiakou' => 'mongodb.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'mongodb.cn-huhehaote.aliyuncs.com', + 'ap-southeast-2' => 'mongodb.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'mongodb.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'mongodb.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'mongodb.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'mongodb.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'mongodb.eu-central-1.aliyuncs.com', + 'me-east-1' => 'mongodb.me-east-1.aliyuncs.com', + 'ap-south-1' => 'mongodb.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'mongodb.cn-chengdu.aliyuncs.com', + 'cn-hangzhou-finance' => 'mongodb.aliyuncs.com', + 'cn-shanghai-finance-1' => 'mongodb.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'mongodb.aliyuncs.com', + 'cn-north-2-gov-1' => 'mongodb.aliyuncs.com', + 'cn-heyuan' => 'mongodb.aliyuncs.com', + 'cn-wulanchabu' => 'mongodb.aliyuncs.com', + ], + 'emr' => + [ + 'us-east-1' => 'emr.us-east-1.aliyuncs.com', + 'cn-hongkong' => 'emr.cn-hongkong.aliyuncs.com', + 'cn-qingdao-cm9' => 'emr.aliyuncs.com', + 'cn-shanghai' => 'emr.aliyuncs.com', + 'cn-shenzhen-inner' => 'emr.aliyuncs.com', + 'us-west-1' => 'emr.aliyuncs.com', + 'cn-shanghai-inner' => 'emr.aliyuncs.com', + 'cn-hangzhou' => 'emr.aliyuncs.com', + 'cn-beijing-inner' => 'emr.aliyuncs.com', + 'cn-shenzhen' => 'emr.aliyuncs.com', + 'cn-qingdao' => 'emr.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'emr.aliyuncs.com', + 'cn-hangzhou-d' => 'emr.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'emr.aliyuncs.com', + 'ap-southeast-1' => 'emr.aliyuncs.com', + 'cn-zhangjiakou' => 'emr.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'emr.cn-huhehaote.aliyuncs.com', + 'ap-southeast-2' => 'emr.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'emr.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'emr.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'emr.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'emr.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'emr.eu-central-1.aliyuncs.com', + 'me-east-1' => 'emr.me-east-1.aliyuncs.com', + 'ap-south-1' => 'emr.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'emr.cn-chengdu.aliyuncs.com', + 'cn-shanghai-finance-1' => 'emr.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'emr.aliyuncs.com', + ], + 'sms' => + [ + 'us-east-1' => 'sms.aliyuncs.com', + 'cn-hongkong' => 'sms.aliyuncs.com', + 'cn-qingdao-cm9' => 'sms.aliyuncs.com', + 'cn-shanghai' => 'sms.aliyuncs.com', + 'cn-shenzhen-inner' => 'sms.aliyuncs.com', + 'us-west-1' => 'sms.aliyuncs.com', + 'cn-shanghai-inner' => 'sms.aliyuncs.com', + 'cn-hangzhou' => 'sms.aliyuncs.com', + 'cn-beijing-inner' => 'sms.aliyuncs.com', + 'cn-shenzhen' => 'sms.aliyuncs.com', + 'cn-qingdao' => 'sms.aliyuncs.com', + 'cn-beijing' => 'sms.aliyuncs.com', + 'cn-hangzhou-d' => 'sms.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'sms.aliyuncs.com', + 'ap-southeast-1' => 'sms.aliyuncs.com', + ], + 'jaq' => + [ + 'us-east-1' => 'jaq.aliyuncs.com', + 'cn-hongkong' => 'jaq.aliyuncs.com', + 'cn-qingdao-cm9' => 'jaq.aliyuncs.com', + 'cn-shanghai' => 'jaq.aliyuncs.com', + 'cn-shenzhen-inner' => 'jaq.aliyuncs.com', + 'us-west-1' => 'jaq.aliyuncs.com', + 'cn-shanghai-inner' => 'jaq.aliyuncs.com', + 'cn-hangzhou' => 'jaq.aliyuncs.com', + 'cn-beijing-inner' => 'jaq.aliyuncs.com', + 'cn-shenzhen' => 'jaq.aliyuncs.com', + 'cn-qingdao' => 'jaq.aliyuncs.com', + 'cn-beijing' => 'jaq.aliyuncs.com', + 'cn-hangzhou-d' => 'jaq.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'jaq.aliyuncs.com', + 'ap-southeast-1' => 'jaq.aliyuncs.com', + ], + 'hpc' => + [ + 'us-east-1' => 'hpc.aliyuncs.com', + 'cn-hongkong' => 'hpc.aliyuncs.com', + 'cn-qingdao-cm9' => 'hpc.aliyuncs.com', + 'cn-shanghai' => 'hpc.aliyuncs.com', + 'cn-shenzhen-inner' => 'hpc.aliyuncs.com', + 'us-west-1' => 'hpc.aliyuncs.com', + 'cn-shanghai-inner' => 'hpc.aliyuncs.com', + 'cn-hangzhou' => 'hpc.aliyuncs.com', + 'cn-beijing-inner' => 'hpc.aliyuncs.com', + 'cn-shenzhen' => 'hpc.aliyuncs.com', + 'cn-qingdao' => 'hpc.aliyuncs.com', + 'cn-beijing' => 'hpc.aliyuncs.com', + 'cn-hangzhou-d' => 'hpc.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'hpc.aliyuncs.com', + 'ap-southeast-1' => 'hpc.aliyuncs.com', + ], + 'location' => + [ + 'us-east-1' => 'location.aliyuncs.com', + 'cn-hongkong' => 'location.aliyuncs.com', + 'cn-qingdao-cm9' => 'location.aliyuncs.com', + 'cn-shanghai' => 'location.aliyuncs.com', + 'cn-shenzhen-inner' => 'location.aliyuncs.com', + 'us-west-1' => 'location.aliyuncs.com', + 'cn-shanghai-inner' => 'location.aliyuncs.com', + 'cn-hangzhou' => 'location.aliyuncs.com', + 'cn-beijing-inner' => 'location.aliyuncs.com', + 'cn-shenzhen' => 'location.aliyuncs.com', + 'cn-qingdao' => 'location.aliyuncs.com', + 'cn-beijing' => 'location.aliyuncs.com', + 'cn-hangzhou-d' => 'location.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'location.aliyuncs.com', + 'ap-southeast-1' => 'location.aliyuncs.com', + ], + 'chargingservice' => + [ + 'us-east-1' => 'chargingservice.aliyuncs.com', + 'cn-hongkong' => 'chargingservice.aliyuncs.com', + 'cn-qingdao-cm9' => 'chargingservice.aliyuncs.com', + 'cn-shanghai' => 'chargingservice.aliyuncs.com', + 'cn-shenzhen-inner' => 'chargingservice.aliyuncs.com', + 'us-west-1' => 'chargingservice.aliyuncs.com', + 'cn-shanghai-inner' => 'chargingservice.aliyuncs.com', + 'cn-hangzhou' => 'chargingservice.aliyuncs.com', + 'cn-beijing-inner' => 'chargingservice.aliyuncs.com', + 'cn-beijing' => 'chargingservice.aliyuncs.com', + 'cn-hangzhou-d' => 'chargingservice.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'chargingservice.aliyuncs.com', + 'ap-southeast-1' => 'chargingservice.aliyuncs.com', + ], + 'msg' => + [ + 'us-east-1' => 'msg-inner.aliyuncs.com', + 'cn-hongkong' => 'msg-inner.aliyuncs.com', + 'cn-qingdao-cm9' => 'msg-inner.aliyuncs.com', + 'cn-shanghai' => 'msg-inner.aliyuncs.com', + 'cn-shenzhen-inner' => 'msg-inner.aliyuncs.com', + 'us-west-1' => 'msg-inner.aliyuncs.com', + 'cn-shanghai-inner' => 'msg-inner.aliyuncs.com', + 'cn-hangzhou' => 'msg-inner.aliyuncs.com', + 'cn-beijing-inner' => 'msg-inner.aliyuncs.com', + 'cn-beijing' => 'msg-inner.aliyuncs.com', + 'cn-hangzhou-d' => 'msg-inner.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'msg-inner.aliyuncs.com', + 'ap-southeast-1' => 'msg-inner.aliyuncs.com', + ], + 'commondriver' => + [ + 'us-east-1' => 'common.driver.aliyuncs.com', + 'cn-hongkong' => 'common.driver.aliyuncs.com', + 'cn-qingdao-cm9' => 'common.driver.aliyuncs.com', + 'cn-shanghai' => 'common.driver.aliyuncs.com', + 'cn-shenzhen-inner' => 'common.driver.aliyuncs.com', + 'us-west-1' => 'common.driver.aliyuncs.com', + 'cn-shanghai-inner' => 'common.driver.aliyuncs.com', + 'cn-hangzhou' => 'common.driver.aliyuncs.com', + 'cn-beijing-inner' => 'common.driver.aliyuncs.com', + 'cn-shenzhen' => 'common.driver.aliyuncs.com', + 'cn-qingdao' => 'common.driver.aliyuncs.com', + 'cn-beijing' => 'common.driver.aliyuncs.com', + 'cn-hangzhou-d' => 'common.driver.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'common.driver.aliyuncs.com', + 'ap-southeast-1' => 'common.driver.aliyuncs.com', + ], + 'r-kvstore' => + [ + 'us-east-1' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'r-kvstore-cn-hangzhou.aliyuncs.com', + ], + 'bss' => + [ + 'us-east-1' => 'bss.aliyuncs.com', + 'cn-hongkong' => 'bss.aliyuncs.com', + 'cn-qingdao-cm9' => 'bss.aliyuncs.com', + 'cn-shanghai' => 'bss.aliyuncs.com', + 'cn-shenzhen-inner' => 'bss.aliyuncs.com', + 'us-west-1' => 'bss.aliyuncs.com', + 'cn-shanghai-inner' => 'bss.aliyuncs.com', + 'cn-hangzhou' => 'bss.aliyuncs.com', + 'cn-beijing-inner' => 'bss.aliyuncs.com', + 'cn-shenzhen' => 'bss.aliyuncs.com', + 'cn-qingdao' => 'bss.aliyuncs.com', + 'cn-beijing' => 'bss.aliyuncs.com', + 'cn-hangzhou-d' => 'bss.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'bss.aliyuncs.com', + 'ap-southeast-1' => 'bss.aliyuncs.com', + ], + 'workorder' => + [ + 'us-east-1' => 'workorder.aliyuncs.com', + 'cn-hongkong' => 'workorder.aliyuncs.com', + 'cn-qingdao-cm9' => 'workorder.aliyuncs.com', + 'cn-shanghai' => 'workorder.aliyuncs.com', + 'cn-shenzhen-inner' => 'workorder.aliyuncs.com', + 'us-west-1' => 'workorder.aliyuncs.com', + 'cn-shanghai-inner' => 'workorder.aliyuncs.com', + 'cn-hangzhou' => 'workorder.aliyuncs.com', + 'cn-beijing-inner' => 'workorder.aliyuncs.com', + 'cn-beijing' => 'workorder.aliyuncs.com', + 'cn-hangzhou-d' => 'workorder.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'workorder.aliyuncs.com', + 'ap-southeast-1' => 'workorder.aliyuncs.com', + ], + 'ocs' => + [ + 'us-east-1' => 'm-kvstore.aliyuncs.com', + 'cn-hongkong' => 'm-kvstore.aliyuncs.com', + 'cn-qingdao-cm9' => 'm-kvstore.aliyuncs.com', + 'cn-shanghai' => 'm-kvstore.aliyuncs.com', + 'cn-shenzhen-inner' => 'm-kvstore.aliyuncs.com', + 'us-west-1' => 'm-kvstore.aliyuncs.com', + 'cn-shanghai-inner' => 'm-kvstore.aliyuncs.com', + 'cn-hangzhou' => 'm-kvstore.aliyuncs.com', + 'cn-beijing-inner' => 'm-kvstore.aliyuncs.com', + 'cn-shenzhen' => 'm-kvstore.aliyuncs.com', + 'cn-qingdao' => 'm-kvstore.aliyuncs.com', + 'cn-beijing' => 'm-kvstore.aliyuncs.com', + 'cn-hangzhou-d' => 'm-kvstore.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'm-kvstore.aliyuncs.com', + 'ap-southeast-1' => 'm-kvstore.aliyuncs.com', + ], + 'yundun' => + [ + 'us-east-1' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'yundun-cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'yundun-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'yundun-cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'yundun-cn-hangzhou.aliyuncs.com', + ], + 'ubsms-inner' => + [ + 'us-east-1' => 'ubsms-inner.aliyuncs.com', + 'cn-hongkong' => 'ubsms-inner.aliyuncs.com', + 'cn-qingdao-cm9' => 'ubsms-inner.aliyuncs.com', + 'cn-shanghai' => 'ubsms-inner.aliyuncs.com', + 'cn-shenzhen-inner' => 'ubsms-inner.aliyuncs.com', + 'us-west-1' => 'ubsms-inner.aliyuncs.com', + 'cn-shanghai-inner' => 'ubsms-inner.aliyuncs.com', + 'cn-hangzhou' => 'ubsms-inner.aliyuncs.com', + 'cn-beijing-inner' => 'ubsms-inner.aliyuncs.com', + 'cn-shenzhen' => 'ubsms-inner.aliyuncs.com', + 'cn-qingdao' => 'ubsms-inner.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'ubsms-inner.aliyuncs.com', + 'cn-hangzhou-d' => 'ubsms-inner.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ubsms-inner.aliyuncs.com', + 'ap-southeast-1' => 'ubsms-inner.aliyuncs.com', + ], + 'dm' => + [ + 'us-east-1' => 'dm.aliyuncs.com', + 'cn-hongkong' => 'dm.aliyuncs.com', + 'cn-qingdao-cm9' => 'dm.aliyuncs.com', + 'cn-shanghai' => 'dm.aliyuncs.com', + 'cn-shenzhen-inner' => 'dm.aliyuncs.com', + 'us-west-1' => 'dm.aliyuncs.com', + 'cn-shanghai-inner' => 'dm.aliyuncs.com', + 'cn-hangzhou' => 'dm.aliyuncs.com', + 'cn-beijing-inner' => 'dm.aliyuncs.com', + 'cn-shenzhen' => 'dm.aliyuncs.com', + 'cn-qingdao' => 'dm.aliyuncs.com', + 'cn-beijing' => 'dm.aliyuncs.com', + 'cn-hangzhou-d' => 'dm.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'dm.aliyuncs.com', + 'ap-southeast-1' => 'dm.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'dm.ap-southeast-2.aliyuncs.com', + ], + 'green' => + [ + 'us-east-1' => 'green.aliyuncs.com', + 'cn-hongkong' => 'green.aliyuncs.com', + 'cn-qingdao-cm9' => 'green.aliyuncs.com', + 'cn-shanghai' => 'green.cn-shanghai.aliyuncs.com', + 'cn-shenzhen-inner' => 'green.aliyuncs.com', + 'us-west-1' => 'green.us-west-1.aliyuncs.com', + 'cn-shanghai-inner' => 'green.aliyuncs.com', + 'cn-hangzhou' => 'green.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'green.aliyuncs.com', + 'cn-shenzhen' => 'green.cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'green.aliyuncs.com', + 'cn-beijing' => 'green.cn-beijing.aliyuncs.com', + 'cn-hangzhou-d' => 'green.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'green.aliyuncs.com', + 'ap-southeast-1' => 'green.ap-southeast-1.aliyuncs.com', + ], + 'risk' => + [ + 'us-east-1' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'risk-cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'risk-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'risk-cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'risk-cn-hangzhou.aliyuncs.com', + ], + 'oceanbase' => + [ + 'us-east-1' => 'oceanbase.aliyuncs.com', + 'cn-hongkong' => 'oceanbase.aliyuncs.com', + 'cn-qingdao-cm9' => 'oceanbase.aliyuncs.com', + 'cn-shanghai' => 'oceanbasepro-share.cn-shanghai.aliyuncs.com', + 'cn-shenzhen-inner' => 'oceanbase.aliyuncs.com', + 'us-west-1' => 'oceanbase.aliyuncs.com', + 'cn-shanghai-inner' => 'oceanbase.aliyuncs.com', + 'cn-hangzhou' => 'oceanbasepro-share.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'oceanbase.aliyuncs.com', + 'cn-shenzhen' => 'oceanbase.aliyuncs.com', + 'cn-qingdao' => 'oceanbase.aliyuncs.com', + 'cn-beijing' => 'oceanbasepro-share.cn-beijing.aliyuncs.com', + 'cn-hangzhou-d' => 'oceanbase.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'oceanbase.aliyuncs.com', + 'ap-southeast-1' => 'oceanbasepro-share.ap-southeast-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'oceanbasepro-share.cn-shanghai-finance-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'oceanbasepro-share.cn-hangzhou.aliyuncs.com', + ], + 'msc' => + [ + 'us-east-1' => 'msc-inner.aliyuncs.com', + 'cn-hongkong' => 'msc-inner.aliyuncs.com', + 'cn-qingdao-cm9' => 'msc-inner.aliyuncs.com', + 'cn-shanghai' => 'msc-inner.aliyuncs.com', + 'cn-shenzhen-inner' => 'msc-inner.aliyuncs.com', + 'us-west-1' => 'msc-inner.aliyuncs.com', + 'cn-shanghai-inner' => 'msc-inner.aliyuncs.com', + 'cn-hangzhou' => 'msc-inner.aliyuncs.com', + 'cn-beijing-inner' => 'msc-inner.aliyuncs.com', + 'cn-beijing' => 'msc-inner.aliyuncs.com', + 'cn-hangzhou-d' => 'msc-inner.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'msc-inner.aliyuncs.com', + 'ap-southeast-1' => 'msc-inner.aliyuncs.com', + ], + 'yundunhsm' => + [ + 'us-east-1' => 'yundunhsm.aliyuncs.com', + 'cn-hongkong' => 'yundunhsm.aliyuncs.com', + 'cn-qingdao-cm9' => 'yundunhsm.aliyuncs.com', + 'cn-shanghai' => 'yundunhsm.aliyuncs.com', + 'cn-shenzhen-inner' => 'yundunhsm.aliyuncs.com', + 'us-west-1' => 'yundunhsm.aliyuncs.com', + 'cn-shanghai-inner' => 'yundunhsm.aliyuncs.com', + 'cn-hangzhou' => 'yundunhsm.aliyuncs.com', + 'cn-beijing-inner' => 'yundunhsm.aliyuncs.com', + 'cn-beijing' => 'yundunhsm.aliyuncs.com', + 'cn-hangzhou-d' => 'yundunhsm.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'yundunhsm.aliyuncs.com', + 'ap-southeast-1' => 'yundunhsm.aliyuncs.com', + ], + 'iot' => + [ + 'cn-hongkong' => 'iot.aliyuncs.com', + 'cn-qingdao-cm9' => 'iot.aliyuncs.com', + 'cn-shanghai' => 'iot.cn-shanghai.aliyuncs.com', + 'cn-shenzhen-inner' => 'iot.aliyuncs.com', + 'us-west-1' => 'iot.us-west-1.aliyuncs.com', + 'cn-shanghai-inner' => 'iot.aliyuncs.com', + 'cn-hangzhou' => 'iot.aliyuncs.com', + 'cn-beijing-inner' => 'iot.aliyuncs.com', + 'cn-shenzhen' => 'iot.aliyuncs.com', + 'cn-qingdao' => 'iot.aliyuncs.com', + 'cn-beijing' => 'iot.aliyuncs.com', + 'cn-hangzhou-d' => 'iot.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'iot.aliyuncs.com', + 'ap-southeast-1' => 'iot.ap-southeast-1.aliyuncs.com', + 'ap-northeast-1' => 'iot.ap-northeast-1.aliyuncs.com', + 'us-east-1' => 'iot.us-east-1.aliyuncs.com', + 'eu-central-1' => 'iot.eu-central-1.aliyuncs.com', + ], + 'oms' => + [ + 'us-east-1' => 'oms.aliyuncs.com', + 'cn-hongkong' => 'oms.aliyuncs.com', + 'cn-qingdao-cm9' => 'oms.aliyuncs.com', + 'cn-shanghai' => 'oms.aliyuncs.com', + 'cn-shenzhen-inner' => 'oms.aliyuncs.com', + 'us-west-1' => 'oms.aliyuncs.com', + 'cn-shanghai-inner' => 'oms.aliyuncs.com', + 'cn-hangzhou' => 'oms.aliyuncs.com', + 'cn-beijing-inner' => 'oms.aliyuncs.com', + 'cn-shenzhen' => 'oms.aliyuncs.com', + 'cn-qingdao' => 'oms.aliyuncs.com', + 'cn-beijing' => 'oms.aliyuncs.com', + 'cn-hangzhou-d' => 'oms.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'oms.aliyuncs.com', + 'ap-southeast-1' => 'oms.aliyuncs.com', + ], + 'live' => + [ + 'us-east-1' => 'live.aliyuncs.com', + 'cn-hongkong' => 'live.aliyuncs.com', + 'cn-qingdao-cm9' => 'live.aliyuncs.com', + 'cn-shanghai' => 'live.aliyuncs.com', + 'cn-shenzhen-inner' => 'live.aliyuncs.com', + 'us-west-1' => 'live.aliyuncs.com', + 'cn-shanghai-inner' => 'live.aliyuncs.com', + 'cn-hangzhou' => 'live.aliyuncs.com', + 'cn-beijing-inner' => 'live.aliyuncs.com', + 'cn-shenzhen' => 'live.aliyuncs.com', + 'cn-qingdao' => 'live.aliyuncs.com', + 'cn-beijing' => 'live.aliyuncs.com', + 'cn-hangzhou-d' => 'live.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'live.aliyuncs.com', + 'ap-southeast-1' => 'live.aliyuncs.com', + 'ap-northeast-1' => 'live.aliyuncs.com', + 'eu-central-1' => 'live.aliyuncs.com', + 'ap-southeast-5' => 'live.aliyuncs.com', + 'ap-south-1' => 'live.aliyuncs.com', + ], + 'ubsms' => + [ + 'us-east-1' => 'ubsms.aliyuncs.com', + 'cn-hongkong' => 'ubsms.aliyuncs.com', + 'cn-qingdao-cm9' => 'ubsms.aliyuncs.com', + 'cn-shanghai' => 'ubsms.aliyuncs.com', + 'cn-shenzhen-inner' => 'ubsms.aliyuncs.com', + 'us-west-1' => 'ubsms.aliyuncs.com', + 'cn-shanghai-inner' => 'ubsms.aliyuncs.com', + 'cn-hangzhou' => 'ubsms.aliyuncs.com', + 'cn-beijing-inner' => 'ubsms.aliyuncs.com', + 'cn-shenzhen' => 'ubsms.aliyuncs.com', + 'cn-qingdao' => 'ubsms.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'ubsms.aliyuncs.com', + 'cn-hangzhou-d' => 'ubsms.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ubsms.aliyuncs.com', + 'ap-southeast-1' => 'ubsms.aliyuncs.com', + ], + 'alert' => + [ + 'us-east-1' => 'alert.aliyuncs.com', + 'cn-hongkong' => 'alert.aliyuncs.com', + 'cn-qingdao-cm9' => 'alert.aliyuncs.com', + 'cn-shanghai' => 'alert.aliyuncs.com', + 'cn-shenzhen-inner' => 'alert.aliyuncs.com', + 'us-west-1' => 'alert.aliyuncs.com', + 'cn-shanghai-inner' => 'alert.aliyuncs.com', + 'cn-hangzhou' => 'alert.aliyuncs.com', + 'cn-beijing-inner' => 'alert.aliyuncs.com', + 'cn-shenzhen' => 'alert.aliyuncs.com', + 'cn-qingdao' => 'alert.aliyuncs.com', + 'cn-beijing' => 'alert.aliyuncs.com', + 'cn-hangzhou-d' => 'alert.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'alert.aliyuncs.com', + 'ap-southeast-1' => 'alert.aliyuncs.com', + ], + 'ace' => + [ + 'us-east-1' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'ace.cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'ace.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ace.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'ace.cn-hangzhou.aliyuncs.com', + ], + 'ams' => + [ + 'us-east-1' => 'ams.aliyuncs.com', + 'cn-hongkong' => 'ams.aliyuncs.com', + 'cn-qingdao-cm9' => 'ams.aliyuncs.com', + 'cn-shanghai' => 'ams.aliyuncs.com', + 'cn-shenzhen-inner' => 'ams.aliyuncs.com', + 'us-west-1' => 'ams.aliyuncs.com', + 'cn-shanghai-inner' => 'ams.aliyuncs.com', + 'cn-hangzhou' => 'ams.aliyuncs.com', + 'cn-beijing-inner' => 'ams.aliyuncs.com', + 'cn-beijing' => 'ams.aliyuncs.com', + 'cn-hangzhou-d' => 'ams.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ams.aliyuncs.com', + 'ap-southeast-1' => 'ams.aliyuncs.com', + ], + 'ros' => + [ + 'us-east-1' => 'ros.aliyuncs.com', + 'cn-hongkong' => 'ros.aliyuncs.com', + 'cn-qingdao-cm9' => 'ros.aliyuncs.com', + 'cn-shanghai' => 'ros.aliyuncs.com', + 'cn-shenzhen-inner' => 'ros.aliyuncs.com', + 'us-west-1' => 'ros.aliyuncs.com', + 'cn-shanghai-inner' => 'ros.aliyuncs.com', + 'cn-hangzhou' => 'ros.aliyuncs.com', + 'cn-beijing-inner' => 'ros.aliyuncs.com', + 'cn-shenzhen' => 'ros.aliyuncs.com', + 'cn-qingdao' => 'ros.aliyuncs.com', + 'cn-beijing' => 'ros.aliyuncs.com', + 'cn-hangzhou-d' => 'ros.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ros.aliyuncs.com', + 'ap-southeast-1' => 'ros.aliyuncs.com', + ], + 'pts' => + [ + 'us-east-1' => 'pts.aliyuncs.com', + 'cn-hongkong' => 'pts.aliyuncs.com', + 'cn-qingdao-cm9' => 'pts.aliyuncs.com', + 'cn-shanghai' => 'pts.aliyuncs.com', + 'cn-shenzhen-inner' => 'pts.aliyuncs.com', + 'us-west-1' => 'pts.aliyuncs.com', + 'cn-shanghai-inner' => 'pts.aliyuncs.com', + 'cn-hangzhou' => 'pts.aliyuncs.com', + 'cn-beijing-inner' => 'pts.aliyuncs.com', + 'cn-shenzhen' => 'pts.aliyuncs.com', + 'cn-qingdao' => 'pts.aliyuncs.com', + 'cn-beijing' => 'pts.aliyuncs.com', + 'cn-hangzhou-d' => 'pts.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'pts.aliyuncs.com', + 'ap-southeast-1' => 'pts.aliyuncs.com', + ], + 'qualitycheck' => + [ + 'us-east-1' => 'qualitycheck.aliyuncs.com', + 'cn-hongkong' => 'qualitycheck.aliyuncs.com', + 'cn-qingdao-cm9' => 'qualitycheck.aliyuncs.com', + 'cn-shanghai' => 'qualitycheck.aliyuncs.com', + 'cn-shenzhen-inner' => 'qualitycheck.aliyuncs.com', + 'us-west-1' => 'qualitycheck.aliyuncs.com', + 'cn-shanghai-inner' => 'qualitycheck.aliyuncs.com', + 'cn-hangzhou' => 'qualitycheck.aliyuncs.com', + 'cn-beijing-inner' => 'qualitycheck.aliyuncs.com', + 'cn-hangzhou-d' => 'qualitycheck.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'qualitycheck.aliyuncs.com', + 'ap-southeast-1' => 'qualitycheck.aliyuncs.com', + ], + 'm-kvstore' => + [ + 'us-east-1' => 'm-kvstore.aliyuncs.com', + 'cn-hongkong' => 'm-kvstore.aliyuncs.com', + 'cn-qingdao-cm9' => 'm-kvstore.aliyuncs.com', + 'cn-shanghai' => 'm-kvstore.aliyuncs.com', + 'cn-shenzhen-inner' => 'm-kvstore.aliyuncs.com', + 'us-west-1' => 'm-kvstore.aliyuncs.com', + 'cn-shanghai-inner' => 'm-kvstore.aliyuncs.com', + 'cn-hangzhou' => 'm-kvstore.aliyuncs.com', + 'cn-beijing-inner' => 'm-kvstore.aliyuncs.com', + 'cn-shenzhen' => 'm-kvstore.aliyuncs.com', + 'cn-qingdao' => 'm-kvstore.aliyuncs.com', + 'cn-beijing' => 'm-kvstore.aliyuncs.com', + 'cn-hangzhou-d' => 'm-kvstore.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'm-kvstore.aliyuncs.com', + 'ap-southeast-1' => 'm-kvstore.aliyuncs.com', + ], + 'highddos' => + [ + 'us-east-1' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'yd-highddos-cn-hangzhou.aliyuncs.com', + ], + 'cmssitemonitor' => + [ + 'us-east-1' => 'sitemonitor.aliyuncs.com', + 'cn-hongkong' => 'sitemonitor.aliyuncs.com', + 'cn-qingdao-cm9' => 'sitemonitor.aliyuncs.com', + 'cn-shanghai' => 'sitemonitor.aliyuncs.com', + 'cn-shenzhen-inner' => 'sitemonitor.aliyuncs.com', + 'us-west-1' => 'sitemonitor.aliyuncs.com', + 'cn-shanghai-inner' => 'sitemonitor.aliyuncs.com', + 'cn-hangzhou' => 'sitemonitor.aliyuncs.com', + 'cn-beijing-inner' => 'sitemonitor.aliyuncs.com', + 'cn-shenzhen' => 'sitemonitor.aliyuncs.com', + 'cn-qingdao' => 'sitemonitor.aliyuncs.com', + 'cn-beijing' => 'sitemonitor.aliyuncs.com', + 'cn-hangzhou-d' => 'sitemonitor.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'sitemonitor.aliyuncs.com', + 'ap-southeast-1' => 'sitemonitor.aliyuncs.com', + ], + 'batchcompute' => + [ + 'us-east-1' => 'batchCompute.us-east-1.aliyuncs.com', + 'cn-hongkong' => 'batchCompute.cn-hongkong.aliyuncs.com', + 'cn-shanghai' => 'batchCompute.cn-shanghai.aliyuncs.com', + 'us-west-1' => 'batchCompute.us-west-1.aliyuncs.com', + 'cn-hangzhou' => 'batchCompute.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'batchcompute.cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'batchcompute.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'batchCompute.cn-beijing.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'batchCompute.cn-shanghai-et2-b01.aliyuncs.com', + 'ap-southeast-1' => 'batchCompute.ap-southeast-1.aliyuncs.com', + ], + 'cf' => + [ + 'us-east-1' => 'cf.aliyuncs.com', + 'cn-hongkong' => 'cf.aliyuncs.com', + 'cn-qingdao-cm9' => 'cf.aliyuncs.com', + 'cn-shanghai' => 'cf.aliyuncs.com', + 'cn-shenzhen-inner' => 'cf.aliyuncs.com', + 'us-west-1' => 'cf.aliyuncs.com', + 'cn-shanghai-inner' => 'cf.aliyuncs.com', + 'cn-hangzhou' => 'cf.aliyuncs.com', + 'cn-beijing-inner' => 'cf.aliyuncs.com', + 'cn-shenzhen' => 'cf.aliyuncs.com', + 'cn-qingdao' => 'cf.aliyuncs.com', + 'cn-beijing' => 'cf.aliyuncs.com', + 'cn-hangzhou-d' => 'cf.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'cf.aliyuncs.com', + 'ap-southeast-1' => 'cf.aliyuncs.com', + ], + 'drds' => + [ + 'us-east-1' => 'drds.aliyuncs.com', + 'cn-hongkong' => 'drds.aliyuncs.com', + 'cn-qingdao-cm9' => 'drds.aliyuncs.com', + 'cn-shanghai' => 'drds.aliyuncs.com', + 'cn-shenzhen-inner' => 'drds.aliyuncs.com', + 'us-west-1' => 'drds.aliyuncs.com', + 'cn-shanghai-inner' => 'drds.aliyuncs.com', + 'cn-hangzhou' => 'drds.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'drds.aliyuncs.com', + 'cn-shenzhen' => 'drds.aliyuncs.com', + 'cn-qingdao' => 'drds.aliyuncs.com', + 'cn-beijing' => 'drds.aliyuncs.com', + 'cn-hangzhou-d' => 'drds.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'drds.aliyuncs.com', + 'ap-southeast-1' => 'drds.aliyuncs.com', + ], + 'acs' => + [ + 'us-east-1' => 'acs.aliyun-inc.com', + 'cn-hongkong' => 'acs.aliyun-inc.com', + 'cn-shanghai' => 'acs.aliyun-inc.com', + 'us-west-1' => 'acs.aliyun-inc.com', + 'cn-hangzhou' => 'acs.aliyun-inc.com', + 'cn-shenzhen' => 'acs.aliyun-inc.com', + 'cn-qingdao' => 'acs.aliyun-inc.com', + 'cn-beijing' => 'acs.aliyun-inc.com', + 'cn-shanghai-et2-b01' => 'acs.aliyun-inc.com', + ], + 'httpdns' => + [ + 'us-east-1' => 'httpdns-api.aliyuncs.com', + 'cn-hongkong' => 'httpdns-api.aliyuncs.com', + 'cn-qingdao-cm9' => 'httpdns-api.aliyuncs.com', + 'cn-shanghai' => 'httpdns-api.aliyuncs.com', + 'cn-shenzhen-inner' => 'httpdns-api.aliyuncs.com', + 'us-west-1' => 'httpdns-api.aliyuncs.com', + 'cn-shanghai-inner' => 'httpdns-api.aliyuncs.com', + 'cn-hangzhou' => 'httpdns-api.aliyuncs.com', + 'cn-beijing-inner' => 'httpdns-api.aliyuncs.com', + 'cn-shenzhen' => 'httpdns-api.aliyuncs.com', + 'cn-qingdao' => 'httpdns-api.aliyuncs.com', + 'cn-beijing' => 'httpdns-api.aliyuncs.com', + 'cn-hangzhou-d' => 'httpdns-api.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'httpdns-api.aliyuncs.com', + 'ap-southeast-1' => 'httpdns-api.aliyuncs.com', + ], + 'location-inner' => + [ + 'us-east-1' => 'location-inner.aliyuncs.com', + 'cn-hongkong' => 'location-inner.aliyuncs.com', + 'cn-qingdao-cm9' => 'location-inner.aliyuncs.com', + 'cn-shanghai' => 'location-inner.aliyuncs.com', + 'cn-shenzhen-inner' => 'location-inner.aliyuncs.com', + 'us-west-1' => 'location-inner.aliyuncs.com', + 'cn-shanghai-inner' => 'location-inner.aliyuncs.com', + 'cn-hangzhou' => 'location-inner.aliyuncs.com', + 'cn-beijing-inner' => 'location-inner.aliyuncs.com', + 'cn-shenzhen' => 'location-inner.aliyuncs.com', + 'cn-qingdao' => 'location-inner.aliyuncs.com', + 'cn-beijing' => 'location-inner.aliyuncs.com', + 'cn-hangzhou-d' => 'location-inner.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'location-inner.aliyuncs.com', + 'ap-southeast-1' => 'location-inner.aliyuncs.com', + ], + 'aas' => + [ + 'us-east-1' => 'aas.aliyuncs.com', + 'cn-hongkong' => 'aas.aliyuncs.com', + 'cn-qingdao-cm9' => 'aas.aliyuncs.com', + 'cn-shanghai' => 'aas.aliyuncs.com', + 'cn-shenzhen-inner' => 'aas.aliyuncs.com', + 'us-west-1' => 'aas.aliyuncs.com', + 'cn-shanghai-inner' => 'aas.aliyuncs.com', + 'cn-hangzhou' => 'aas.aliyuncs.com', + 'cn-beijing-inner' => 'aas.aliyuncs.com', + 'cn-shenzhen' => 'aas.aliyuncs.com', + 'cn-qingdao' => 'aas.aliyuncs.com', + 'cn-beijing' => 'aas.aliyuncs.com', + 'cn-hangzhou-d' => 'aas.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'aas.aliyuncs.com', + 'ap-southeast-1' => 'aas.aliyuncs.com', + ], + 'sts' => + [ + 'cn-hangzhou' => 'sts.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'sts.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'sts.cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'sts.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'sts.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'sts.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'sts.cn-huhehaote.aliyuncs.com', + 'cn-hongkong' => 'sts.cn-hongkong.aliyuncs.com', + 'cn-chengdu' => 'sts.cn-chengdu.aliyuncs.com', + 'ap-southeast-1' => 'sts.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'sts.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'sts.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'sts.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'sts.ap-northeast-1.aliyuncs.com', + 'ap-south-1' => 'sts.ap-south-1.aliyuncs.com', + 'us-west-1' => 'sts.us-west-1.aliyuncs.com', + 'us-east-1' => 'sts.us-east-1.aliyuncs.com', + 'eu-central-1' => 'sts.eu-central-1.aliyuncs.com', + 'me-east-1' => 'sts.me-east-1.aliyuncs.com', + 'eu-west-1' => 'sts.eu-west-1.aliyuncs.com', + ], + 'dts' => + [ + 'us-east-1' => 'dts.aliyuncs.com', + 'cn-hongkong' => 'dts.aliyuncs.com', + 'cn-qingdao-cm9' => 'dts.aliyuncs.com', + 'cn-shanghai' => 'dts.aliyuncs.com', + 'cn-shenzhen-inner' => 'dts.aliyuncs.com', + 'us-west-1' => 'dts.aliyuncs.com', + 'cn-shanghai-inner' => 'dts.aliyuncs.com', + 'cn-hangzhou' => 'dts.aliyuncs.com', + 'cn-beijing-inner' => 'dts.aliyuncs.com', + 'cn-shenzhen' => 'dts.aliyuncs.com', + 'cn-qingdao' => 'dts.aliyuncs.com', + 'cn-beijing' => 'dts.aliyuncs.com', + 'cn-hangzhou-d' => 'dts.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'dts.aliyuncs.com', + 'ap-southeast-1' => 'dts.aliyuncs.com', + 'cn-zhangjiakou' => 'dts.aliyuncs.com', + 'cn-huhehaote' => 'dts.aliyuncs.com', + 'ap-southeast-2' => 'dts.aliyuncs.com', + 'ap-southeast-3' => 'dts.aliyuncs.com', + 'ap-southeast-5' => 'dts.aliyuncs.com', + 'eu-west-1' => 'dts.aliyuncs.com', + 'eu-central-1' => 'dts.aliyuncs.com', + 'me-east-1' => 'dts.aliyuncs.com', + 'ap-south-1' => 'dts.aliyuncs.com', + 'cn-hangzhou-finance' => 'dts.aliyuncs.com', + 'cn-shanghai-finance-1' => 'dts.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'dts.aliyuncs.com', + 'cn-north-2-gov-1' => 'dts.aliyuncs.com', + 'cn-beijing-gov-1' => 'dts.aliyuncs.com', + ], + 'drc' => + [ + 'us-east-1' => 'drc.aliyuncs.com', + 'cn-hongkong' => 'drc.aliyuncs.com', + 'cn-qingdao-cm9' => 'drc.aliyuncs.com', + 'cn-shanghai' => 'drc.aliyuncs.com', + 'cn-shenzhen-inner' => 'drc.aliyuncs.com', + 'us-west-1' => 'drc.aliyuncs.com', + 'cn-shanghai-inner' => 'drc.aliyuncs.com', + 'cn-hangzhou' => 'drc.aliyuncs.com', + 'cn-beijing-inner' => 'drc.aliyuncs.com', + 'cn-shenzhen' => 'drc.aliyuncs.com', + 'cn-qingdao' => 'drc.aliyuncs.com', + 'cn-beijing' => 'drc.aliyuncs.com', + 'cn-hangzhou-d' => 'drc.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'drc.aliyuncs.com', + 'ap-southeast-1' => 'drc.aliyuncs.com', + ], + 'vpc-inner' => + [ + 'us-east-1' => 'vpc-inner.aliyuncs.com', + 'cn-hongkong' => 'vpc-inner.aliyuncs.com', + 'cn-shanghai' => 'vpc-inner.aliyuncs.com', + 'us-west-1' => 'vpc-inner.aliyuncs.com', + 'cn-hangzhou' => 'vpc-inner.aliyuncs.com', + 'cn-shenzhen' => 'vpc-inner.aliyuncs.com', + 'cn-qingdao' => 'vpc-inner.aliyuncs.com', + 'cn-beijing' => 'vpc-inner.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'vpc-inner.aliyuncs.com', + ], + 'crm' => + [ + 'us-east-1' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'crm-cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'crm-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'crm-cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'crm-cn-hangzhou.aliyuncs.com', + ], + 'domain' => + [ + 'us-east-1' => 'domain.aliyuncs.com', + 'cn-hongkong' => 'domain.aliyuncs.com', + 'cn-qingdao-cm9' => 'domain.aliyuncs.com', + 'cn-shanghai' => 'domain.aliyuncs.com', + 'cn-shenzhen-inner' => 'domain.aliyuncs.com', + 'us-west-1' => 'domain.aliyuncs.com', + 'cn-shanghai-inner' => 'domain.aliyuncs.com', + 'cn-hangzhou' => 'domain.aliyuncs.com', + 'cn-beijing-inner' => 'domain.aliyuncs.com', + 'cn-shenzhen' => 'domain.aliyuncs.com', + 'cn-qingdao' => 'domain.aliyuncs.com', + 'cn-beijing' => 'domain.aliyuncs.com', + 'cn-hangzhou-d' => 'domain.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'domain.aliyuncs.com', + 'ap-southeast-1' => 'domain.aliyuncs.com', + ], + 'ots' => + [ + 'us-east-1' => 'ots.us-east-1.aliyuncs.com', + 'cn-hongkong' => 'ots.cn-hongkong.aliyuncs.com', + 'cn-qingdao-cm9' => 'ots-pop.aliyuncs.com', + 'cn-shanghai' => 'ots.cn-shanghai.aliyuncs.com', + 'cn-shenzhen-inner' => 'ots-pop.aliyuncs.com', + 'us-west-1' => 'ots.us-west-1.aliyuncs.com', + 'cn-shanghai-inner' => 'ots-pop.aliyuncs.com', + 'cn-hangzhou' => 'ots.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'ots-pop.aliyuncs.com', + 'cn-shenzhen' => 'ots.cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'ots.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'ots.cn-beijing.aliyuncs.com', + 'cn-hangzhou-d' => 'ots-pop.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ots-pop.aliyuncs.com', + 'ap-southeast-1' => 'ots.ap-southeast-1.aliyuncs.com', + 'cn-zhangjiakou' => 'ots.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'ots.cn-huhehaote.aliyuncs.com', + 'ap-southeast-2' => 'ots.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'ots.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'ots.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'ots.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'ots.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'ots.eu-central-1.aliyuncs.com', + 'me-east-1' => 'ots.me-east-1.aliyuncs.com', + 'ap-south-1' => 'ots.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'ots.cn-chengdu.aliyuncs.com', + 'cn-shanghai-finance-1' => 'ots.cn-shanghai-finance-1.aliyuncs.com', + ], + 'oss' => + [ + 'us-east-1' => 'oss-cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'oss-cn-hongkong.aliyuncs.com', + 'cn-qingdao-cm9' => 'oss-cn-hangzhou.aliyuncs.com', + 'cn-qingdao-finance' => 'oss-cn-qdjbp-a.aliyuncs.com', + 'cn-beijing-gov-1' => 'oss-cn-haidian-a.aliyuncs.com', + 'cn-shanghai' => 'oss-cn-shanghai.aliyuncs.com', + 'cn-shenzhen-inner' => 'oss-cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'oss-us-west-1.aliyuncs.com', + 'cn-shanghai-inner' => 'oss-cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-finance' => 'oss-cn-hzjbp-b-console.aliyuncs.com', + 'cn-hangzhou' => 'oss-cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'oss-cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'oss-cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'oss-cn-qingdao.aliyuncs.com', + 'oss-cn-bjzwy' => 'oss-cn-bjzwy.aliyuncs.com', + 'cn-beijing' => 'oss-cn-beijing.aliyuncs.com', + 'cn-hangzhou-d' => 'oss-cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'oss-cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'oss-ap-southeast-1.aliyuncs.com', + 'cn-chengdu' => 'oss-cn-chengdu.aliyuncs.com', + 'ap-northeast-1' => 'oss-ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'oss-eu-west-1.aliyuncs.com', + 'me-east-1' => 'oss-me-east-1.aliyuncs.com', + 'ap-south-1' => 'oss-ap-south-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'oss-cn-shanghai-finance-1-internal.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'oss-cn-shenzhen-finance-1-internal.aliyuncs.com', + 'cn-huhehaote-nebula-1' => 'oss-cn-huhehaote-nebula-1.aliyuncs.com', + 'cn-zhengzhou-nebula-1' => 'oss-cn-zhengzhou-nebula-1.aliyuncs.com', + 'cn-heyuan' => 'oss-cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'oss-cn-wulanchabu.aliyuncs.com', + ], + 'ram' => + [ + 'global' => 'ram.aliyuncs.com', + 'us-east-1' => 'ram.aliyuncs.com', + 'cn-hongkong' => 'ram.aliyuncs.com', + 'cn-qingdao-cm9' => 'ram.aliyuncs.com', + 'cn-shanghai' => 'ram.aliyuncs.com', + 'cn-shenzhen-inner' => 'ram.aliyuncs.com', + 'us-west-1' => 'ram.aliyuncs.com', + 'cn-shanghai-inner' => 'ram.aliyuncs.com', + 'cn-hangzhou' => 'ram.aliyuncs.com', + 'cn-beijing-inner' => 'ram.aliyuncs.com', + 'cn-shenzhen' => 'ram.aliyuncs.com', + 'cn-qingdao' => 'ram.aliyuncs.com', + 'cn-beijing' => 'ram.aliyuncs.com', + 'cn-hangzhou-d' => 'ram.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ram.aliyuncs.com', + 'ap-southeast-1' => 'ram.aliyuncs.com', + ], + 'sales' => + [ + 'us-east-1' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'sales.cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'sales.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'sales.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'sales.cn-hangzhou.aliyuncs.com', + ], + 'ossadmin' => + [ + 'us-east-1' => 'oss-admin.aliyuncs.com', + 'cn-hongkong' => 'oss-admin.aliyuncs.com', + 'cn-qingdao-cm9' => 'oss-admin.aliyuncs.com', + 'cn-shanghai' => 'oss-admin.aliyuncs.com', + 'cn-shenzhen-inner' => 'oss-admin.aliyuncs.com', + 'us-west-1' => 'oss-admin.aliyuncs.com', + 'cn-shanghai-inner' => 'oss-admin.aliyuncs.com', + 'cn-hangzhou' => 'oss-admin.aliyuncs.com', + 'cn-beijing-inner' => 'oss-admin.aliyuncs.com', + 'cn-shenzhen' => 'oss-admin.aliyuncs.com', + 'cn-qingdao' => 'oss-admin.aliyuncs.com', + 'cn-beijing' => 'oss-admin.aliyuncs.com', + 'cn-hangzhou-d' => 'oss-admin.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'oss-admin.aliyuncs.com', + 'ap-southeast-1' => 'oss-admin.aliyuncs.com', + ], + 'alidns' => + [ + 'us-east-1' => 'alidns.aliyuncs.com', + 'cn-hongkong' => 'alidns.aliyuncs.com', + 'cn-qingdao-cm9' => 'alidns.aliyuncs.com', + 'cn-shanghai' => 'alidns.aliyuncs.com', + 'cn-shenzhen-inner' => 'alidns.aliyuncs.com', + 'us-west-1' => 'alidns.aliyuncs.com', + 'cn-shanghai-inner' => 'alidns.aliyuncs.com', + 'cn-hangzhou' => 'alidns.aliyuncs.com', + 'cn-beijing-inner' => 'alidns.aliyuncs.com', + 'cn-shenzhen' => 'alidns.aliyuncs.com', + 'cn-qingdao' => 'alidns.aliyuncs.com', + 'cn-beijing' => 'alidns.aliyuncs.com', + 'cn-hangzhou-d' => 'alidns.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'alidns.aliyuncs.com', + 'ap-southeast-1' => 'alidns.aliyuncs.com', + ], + 'ons' => + [ + 'us-east-1' => 'ons.us-east-1.aliyuncs.com', + 'cn-hongkong' => 'ons.cn-hongkong.aliyuncs.com', + 'cn-qingdao-cm9' => 'ons.aliyuncs.com', + 'cn-shanghai' => 'ons.cn-shanghai.aliyuncs.com', + 'cn-shenzhen-inner' => 'ons.aliyuncs.com', + 'us-west-1' => 'ons.us-west-1.aliyuncs.com', + 'cn-shanghai-inner' => 'ons.aliyuncs.com', + 'cn-hangzhou' => 'ons.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'ons.aliyuncs.com', + 'cn-shenzhen' => 'ons.cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'ons.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'ons.cn-beijing.aliyuncs.com', + 'cn-hangzhou-d' => 'ons.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'ons.aliyuncs.com', + 'ap-southeast-1' => 'ons.ap-southeast-1.aliyuncs.com', + 'cn-zhangjiakou' => 'ons.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'ons.cn-huhehaote.aliyuncs.com', + 'ap-southeast-2' => 'ons.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'ons.ap-southeast-3.aliyuncs.com', + 'ap-northeast-1' => 'ons.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'ons.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'ons.eu-central-1.aliyuncs.com', + 'me-east-1' => 'ons.me-east-1.aliyuncs.com', + 'ap-south-1' => 'ons.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'ons.cn-chengdu.aliyuncs.com', + 'cn-hangzhou-finance' => 'ons.cn-hangzhou-finance.aliyuncs.com', + 'cn-shanghai-finance-1' => 'ons.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'ons.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'ons.cn-north-2-gov-1.aliyuncs.com', + 'ap-southeast-5' => 'ons.ap-southeast-5.aliyuncs.com', + ], + 'cdn' => + [ + 'global' => 'cdn.aliyuncs.com', + 'us-east-1' => 'cdn.aliyuncs.com', + 'cn-hongkong' => 'cdn.aliyuncs.com', + 'cn-qingdao-cm9' => 'cdn.aliyuncs.com', + 'cn-shanghai' => 'cdn.aliyuncs.com', + 'cn-shenzhen-inner' => 'cdn.aliyuncs.com', + 'us-west-1' => 'cdn.aliyuncs.com', + 'cn-shanghai-inner' => 'cdn.aliyuncs.com', + 'cn-hangzhou' => 'cdn.aliyuncs.com', + 'cn-beijing-inner' => 'cdn.aliyuncs.com', + 'cn-shenzhen' => 'cdn.aliyuncs.com', + 'cn-qingdao' => 'cdn.aliyuncs.com', + 'cn-beijing' => 'cdn.aliyuncs.com', + 'cn-hangzhou-d' => 'cdn.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'cdn.aliyuncs.com', + 'ap-southeast-1' => 'cdn.aliyuncs.com', + ], + 'yundunddos' => + [ + 'us-east-1' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-qingdao-cm9' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-inner' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'us-west-1' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-inner' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou-d' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'inner-yundun-ddos.cn-hangzhou.aliyuncs.com', + ], + 'kvstore' => + [ + 'ap-northeast-1' => 'r-kvstore.ap-northeast-1.aliyuncs.com', + ], + 'cloudapi' => + [ + 'cn-hongkong' => 'apigateway.cn-hongkong.aliyuncs.com', + 'cn-shanghai' => 'apigateway.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'apigateway.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'apigateway.cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'apigateway.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'apigateway.cn-beijing.aliyuncs.com', + 'ap-southeast-1' => 'apigateway.ap-southeast-1.aliyuncs.com', + ], + 'mts' => + [ + 'cn-hongkong' => 'mts.cn-hongkong.aliyuncs.com', + 'cn-qingdao-cm9' => 'mts.cn-qingdao.aliyuncs.com', + 'cn-shanghai' => 'mts.cn-shanghai.aliyuncs.com', + 'cn-shenzhen-inner' => 'mts.cn-shenzhen.aliyuncs.com', + 'us-west-1' => 'mts.us-west-1.aliyuncs.com', + 'cn-shanghai-inner' => 'mts.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'mts.cn-hangzhou.aliyuncs.com', + 'cn-beijing-inner' => 'mts.cn-beijing.aliyuncs.com', + 'cn-shenzhen' => 'mts.cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'mts.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'mts.cn-beijing.aliyuncs.com', + 'cn-hangzhou-d' => 'mts.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'mts.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'mts.ap-southeast-1.aliyuncs.com', + 'cn-zhangjiakou' => 'mts.cn-zhangjiakou.aliyuncs.com', + 'ap-northeast-1' => 'mts.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'mts.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'mts.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'mts.ap-south-1.aliyuncs.com', + 'ap-southeast-5' => 'mts.ap-southeast-5.aliyuncs.com', + ], + 'saf' => + [ + 'cn-shanghai' => 'saf.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'saf.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'saf.cn-shenzhen.aliyuncs.com', + 'ap-southeast-1' => 'saf.ap-southeast-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'saf.cn-north-2-gov-1.aliyuncs.com', + 'cn-zhangjiakou' => 'saf.cn-zhangjiakou.aliyuncs.com', + ], + 'arms' => + [ + 'cn-shanghai' => 'arms.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'arms.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'arms.cn-shenzhen.aliyuncs.com', + 'cn-beijing' => 'arms.cn-beijing.aliyuncs.com', + 'cn-qingdao' => 'arms.cn-qingdao.aliyuncs.com', + 'cn-zhangjiakou' => 'arms.cn-zhangjiakou.aliyuncs.com', + 'cn-hongkong' => 'arms.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'arms.ap-southeast-1.aliyuncs.com', + 'ap-south-1' => 'arms.ap-south-1.aliyuncs.com', + ], + 'apigateway' => + [ + 'cn-shanghai' => 'apigateway.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'apigateway.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'apigateway.cn-shenzhen.aliyuncs.com', + 'cn-qingdao' => 'apigateway.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'apigateway.cn-beijing.aliyuncs.com', + 'ap-southeast-1' => 'apigateway.ap-southeast-1.aliyuncs.com', + 'cn-hongkong' => 'apigateway.cn-hongkong.aliyuncs.com', + 'ap-southeast-2' => 'apigateway.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'apigateway.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'apigateway.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'apigateway.ap-northeast-1.aliyuncs.com', + 'eu-central-1' => 'apigateway.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'apigateway.ap-south-1.aliyuncs.com', + 'eu-west-1' => 'apigateway.eu-west-1.aliyuncs.com', + 'me-east-1' => 'apigateway.me-east-1.aliyuncs.com', + 'us-east-1' => 'apigateway.us-east-1.aliyuncs.com', + 'us-west-1' => 'apigateway.us-west-1.aliyuncs.com', + 'cn-zhangjiakou' => 'apigateway.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'apigateway.cn-huhehaote.aliyuncs.com', + 'cn-chengdu' => 'apigateway.cn-chengdu.aliyuncs.com', + 'cn-north-2-gov-1' => 'apigateway.cn-north-2-gov-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'apigateway.cn-hangzhou-finance.aliyuncs.com', + 'cn-shanghai-finance-1' => 'apigateway.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'apigateway.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-shanghai-inner' => 'apigateway.cn-shanghai-inner.aliyuncs.com', + 'cn-heyuan' => 'apigateway.cn-heyuan.aliyuncs.com', + ], + 'vod' => + [ + 'cn-shanghai' => 'vod.cn-shanghai.aliyuncs.com', + 'cn-beijing' => 'vod.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'vod.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'vod.cn-shenzhen.aliyuncs.com', + 'ap-southeast-1' => 'vod.ap-southeast-1.aliyuncs.com', + 'eu-central-1' => 'vod.eu-central-1.aliyuncs.com', + 'cn-zhangjiakou' => 'vod.cn-zhangjiakou.aliyuncs.com', + 'cn-hongkong' => 'vod.cn-hongkong.aliyuncs.com', + 'ap-southeast-5' => 'vod.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'vod.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'vod.eu-west-1.aliyuncs.com', + 'us-west-1' => 'vod.us-west-1.aliyuncs.com', + 'ap-south-1' => 'vod.ap-south-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'vod.cn-north-2-gov-1.aliyuncs.com', + ], + 'afs' => + [ + 'cn-hangzhou' => 'afs.aliyuncs.com', + ], + 'oas' => + [ + 'cn-hangzhou' => 'cn-hangzhou.oas.aliyuncs.com', + 'cn-shenzhen' => 'cn-shenzhen.oas.aliyuncs.com', + 'cn-beijing' => 'cn-beijing.oas.aliyuncs.com', + ], + 'alikafka' => + [ + 'cn-qingdao' => 'alikafka.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'alikafka.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'alikafka.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'alikafka.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'alikafka.cn-shenzhen.aliyuncs.com', + 'cn-zhangjiakou' => 'alikafka.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'alikafka.cn-huhehaote.aliyuncs.com', + 'cn-hongkong' => 'alikafka.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'alikafka.ap-southeast-1.aliyuncs.com', + 'ap-southeast-5' => 'alikafka.ap-southeast-5.aliyuncs.com', + 'ap-south-1' => 'alikafka.ap-south-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'alikafka.cn-hangzhou-finance.aliyuncs.com', + 'cn-shanghai-finance-1' => 'alikafka.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'alikafka.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-chengdu' => 'alikafka.cn-chengdu.aliyuncs.com', + 'cn-north-2-gov-1' => 'alikafka.cn-north-2-gov-1.aliyuncs.com', + 'cn-heyuan' => 'alikafka.cn-heyuan.aliyuncs.com', + 'ap-southeast-3' => 'alikafka.ap-southeast-3.aliyuncs.com', + 'ap-northeast-1' => 'alikafka.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'alikafka.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'alikafka.eu-central-1.aliyuncs.com', + ], + 'cbn' => + [ + 'cn-qingdao' => 'cbn.aliyuncs.com', + 'cn-beijing' => 'cbn.aliyuncs.com', + 'cn-zhangjiakou' => 'cbn.aliyuncs.com', + 'cn-huhehaote' => 'cbn.aliyuncs.com', + 'cn-hangzhou' => 'cbn.aliyuncs.com', + 'cn-shanghai' => 'cbn.aliyuncs.com', + 'cn-shenzhen' => 'cbn.aliyuncs.com', + 'cn-hongkong' => 'cbn.aliyuncs.com', + 'ap-southeast-1' => 'cbn.aliyuncs.com', + 'ap-southeast-2' => 'cbn.aliyuncs.com', + 'ap-southeast-3' => 'cbn.aliyuncs.com', + 'ap-southeast-5' => 'cbn.aliyuncs.com', + 'ap-northeast-1' => 'cbn.aliyuncs.com', + 'eu-west-1' => 'cbn.aliyuncs.com', + 'us-west-1' => 'cbn.aliyuncs.com', + 'us-east-1' => 'cbn.aliyuncs.com', + 'eu-central-1' => 'cbn.aliyuncs.com', + 'me-east-1' => 'cbn.aliyuncs.com', + 'ap-south-1' => 'cbn.aliyuncs.com', + 'cn-chengdu' => 'cbn.aliyuncs.com', + 'cn-shanghai-finance-1' => 'cbn.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'cbn.aliyuncs.com', + 'ap-northeast-2-pop' => 'cbn.aliyuncs.com', + 'cn-beijing-finance-pop' => 'cbn.aliyuncs.com', + 'cn-hangzhou-internal-test-1' => 'cbn.aliyuncs.com', + 'cn-hangzhou-internal-test-2' => 'cbn.aliyuncs.com', + 'cn-hangzhou-internal-test-3' => 'cbn.aliyuncs.com', + 'cn-wuhan' => 'cbn.aliyuncs.com', + 'cn-heyuan' => 'cbn.aliyuncs.com', + 'cn-wulanchabu' => 'cbn.aliyuncs.com', + 'cn-north-2-gov-1' => 'cbn.aliyuncs.com', + ], + 'onsvip' => + [ + 'cn-qingdao' => 'ons.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'ons.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'ons.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'ons.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'ons.cn-shenzhen.aliyuncs.com', + 'ap-southeast-1' => 'ons.ap-southeast-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'ons.cn-hangzhou-finance.aliyuncs.com', + 'cn-shanghai-finance-1' => 'ons.cn-shanghai-finance.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'ons.cn-shenzhen-finance.aliyuncs.com', + ], + 'ddosbgp' => + [ + 'cn-qingdao' => 'ddosbgp.aliyuncs.com', + 'cn-beijing' => 'ddosbgp.aliyuncs.com', + 'cn-zhangjiakou' => 'ddosbgp.aliyuncs.com', + 'cn-huhehaote' => 'ddosbgp.aliyuncs.com', + 'cn-hangzhou' => 'ddosbgp.aliyuncs.com', + 'cn-shanghai' => 'ddosbgp.aliyuncs.com', + 'cn-shenzhen' => 'ddosbgp.aliyuncs.com', + 'cn-hongkong' => 'ddosbgp.cn-hongkong.aliyuncs.com', + 'us-west-1' => 'ddosbgp.us-west-1.aliyuncs.com', + 'ap-southeast-1' => 'ddosbgp.ap-southeast-1.aliyuncs.com', + 'us-east-1' => 'ddosbgp.us-east-1.aliyuncs.com', + 'cn-chengdu' => 'ddosbgp.aliyuncs.com', + 'cn-heyuan' => 'ddosbgp.aliyuncs.com', + 'cn-wulanchabu' => 'ddosbgp.aliyuncs.com', + 'ap-southeast-2' => 'ddosbgp.aliyuncs.com', + 'ap-southeast-3' => 'ddosbgp.aliyuncs.com', + 'ap-southeast-5' => 'ddosbgp.aliyuncs.com', + 'ap-northeast-1' => 'ddosbgp.aliyuncs.com', + 'eu-west-1' => 'ddosbgp.aliyuncs.com', + 'eu-central-1' => 'ddosbgp.aliyuncs.com', + 'me-east-1' => 'ddosbgp.aliyuncs.com', + 'ap-south-1' => 'ddosbgp.aliyuncs.com', + ], + 'ehs' => + [ + 'cn-qingdao' => 'ehpc.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'ehpc.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'ehpc.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'ehpc.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'ehpc.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'ehpc.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'ehpc.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'ehpc.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'ehpc.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'ehpc.ap-southeast-2.aliyuncs.com', + 'eu-central-1' => 'ehpc.eu-central-1.aliyuncs.com', + 'ap-northeast-1' => 'ehpc.ap-northeast-1.aliyuncs.com', + ], + 'redisa' => + [ + 'cn-qingdao' => 'r-kvstore.aliyuncs.com', + 'cn-beijing' => 'r-kvstore.aliyuncs.com', + 'cn-zhangjiakou' => 'r-kvstore.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'r-kvstore.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'r-kvstore.aliyuncs.com', + 'cn-shanghai' => 'r-kvstore.aliyuncs.com', + 'cn-shenzhen' => 'r-kvstore.aliyuncs.com', + 'cn-hongkong' => 'r-kvstore.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'r-kvstore.aliyuncs.com', + 'ap-southeast-2' => 'r-kvstore.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'r-kvstore.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'r-kvstore.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'r-kvstore.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'r-kvstore.eu-west-1.aliyuncs.com', + 'us-west-1' => 'r-kvstore.aliyuncs.com', + 'us-east-1' => 'r-kvstore.aliyuncs.com', + 'eu-central-1' => 'r-kvstore.eu-central-1.aliyuncs.com', + 'me-east-1' => 'r-kvstore.me-east-1.aliyuncs.com', + 'ap-south-1' => 'r-kvstore.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'r-kvstore.cn-chengdu.aliyuncs.com', + 'cn-hangzhou-finance' => 'r-kvstore.aliyuncs.com', + 'cn-shanghai-finance-1' => 'r-kvstore.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'r-kvstore.aliyuncs.com', + 'cn-north-2-gov-1' => 'r-kvstore.aliyuncs.com', + 'cn-heyuan' => 'r-kvstore.aliyuncs.com', + 'cn-wulanchabu' => 'r-kvstore.aliyuncs.com', + ], + 'nas' => + [ + 'cn-qingdao' => 'nas.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'nas.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'nas.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'nas.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'nas.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'nas.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'nas.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'nas.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'nas.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'nas.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'nas.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'nas.ap-southeast-5.aliyuncs.com', + 'us-east-1' => 'nas.us-east-1.aliyuncs.com', + 'eu-central-1' => 'nas.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'nas.ap-south-1.aliyuncs.com', + 'ap-northeast-1' => 'nas.ap-northeast-1.aliyuncs.com', + 'us-west-1' => 'nas.us-west-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'nas.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'nas.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'nas.cn-north-2-gov-1.aliyuncs.com', + 'eu-west-1' => 'nas.eu-west-1.aliyuncs.com', + 'cn-chengdu' => 'nas.cn-chengdu.aliyuncs.com', + 'cn-heyuan' => 'nas.cn-heyuan.aliyuncs.com', + ], + 'hbase' => + [ + 'cn-qingdao' => 'hbase.aliyuncs.com', + 'cn-beijing' => 'hbase.aliyuncs.com', + 'cn-huhehaote' => 'hbase.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'hbase.aliyuncs.com', + 'cn-shanghai' => 'hbase.aliyuncs.com', + 'cn-shenzhen' => 'hbase.aliyuncs.com', + 'ap-southeast-1' => 'hbase.aliyuncs.com', + 'ap-southeast-2' => 'hbase.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'hbase.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'hbase.ap-southeast-5.aliyuncs.com', + 'us-west-1' => 'hbase.aliyuncs.com', + 'us-east-1' => 'hbase.aliyuncs.com', + 'eu-central-1' => 'hbase.eu-central-1.aliyuncs.com', + 'me-east-1' => 'hbase.me-east-1.aliyuncs.com', + 'ap-south-1' => 'hbase.ap-south-1.aliyuncs.com', + 'eu-west-1' => 'hbase.eu-west-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'hbase.aliyuncs.com', + 'cn-shanghai-finance-1' => 'hbase.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'hbase.aliyuncs.com', + 'cn-north-2-gov-1' => 'hbase.aliyuncs.com', + 'cn-zhangjiakou' => 'hbase.cn-zhangjiakou.aliyuncs.com', + 'cn-hongkong' => 'hbase.aliyuncs.com', + 'ap-northeast-1' => 'hbase.ap-northeast-1.aliyuncs.com', + ], + 'ddosbasic' => + [ + 'cn-qingdao' => 'antiddos.aliyuncs.com', + 'cn-beijing' => 'antiddos.aliyuncs.com', + 'cn-zhangjiakou' => 'antiddos-openapi.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'antiddos-openapi.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'antiddos.aliyuncs.com', + 'cn-shanghai' => 'antiddos.aliyuncs.com', + 'cn-shenzhen' => 'antiddos.aliyuncs.com', + 'cn-hongkong' => 'antiddos.aliyuncs.com', + 'ap-southeast-1' => 'antiddos.aliyuncs.com', + 'ap-southeast-2' => 'antiddos-openapi.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'antiddos-openapi.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'antiddos-openapi.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'antiddos-openapi.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'antiddos-openapi.eu-west-1.aliyuncs.com', + 'us-west-1' => 'antiddos.aliyuncs.com', + 'us-east-1' => 'antiddos.aliyuncs.com', + 'eu-central-1' => 'antiddos-openapi.eu-central-1.aliyuncs.com', + 'me-east-1' => 'antiddos-openapi.me-east-1.aliyuncs.com', + 'ap-south-1' => 'antiddos-openapi.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'antiddos-openapi.cn-chengdu.aliyuncs.com', + 'cn-shanghai-finance-1' => 'antiddos.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'antiddos.aliyuncs.com', + 'cn-north-2-gov-1' => 'antiddos.aliyuncs.com', + 'cn-fujian' => 'antiddos.aliyuncs.com', + 'cn-haidian-cm12-c01' => 'antiddos.aliyuncs.com', + 'cn-heyuan' => 'antiddos-openapi.cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'antiddos-openapi.cn-wulanchabu.aliyuncs.com', + ], + 'polardb' => + [ + 'cn-qingdao' => 'polardb.aliyuncs.com', + 'cn-beijing' => 'polardb.aliyuncs.com', + 'cn-huhehaote' => 'polardb.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'polardb.aliyuncs.com', + 'cn-shanghai' => 'polardb.aliyuncs.com', + 'cn-shenzhen' => 'polardb.aliyuncs.com', + 'cn-hongkong' => 'polardb.aliyuncs.com', + 'cn-zhangjiakou' => 'polardb.cn-zhangjiakou.aliyuncs.com', + 'ap-southeast-1' => 'polardb.aliyuncs.com', + 'ap-southeast-3' => 'polardb.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'polardb.ap-southeast-5.aliyuncs.com', + 'us-west-1' => 'polardb.aliyuncs.com', + 'cn-hangzhou-finance' => 'polardb.aliyuncs.com', + 'cn-shanghai-finance-1' => 'polardb.aliyuncs.com', + 'eu-central-1' => 'polardb.eu-central-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'polardb.aliyuncs.com', + 'ap-south-1' => 'polardb.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'polardb.cn-chengdu.aliyuncs.com', + 'ap-northeast-1' => 'polardb.ap-northeast-1.aliyuncs.com', + 'us-east-1' => 'polardb.aliyuncs.com', + ], + 'actiontrail' => + [ + 'cn-qingdao' => 'actiontrail.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'actiontrail.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'actiontrail.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'actiontrail.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'actiontrail.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'actiontrail.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'actiontrail.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'actiontrail.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'actiontrail.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'actiontrail.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'actiontrail.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'actiontrail.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'actiontrail.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'actiontrail.eu-west-1.aliyuncs.com', + 'us-west-1' => 'actiontrail.us-west-1.aliyuncs.com', + 'us-east-1' => 'actiontrail.us-east-1.aliyuncs.com', + 'eu-central-1' => 'actiontrail.eu-central-1.aliyuncs.com', + 'me-east-1' => 'actiontrail.me-east-1.aliyuncs.com', + 'ap-south-1' => 'actiontrail.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'actiontrail.cn-chengdu.aliyuncs.com', + 'cn-shanghai-finance-1' => 'actiontrail.cn-shanghai-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'actiontrail.cn-north-2-gov-1.aliyuncs.com', + 'cn-heyuan' => 'actiontrail.cn-heyuan.aliyuncs.com', + ], + 'codepipeline' => + [ + 'cn-beijing' => 'cds.cn-beijing.aliyuncs.com', + ], + 'hcs_sgw' => + [ + 'cn-beijing' => 'sgw.cn-shanghai.aliyuncs.com', + 'cn-zhangjiakou' => 'sgw.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'sgw.cn-shanghai.aliyuncs.com', + 'cn-shanghai' => 'sgw.cn-shanghai.aliyuncs.com', + 'cn-hongkong' => 'sgw.cn-shanghai.aliyuncs.com', + 'ap-southeast-1' => 'sgw.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'sgw.ap-southeast-2.aliyuncs.com', + 'eu-central-1' => 'sgw.eu-central-1.aliyuncs.com', + 'cn-qingdao' => 'sgw.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'sgw.cn-shanghai.aliyuncs.com', + 'cn-huhehaote' => 'sgw.cn-shanghai.aliyuncs.com', + 'cn-chengdu' => 'sgw.cn-shanghai.aliyuncs.com', + 'ap-southeast-5' => 'sgw.ap-southeast-5.aliyuncs.com', + 'ap-southeast-3' => 'sgw.ap-southeast-3.aliyuncs.com', + 'ap-northeast-1' => 'sgw.ap-northeast-1.aliyuncs.com', + 'us-west-1' => 'sgw.us-west-1.aliyuncs.com', + 'us-east-1' => 'sgw.us-west-1.aliyuncs.com', + 'cn-heyuan' => 'sgw.cn-shanghai.aliyuncs.com', + 'cn-north-2-gov-1' => 'sgw.cn-north-2-gov-1.aliyuncs.com', + ], + 'openanalytics' => + [ + 'cn-beijing' => 'openanalytics.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'openanalytics.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'openanalytics.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'openanalytics.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'openanalytics.cn-shenzhen.aliyuncs.com', + 'ap-southeast-1' => 'openanalytics.ap-southeast-1.aliyuncs.com', + 'ap-southeast-3' => 'openanalytics.ap-southeast-3.aliyuncs.com', + 'eu-west-1' => 'openanalytics.eu-west-1.aliyuncs.com', + 'cn-hongkong' => 'openanalytics.cn-hongkong.aliyuncs.com', + 'us-west-1' => 'openanalytics.us-west-1.aliyuncs.com', + 'ap-southeast-2' => 'datalakeanalytics.ap-southeast-2.aliyuncs.com', + 'ap-northeast-1' => 'datalakeanalytics.ap-northeast-1.aliyuncs.com', + 'us-east-1' => 'datalakeanalytics.us-east-1.aliyuncs.com', + 'eu-central-1' => 'datalakeanalytics.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'openanalytics.ap-south-1.aliyuncs.com', + 'ap-southeast-5' => 'openanalytics.ap-southeast-5.aliyuncs.com', + ], + 'clouddesktop' => + [ + 'cn-beijing' => 'clouddesktop.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'clouddesktop.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'clouddesktop.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'clouddesktop.cn-shenzhen.aliyuncs.com', + ], + 'ivision' => + [ + 'cn-beijing' => 'ivision.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'ivision.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'ivision.cn-shanghai.aliyuncs.com', + ], + 'fc' => + [ + 'cn-beijing' => 'cn-beijing.fc.aliyuncs.com', + 'cn-hangzhou' => 'cn-hangzhou.fc.aliyuncs.com', + 'cn-shanghai' => 'cn-shanghai.fc.aliyuncs.com', + 'cn-shenzhen' => 'cn-shenzhen.fc.aliyuncs.com', + 'ap-southeast-2' => 'ap-southeast-2.fc.aliyuncs.com', + 'cn-huhehaote' => 'cn-huhehaote.fc.aliyuncs.com', + 'cn-qingdao' => 'cn-qingdao.fc.aliyuncs.com', + 'cn-chengdu' => 'cn-chengdu.fc.aliyuncs.com', + 'cn-zhangjiakou' => 'cn-zhangjiakou.fc.aliyuncs.com', + 'cn-hongkong' => 'cn-hongkong.fc.aliyuncs.com', + 'ap-southeast-1' => 'ap-southeast-1.fc.aliyuncs.com', + 'ap-southeast-3' => 'ap-southeast-3.fc.aliyuncs.com', + 'ap-southeast-5' => 'ap-southeast-5.fc.aliyuncs.com', + 'ap-northeast-1' => 'ap-northeast-1.fc.aliyuncs. com', + 'eu-west-1' => 'eu-west-1.fc.aliyuncs.com', + 'us-west-1' => 'us-west-1.fc.aliyuncs.com', + 'us-east-1' => 'us-east-1.fc.aliyuncs.com', + 'eu-central-1' => 'eu-central-1.fc.aliyuncs.com', + 'ap-south-1' => 'ap-south-1.fc.aliyuncs.com', + 'cn-hangzhou-finance' => 'cn-hangzhou-finance.fc.aliyuncs.com', + ], + 'hsm' => + [ + 'cn-beijing' => 'hsm.aliyuncs.com', + 'cn-hangzhou' => 'hsm.aliyuncs.com', + 'cn-shanghai' => 'hsm.aliyuncs.com', + 'cn-shenzhen' => 'hsm.aliyuncs.com', + 'cn-hongkong' => 'hsm.aliyuncs.com', + 'ap-southeast-1' => 'hsm.aliyuncs.com', + 'cn-shanghai-finance-1' => 'hsm.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'hsm.aliyuncs.com', + 'cn-hangzhou-finance' => 'hsm.aliyuncs.com', + 'cn-north-2-gov-1' => 'hsm.aliyuncs.com', + 'cn-haidian-cm12-c01' => 'hsm.aliyuncs.com', + 'cn-heyuan' => 'hsm.aliyuncs.com', + 'ap-southeast-3' => 'hsm.aliyuncs.com', + ], + 'petadata' => + [ + 'cn-beijing' => 'petadata.aliyuncs.com', + 'cn-zhangjiakou' => 'petadata.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'petadata.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'petadata.aliyuncs.com', + 'cn-shanghai' => 'petadata.aliyuncs.com', + 'cn-shenzhen' => 'petadata.aliyuncs.com', + 'ap-southeast-1' => 'petadata.aliyuncs.com', + 'ap-southeast-2' => 'petadata.ap-southeast-2.aliyuncs.com', + 'ap-southeast-5' => 'petadata.ap-southeast-5.aliyuncs.com', + 'us-west-1' => 'petadata.aliyuncs.com', + 'us-east-1' => 'petadata.aliyuncs.com', + 'eu-central-1' => 'petadata.eu-central-1.aliyuncs.com', + 'me-east-1' => 'petadata.me-east-1.aliyuncs.com', + 'cn-hongkong' => 'petadata.aliyuncs.com', + 'cn-qingdao' => 'petadata.aliyuncs.com', + 'cn-shanghai-et2-b01' => 'petadata.aliyuncs.com', + 'cn-zhangjiakou-na62-a01' => 'petadata.aliyuncs.com', + ], + 'gpdb' => + [ + 'cn-beijing' => 'gpdb.aliyuncs.com', + 'cn-zhangjiakou' => 'gpdb.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'gpdb.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'gpdb.aliyuncs.com', + 'cn-shanghai' => 'gpdb.aliyuncs.com', + 'cn-shenzhen' => 'gpdb.aliyuncs.com', + 'ap-southeast-1' => 'gpdb.aliyuncs.com', + 'ap-southeast-2' => 'gpdb.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'gpdb.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'gpdb.ap-southeast-5.aliyuncs.com', + 'eu-west-1' => 'gpdb.eu-west-1.aliyuncs.com', + 'us-west-1' => 'gpdb.aliyuncs.com', + 'us-east-1' => 'gpdb.aliyuncs.com', + 'eu-central-1' => 'gpdb.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'gpdb.ap-south-1.aliyuncs.com', + 'ap-northeast-1' => 'gpdb.ap-northeast-1.aliyuncs.com', + 'cn-hongkong' => 'gpdb.aliyuncs.com', + 'cn-chengdu' => 'gpdb.cn-chengdu.aliyuncs.com', + 'cn-hangzhou-finance' => 'gpdb.aliyuncs.com', + 'cn-shanghai-finance-1' => 'gpdb.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'gpdb.aliyuncs.com', + ], + 'eci' => + [ + 'cn-beijing' => 'eci.aliyuncs.com', + 'cn-hangzhou' => 'eci.aliyuncs.com', + 'cn-shanghai' => 'eci.aliyuncs.com', + 'cn-shenzhen' => 'eci.aliyuncs.com', + 'ap-southeast-1' => 'eci.aliyuncs.com', + 'us-west-1' => 'eci.aliyuncs.com', + 'cn-hongkong' => 'eci.aliyuncs.com', + 'cn-zhangjiakou' => 'eci.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'eci.cn-huhehaote.aliyuncs.com', + 'ap-southeast-2' => 'eci.ap-southeast-2.aliyuncs.com', + 'eu-west-1' => 'eci.eu-west-1.aliyuncs.com', + 'us-east-1' => 'eci.aliyuncs.com', + 'eu-central-1' => 'eci.eu-central-1.aliyuncs.com', + 'cn-chengdu' => 'eci.cn-chengdu.aliyuncs.com', + 'ap-southeast-5' => 'eci.ap-southeast-5.aliyuncs.com', + 'ap-south-1' => 'eci.ap-south-1.aliyuncs.com', + 'cn-hangzhou-internal-test-1' => 'eci.aliyuncs.com', + 'cn-hangzhou-internal-test-2' => 'eci.aliyuncs.com', + 'cn-qingdao' => 'eci.aliyuncs.com', + 'cn-heyuan' => 'eci.cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'eci.cn-wulanchabu.aliyuncs.com', + 'ap-southeast-3' => 'eci.ap-southeast-3.aliyuncs.com', + 'ap-northeast-1' => 'eci.ap-northeast-1.aliyuncs.com', + ], + 'airec' => + [ + 'cn-beijing' => 'airec.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'airec.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'airec.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'airec.cn-shenzhen.aliyuncs.com', + ], + 'imm' => + [ + 'cn-beijing' => 'imm.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'imm.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'imm.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'imm.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'imm.cn-shenzhen.aliyuncs.com', + 'ap-southeast-1' => 'imm.ap-southeast-1.aliyuncs.com', + ], + 'gameshield' => + [ + 'cn-zhangjiakou' => 'gameshield.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'gameshield.aliyuncs.com', + ], + 'ims' => + [ + 'cn-hangzhou' => 'ims.aliyuncs.com', + ], + 'cloudfirewall' => + [ + 'cn-hangzhou' => 'cloudfw.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'cloudfw.ap-southeast-1.aliyuncs.com', + ], + 'ens' => + [ + 'cn-hangzhou' => 'ens.aliyuncs.com', + 'ap-southeast-1' => 'ens.ap-southeast-1.aliyuncs.com', + 'cn-beijing' => 'ens.aliyuncs.com', + 'cn-chengdu' => 'ens.aliyuncs.com', + 'cn-zhangjiakou' => 'ens.aliyuncs.com', + 'cn-shanghai' => 'ens.aliyuncs.com', + 'cn-heyuan' => 'ens.aliyuncs.com', + 'cn-wulanchabu' => 'ens.aliyuncs.com', + ], + 'hitsdb' => + [ + 'cn-hangzhou' => 'hitsdb.aliyuncs.com', + 'cn-qingdao' => 'hitsdb.aliyuncs.com', + 'cn-beijing' => 'hitsdb.aliyuncs.com', + 'cn-zhangjiakou' => 'hitsdb.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'hitsdb.cn-huhehaote.aliyuncs.com', + 'cn-shanghai' => 'hitsdb.aliyuncs.com', + 'cn-shenzhen' => 'hitsdb.aliyuncs.com', + 'cn-hongkong' => 'hitsdb.aliyuncs.com', + 'ap-southeast-5' => 'hitsdb.ap-southeast-5.aliyuncs.com', + 'us-west-1' => 'hitsdb.aliyuncs.com', + 'us-east-1' => 'hitsdb.aliyuncs.com', + 'ap-southeast-1' => 'hitsdb.aliyuncs.com', + 'ap-southeast-2' => 'hitsdb.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'hitsdb.ap-southeast-3.aliyuncs.com', + 'ap-northeast-1' => 'hitsdb.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'hitsdb.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'hitsdb.eu-central-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'hitsdb.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'hitsdb.aliyuncs.com', + ], + 'ddos' => + [ + 'cn-hangzhou' => 'ddospro.cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'ddospro.cn-hongkong.aliyuncs.com', + ], + 'rtc' => + [ + 'cn-hangzhou' => 'rtc.aliyuncs.com', + ], + 'emas' => + [ + 'cn-hangzhou' => 'mhub.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'mhub.cn-shanghai.aliyuncs.com', + ], + 'vipaegis' => + [ + 'cn-hangzhou' => 'aegis.cn-hangzhou.aliyuncs.com', + 'ap-southeast-3' => 'aegis.ap-southeast-3.aliyuncs.com', + ], + 'ddosrewards' => + [ + 'cn-hangzhou' => 'ddosright.cn-hangzhou.aliyuncs.com', + ], + 'cloudap' => + [ + 'cn-hangzhou' => 'cloudwf.aliyuncs.com', + ], + 'ensdisk' => + [ + 'cn-hangzhou' => 'ens.aliyuncs.com', + ], + 'bastionhost' => + [ + 'cn-hangzhou' => 'yundun-bastionhost.aliyuncs.com', + 'cn-qingdao' => 'yundun-bastionhost.aliyuncs.com', + 'cn-beijing' => 'yundun-bastionhost.aliyuncs.com', + 'cn-chengdu' => 'yundun-bastionhost.aliyuncs.com', + 'cn-zhangjiakou' => 'yundun-bastionhost.aliyuncs.com', + 'cn-huhehaote' => 'yundun-bastionhost.aliyuncs.com', + 'cn-shanghai' => 'yundun-bastionhost.aliyuncs.com', + 'cn-shenzhen' => 'yundun-bastionhost.aliyuncs.com', + 'cn-hongkong' => 'bastionhost.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'bastionhost.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'bastionhost.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'bastionhost.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'bastionhost.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'bastionhost.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'bastionhost.eu-west-1.aliyuncs.com', + 'us-west-1' => 'bastionhost.us-west-1.aliyuncs.com', + 'us-east-1' => 'bastionhost.us-east-1.aliyuncs.com', + 'eu-central-1' => 'bastionhost.eu-central-1.aliyuncs.com', + 'me-east-1' => 'yundun-bastionhost.aliyuncs.com', + 'ap-south-1' => 'bastionhost.ap-south-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'yundun-bastionhost.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'yundun-bastionhost.aliyuncs.com', + 'cn-north-2-gov-1' => 'yundun-bastionhost.aliyuncs.com', + 'cn-haidian-cm12-c01' => 'yundun-bastionhost.aliyuncs.com', + 'cn-heyuan' => 'yundun-bastionhost.aliyuncs.com', + ], + 'pvtz' => + [ + 'cn-hangzhou' => 'pvtz.aliyuncs.com', + ], + 'ccs' => + [ + 'cn-hangzhou' => 'ccs.aliyuncs.com', + ], + 'yunmarket' => + [ + 'cn-hangzhou' => 'market.aliyuncs.com', + ], + 'cas' => + [ + 'cn-hangzhou' => 'cas.aliyuncs.com', + 'ap-southeast-2' => 'cas.ap-southeast-2.aliyuncs.com', + 'ap-northeast-1' => 'cas.ap-northeast-1.aliyuncs.com', + 'eu-central-1' => 'cas.eu-central-1.aliyuncs.com', + 'me-east-1' => 'cas.me-east-1.aliyuncs.com', + 'ap-south-1' => 'cas.ap-south-1.aliyuncs.com', + ], + 'ddoscoo' => + [ + 'cn-hangzhou' => 'ddoscoo.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'ddoscoo.ap-southeast-1.aliyuncs.com', + ], + 'waf' => + [ + 'cn-hangzhou' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'cn-qingdao' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-chengdu' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-zhangjiakou' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-huhehaote' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-heyuan' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-wulanchabu' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'ap-southeast-3' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'ap-southeast-5' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'eu-west-1' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'us-west-1' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'us-east-1' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'eu-central-1' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'me-east-1' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'ap-south-1' => 'wafopenapi.ap-southeast-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + 'cn-north-2-gov-1' => 'wafopenapi.cn-hangzhou.aliyuncs.com', + ], + 'xianzhi' => + [ + 'cn-hangzhou' => 'xianzhi.aliyuncs.com', + ], + 'sas' => + [ + 'cn-hangzhou' => 'tds.aliyuncs.com', + 'ap-southeast-3' => 'tds.ap-southeast-3.aliyuncs.com', + ], + 'cloudauth' => + [ + 'cn-hangzhou' => 'cloudauth.aliyuncs.com', + ], + 'dmsenterprise' => + [ + 'cn-hangzhou' => 'dms-enterprise.aliyuncs.com', + 'cn-shanghai' => 'dms-enterprise.aliyuncs.com', + 'cn-shenzhen' => 'dms-enterprise.aliyuncs.com', + 'cn-beijing' => 'dms-enterprise.aliyuncs.com', + 'cn-qingdao' => 'dms-enterprise.aliyuncs.com', + 'ap-northeast-1' => 'dms-enterprise.aliyuncs.com', + 'ap-southeast-1' => 'dms-enterprise.aliyuncs.com', + ], + 'baas' => + [ + 'cn-hangzhou' => 'baas.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'baas.ap-southeast-1.aliyuncs.com', + 'ap-northeast-1' => 'baas.ap-southeast-1.aliyuncs.com', + 'cn-beijing' => 'baas.aliyuncs.com', + 'cn-shanghai' => 'baas.aliyuncs.com', + 'cn-shenzhen' => 'baas.aliyuncs.com', + 'cn-hongkong' => 'baas.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'baas.ap-southeast-1.aliyuncs.com', + 'us-east-1' => 'baas.ap-southeast-1.aliyuncs.com', + 'eu-central-1' => 'baas.ap-southeast-1.aliyuncs.com', + 'cn-qingdao' => 'baas.aliyuncs.com', + 'cn-zhangjiakou' => 'baas.aliyuncs.com', + 'cn-huhehaote' => 'baas.aliyuncs.com', + 'eu-west-1' => 'baas.ap-southeast-1.aliyuncs.com', + 'us-west-1' => 'baas.ap-southeast-1.aliyuncs.com', + 'ap-south-1' => 'baas.ap-southeast-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'baas.cn-north-2-gov-1.aliyuncs.com', + ], + 'alimt' => + [ + 'cn-hangzhou' => 'mt.cn-hangzhou.aliyuncs.com', + ], + 'dcdn' => + [ + 'cn-hangzhou' => 'dcdn.aliyuncs.com', + ], + 'hcs_mgw' => + [ + 'cn-hangzhou' => 'mgw.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'mgw.cn-shanghai.aliyuncs.com', + 'ap-southeast-1' => 'mgw.ap-southeast-1.aliyuncs.com', + ], + 'linkedmall' => + [ + 'cn-hangzhou' => 'linkedmall.aliyuncs.com', + 'cn-shanghai' => 'linkedmall.aliyuncs.com', + ], + 'cps' => + [ + 'cn-hangzhou' => 'cloudpush.aliyuncs.com', + ], + 'scdn' => + [ + 'cn-hangzhou' => 'scdn.aliyuncs.com', + ], + 'trademark' => + [ + 'cn-hangzhou' => 'trademark.aliyuncs.com', + ], + 'elasticsearch' => + [ + 'cn-hangzhou' => 'elasticsearch.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'elasticsearch.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'elasticsearch.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'elasticsearch.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'elasticsearch.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'elasticsearch.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'elasticsearch.ap-southeast-3.aliyuncs.com', + 'ap-northeast-1' => 'elasticsearch.ap-northeast-1.aliyuncs.com', + 'us-west-1' => 'elasticsearch.us-west-1.aliyuncs.com', + 'eu-central-1' => 'elasticsearch.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'elasticsearch.ap-south-1.aliyuncs.com', + 'cn-qingdao' => 'elasticsearch.cn-qingdao.aliyuncs.com', + 'ap-southeast-5' => 'elasticsearch.ap-southeast-5.aliyuncs.com', + 'cn-beijing' => 'elasticsearch.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'elasticsearch.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou-finance' => 'elasticsearch.cn-hangzhou-finance.aliyuncs.com', + 'cn-shanghai-finance-1' => 'elasticsearch.cn-shanghai-finance-1.aliyuncs.com', + 'us-east-1' => 'elasticsearch.us-east-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'elasticsearch.cn-north-2-gov-1.aliyuncs.com', + 'eu-west-1' => 'elasticsearch.eu-west-1.aliyuncs.com', + ], + 'luban' => + [ + 'cn-hangzhou' => 'luban.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'luban.cn-shanghai.aliyuncs.com', + ], + 'pcdn' => + [ + 'cn-hangzhou' => 'pcdn.aliyuncs.com', + ], + 'uis' => + [ + 'cn-hangzhou' => 'uis.cn-hangzhou.aliyuncs.com', + 'cn-north-2-gov-1' => 'uis.cn-hangzhou.aliyuncs.com', + ], + 'beebot' => + [ + 'cn-hangzhou' => 'chatbot.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'chatbot.cn-shanghai.aliyuncs.com', + 'cn-north-2-gov-1' => 'chatbot.cn-north-2-gov-1.aliyuncs.com', + ], + 'chatbot' => + [ + 'global' => 'chatbot.cn-shanghai.aliyuncs.com', + 'cn-shanghai' => 'chatbot.cn-shanghai.aliyuncs.com', + ], + 'alidnsgtm' => + [ + 'cn-hangzhou' => 'alidns.aliyuncs.com', + ], + 'sca' => + [ + 'cn-hangzhou' => 'qualitycheck.cn-hangzhou.aliyuncs.com', + ], + 'cccvn' => + [ + 'cn-shanghai' => 'voicenavigator.cn-shanghai.aliyuncs.com', + ], + 'cloudphoto' => + [ + 'cn-shanghai' => 'cloudphoto.cn-shanghai.aliyuncs.com', + ], + 'smartag' => + [ + 'cn-shanghai' => 'smartag.cn-shanghai.aliyuncs.com', + 'cn-hongkong' => 'smartag.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'smartag.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'smartag.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'smartag.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'smartag.ap-southeast-5.aliyuncs.com', + 'eu-central-1' => 'smartag.eu-central-1.aliyuncs.com', + 'ap-northeast-1' => 'smartag.ap-northeast-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'smartag.cn-shanghai-finance-1.aliyuncs.com', + 'cn-hangzhou-internal-test-1' => 'smartag.aliyuncs.com', + 'cn-hangzhou-internal-test-2' => 'smartag.aliyuncs.com', + 'eu-west-1' => 'smartag.eu-west-1.aliyuncs.com', + 'us-east-1' => 'smartag.us-east-1.aliyuncs.com', + ], + 'nlp' => + [ + 'cn-shanghai' => 'nlp.cn-shanghai.aliyuncs.com', + ], + 'nls-cloud-meta' => + [ + 'cn-shanghai' => 'nls-meta.cn-shanghai.aliyuncs.com', + ], + 'nls-filetrans' => + [ + 'cn-shanghai' => 'filetrans.cn-shanghai.aliyuncs.com', + ], + 'linkwan' => + [ + 'cn-shanghai' => 'linkwan.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'linkwan.cn-hangzhou.aliyuncs.com', + ], + 'hdm' => + [ + 'cn-shanghai' => 'hdm-api.aliyuncs.com', + ], + 'iovcc' => + [ + 'cn-shanghai' => 'iovcc.cn-shanghai.aliyuncs.com', + ], + 'ddosdip' => + [ + 'ap-southeast-1' => 'ddosdip.ap-southeast-1.aliyuncs.com', + ], + 'imagesearch' => + [ + 'ap-southeast-1' => 'imagesearch.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'imagesearch.ap-southeast-2.aliyuncs.com', + 'ap-northeast-1' => 'imagesearch.ap-northeast-1.aliyuncs.com', + 'cn-shanghai' => 'imagesearch.cn-shanghai.aliyuncs.com', + ], + 'alidfs' => + [ + 'cn-beijing' => 'dfs.cn-beijing.aliyuncs.com', + 'cn-shanghai' => 'dfs.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'dfs.cn-hangzhou.aliyuncs.com', + 'cn-zhangjiakou' => 'dfs.cn-zhangjiakou.aliyuncs.com', + ], + 'vs' => + [ + 'cn-hangzhou' => 'vs.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'vs.cn-shanghai.aliyuncs.com', + 'cn-qingdao' => 'vs.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'vs.cn-beijing.aliyuncs.com', + 'cn-shenzhen' => 'vs.cn-shenzhen.aliyuncs.com', + ], + 'foas' => + [ + 'cn-qingdao' => 'foas.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'foas.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'foas.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'foas.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'foas.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'foas.cn-shenzhen.aliyuncs.com', + 'ap-northeast-1' => 'foas.ap-northeast-1.aliyuncs.com', + 'ap-southeast-1' => 'foas.ap-southeast-1.aliyuncs.com', + 'ap-southeast-3' => 'foas.ap-southeast-3.aliyuncs.com', + 'cn-hangzhou-finance' => 'foas.cn-hangzhou-finance.aliyuncs.com', + 'cn-shanghai-finance-1' => 'foas.cn-shanghai-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'foas.cn-north-2-gov-1.aliyuncs.com', + 'cn-hongkong' => 'foas.cn-hongkong.aliyuncs.com', + 'eu-central-1' => 'foas.eu-central-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'foas.cn-shenzhen-finance-1.aliyuncs.com', + ], + 'iotid' => + [ + 'cn-hangzhou' => 'iotid.cn-hangzhou.aliyuncs.com', + ], + 'drdspost' => + [ + 'ap-southeast-1' => 'drds.ap-southeast-1.aliyuncs.com', + 'cn-shanghai' => 'drds.cn-shanghai.aliyuncs.com', + 'cn-hongkong' => 'drds.cn-hangzhou.aliyuncs.com', + 'cn-huhehaote' => 'drds.cn-huhehaote.aliyuncs.com', + 'us-east-1' => 'drds.us-east-1.aliyuncs.com', + ], + 'drdspre' => + [ + 'cn-qingdao' => 'drds.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'drds.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'drds.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'drds.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'drds.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'drds.cn-hangzhou.aliyuncs.com', + 'cn-huhehaote' => 'drds.cn-huhehaote.aliyuncs.com', + 'us-east-1' => 'drds.us-east-1.aliyuncs.com', + ], + 'acr' => + [ + 'cn-qingdao' => 'cr.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'cr.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'cr.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'cr.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'cr.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'cr.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'cr.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'cr.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'cr.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'cr.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'cr.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'cr.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'cr.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'cr.eu-west-1.aliyuncs.com', + 'us-west-1' => 'cr.us-west-1.aliyuncs.com', + 'us-east-1' => 'cr.us-east-1.aliyuncs.com', + 'eu-central-1' => 'cr.eu-central-1.aliyuncs.com', + 'me-east-1' => 'cr.me-east-1.aliyuncs.com', + 'ap-south-1' => 'cr.ap-south-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'cr.cn-hangzhou-finance.aliyuncs.com', + 'cn-shanghai-finance-1' => 'cr.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'cr.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'cr.cn-north-2-gov-1.aliyuncs.com', + 'cn-chengdu' => 'cr.cn-chengdu.aliyuncs.com', + ], + 'faas' => + [ + 'cn-beijing' => 'faas.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'faas.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'faas.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'faas.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'faas.cn-shenzhen.aliyuncs.com', + 'ap-southeast-5' => 'faas.ap-southeast-5.aliyuncs.com', + 'cn-shanghai-finance-1' => 'faas.cn-shanghai-finance-1.aliyuncs.com', + 'cn-chengdu' => 'faas.cn-chengdu.aliyuncs.com', + 'cn-heyuan' => 'faas.cn-heyuan.aliyuncs.com', + 'us-west-1' => 'faas.us-west-1.aliyuncs.com', + ], + 'idaas' => + [ + 'cn-hangzhou' => 'idaas.aliyuncs.com', + 'cn-qingdao' => 'idaas.aliyuncs.com', + 'cn-beijing' => 'idaas.aliyuncs.com', + 'cn-chengdu' => 'idaas.aliyuncs.com', + 'cn-zhangjiakou' => 'idaas.aliyuncs.com', + 'cn-huhehaote' => 'idaas.aliyuncs.com', + 'cn-shanghai' => 'idaas.aliyuncs.com', + 'cn-shenzhen' => 'idaas.aliyuncs.com', + 'cn-hongkong' => 'idaas.aliyuncs.com', + 'cn-shanghai-finance-1' => 'idaas.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'idaas.aliyuncs.com', + 'ap-southeast-1' => 'idaas.ap-southeast-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'idaas.aliyuncs.com', + ], + 'privatelink' => + [ + 'cn-hangzhou' => 'privatelink-center.cn-hangzhou.aliyuncs.com', + 'cn-huhehaote' => 'privatelink.cn-huhehaote.aliyuncs.com', + 'eu-west-1' => 'privatelink.eu-west-1.aliyuncs.com', + 'ap-southeast-2' => 'privatelink.ap-southeast-2.aliyuncs.com', + 'ap-southeast-5' => 'privatelink.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'privatelink.ap-northeast-1.aliyuncs.com', + 'ap-south-1' => 'privatelink.ap-south-1.aliyuncs.com', + 'cn-shenzhen' => 'privatelink.cn-shenzhen.aliyuncs.com', + 'eu-central-1' => 'privatelink.eu-central-1.aliyuncs.com', + 'cn-zhangjiakou' => 'privatelink.cn-zhangjiakou.aliyuncs.com', + 'ap-southeast-3' => 'privatelink.ap-southeast-3.aliyuncs.com', + 'cn-hangzhou-internal-test-1' => 'privatelink.aliyuncs.com', + 'cn-hangzhou-test-306' => 'privatelink-center.cn-hangzhou.aliyuncs.com', + 'cn-chengdu' => 'privatelink.cn-chengdu.aliyuncs.com', + 'ap-southeast-1' => 'privatelink.ap-southeast-1.aliyuncs.com', + ], + 'batchcomputenew' => + [ + 'cn-hongkong' => 'batchcompute.cn-hongkong.aliyuncs.com', + ], + 'vcs' => + [ + 'cn-hangzhou' => 'vcs.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'vcs.cn-shanghai.aliyuncs.com', + ], + 'vds' => + [ + 'cn-hangzhou' => 'vds.aliyuncs.com', + 'cn-shanghai' => 'vds.cn-shanghai.aliyuncs.com', + ], + 'vcsbasic' => + [ + 'cn-hangzhou' => 'vcs.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'vcs.cn-hangzhou.aliyuncs.com', + ], + 'hbr' => + [ + 'cn-qingdao' => 'hbr.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'hbr.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'hbr.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'hbr.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'hbr.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'hbr.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'hbr.cn-shenzhen.aliyuncs.com', + 'ap-southeast-1' => 'hbr.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'hbr.ap-southeast-2.aliyuncs.com', + 'cn-hongkong' => 'hbr.cn-hongkong.aliyuncs.com', + 'ap-southeast-5' => 'hbr.ap-southeast-5.aliyuncs.com', + 'ap-southeast-3' => 'hbr.ap-southeast-3.aliyuncs.com', + 'us-west-1' => 'hbr.us-west-1.aliyuncs.com', + 'eu-central-1' => 'hbr.eu-central-1.aliyuncs.com', + 'ap-northeast-1' => 'hbr.ap-northeast-1.aliyuncs.com', + 'cn-chengdu' => 'hbr.cn-chengdu.aliyuncs.com', + 'us-east-1' => 'hbr.us-east-1.aliyuncs.com', + 'ap-south-1' => 'hbr.ap-south-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'hbr.cn-hangzhou-finance.aliyuncs.com', + 'cn-shanghai-finance-1' => 'hbr.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'hbr.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'hbr.cn-north-2-gov-1.aliyuncs.com', + ], + 'image' => + [ + 'cn-shanghai' => 'image.cn-shanghai.aliyuncs.com', + ], + 'webx' => + [ + 'cn-shenzhen' => 'webplus.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'webplus.cn-hangzhou.aliyuncs.com', + 'cn-zhangjiakou' => 'webplus.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'webplus.cn-hangzhou.aliyuncs.com', + 'cn-hangzhou' => 'webplus.cn-hangzhou.aliyuncs.com', + ], + 'sddp' => + [ + 'cn-zhangjiakou' => 'sddp.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'sddp.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'sddp.ap-southeast-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'sddp.cn-north-2-gov-1.aliyuncs.com', + ], + 'oos' => + [ + 'cn-hangzhou' => 'oos.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'oos.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'oos.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'oos.cn-hongkong.aliyuncs.com', + 'us-east-1' => 'oos.us-east-1.aliyuncs.com', + 'cn-beijing' => 'oos.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'oos.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'oos.cn-huhehaote.aliyuncs.com', + 'eu-west-1' => 'oos.eu-west-1.aliyuncs.com', + 'eu-central-1' => 'oos.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'oos.ap-south-1.aliyuncs.com', + 'cn-chengdu' => 'oos.cn-chengdu.aliyuncs.com', + 'ap-southeast-1' => 'oos.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'oos.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'oos.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'oos.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'oos.ap-northeast-1.aliyuncs.com', + ], + 'fnf' => + [ + 'cn-hangzhou' => 'cn-hangzhou.fnf.aliyuncs.com', + 'cn-shanghai' => 'cn-shanghai.fnf.aliyuncs.com', + 'cn-shenzhen' => 'cn-shenzhen.fnf.aliyuncs.com', + 'cn-beijing' => 'cn-beijing.fnf.aliyuncs.com', + ], + 'smc' => + [ + 'cn-huhehaote' => 'smc.aliyuncs.com', + 'cn-hangzhou' => 'smc.aliyuncs.com', + 'cn-qingdao' => 'smc.aliyuncs.com', + 'cn-beijing' => 'smc.aliyuncs.com', + 'cn-zhangjiakou' => 'smc.aliyuncs.com', + 'cn-shanghai' => 'smc.aliyuncs.com', + 'cn-shenzhen' => 'smc.aliyuncs.com', + 'cn-hongkong' => 'smc.aliyuncs.com', + 'ap-southeast-1' => 'smc.aliyuncs.com', + 'ap-southeast-2' => 'smc.aliyuncs.com', + 'ap-southeast-3' => 'smc.aliyuncs.com', + 'ap-southeast-5' => 'smc.aliyuncs.com', + 'ap-northeast-1' => 'smc.aliyuncs.com', + 'eu-west-1' => 'smc.aliyuncs.com', + 'us-west-1' => 'smc.aliyuncs.com', + 'us-east-1' => 'smc.aliyuncs.com', + 'eu-central-1' => 'smc.aliyuncs.com', + 'me-east-1' => 'smc.aliyuncs.com', + 'ap-south-1' => 'smc.aliyuncs.com', + 'cn-chengdu' => 'smc.aliyuncs.com', + ], + 'foasconsole' => + [ + 'cn-beijing' => 'foasconsole.aliyuncs.com', + 'cn-zhangjiakou' => 'foasconsole.aliyuncs.com', + 'cn-hangzhou' => 'foasconsole.aliyuncs.com', + 'cn-shanghai' => 'foasconsole.aliyuncs.com', + 'cn-shenzhen' => 'foasconsole.aliyuncs.com', + 'cn-hongkong' => 'foasconsole.aliyuncs.com', + 'ap-southeast-1' => 'foasconsole.aliyuncs.com', + 'ap-southeast-3' => 'foasconsole.aliyuncs.com', + 'ap-northeast-1' => 'foasconsole.aliyuncs.com', + 'cn-hangzhou-finance' => 'foasconsole.aliyuncs.com', + 'cn-shanghai-finance-1' => 'foasconsole.aliyuncs.com', + 'cn-north-2-gov-1' => 'foasconsole.aliyuncs.com', + 'eu-central-1' => 'foasconsole.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'foasconsole.aliyuncs.com', + ], + 'serverless' => + [ + 'cn-beijing' => 'sae.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'sae.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'sae.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'sae.cn-shenzhen.aliyuncs.com', + 'us-west-1' => 'sae.us-west-1.aliyuncs.com', + ], + 'ivpd' => + [ + 'cn-huhehaote' => 'ivpd.cn-huhehaote.aliyuncs.com', + 'cn-shanghai' => 'ivpd.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'ivpd.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'ivpd.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'ivpd.cn-zhangjiakou.aliyuncs.com', + 'cn-hongkong' => 'ivpd.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'ivpd.ap-southeast-1.aliyuncs.com', + ], + 'hivisengine' => + [ + 'cn-huhehaote' => 'hivisengine.aliyuncs.com', + 'cn-shanghai' => 'hivisengine.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'hivisengine.cn-hangzhou.aliyuncs.com', + ], + 'hiknoengine' => + [ + 'cn-huhehaote' => 'hiknoengine.aliyuncs.com', + 'cn-shanghai' => 'hiknoengine.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'hiknoengine.cn-hangzhou.aliyuncs.com', + ], + 'clouddev' => + [ + 'cn-hangzhou' => 'mpserverless.aliyuncs.com', + 'cn-shanghai' => 'mpserverless.aliyuncs.com', + ], + 'premiumpics' => + [ + 'cn-hangzhou' => 'premiumpics.aliyuncs.com', + ], + 'composer' => + [ + 'cn-hangzhou' => 'composer.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'composer.cn-shanghai.aliyuncs.com', + 'us-east-1' => 'composer.us-east-1.aliyuncs.com', + 'ap-southeast-1' => 'composer.ap-southeast-1.aliyuncs.com', + ], + 'cloudesl' => + [ + 'cn-hangzhou' => 'cloudesl.cn-hangzhou.aliyuncs.com', + ], + 'amscloudapp' => + [ + 'cn-hangzhou' => 'mpca.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'mpca.cn-shanghai.aliyuncs.com', + ], + 'mse' => + [ + 'cn-hangzhou' => 'mse.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'mse.cn-shanghai.aliyuncs.com', + 'cn-beijing' => 'mse.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'mse.cn-zhangjiakou.aliyuncs.com', + 'cn-shenzhen' => 'mse.cn-shenzhen.aliyuncs.com', + 'us-east-1' => 'mse.us-east-1.aliyuncs.com', + 'ap-southeast-1' => 'mse.ap-southeast-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'msefinance-share.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'msefinance-share.cn-shenzhen-finance-1.aliyuncs.com', + ], + 'dg' => + [ + 'cn-hangzhou' => 'dg.cn-hangzhou.aliyuncs.com', + ], + 'graphcompute' => + [ + 'cn-shanghai' => 'gcs.cn-shanghai.aliyuncs.com', + ], + 'cds' => + [ + 'ap-southeast-1' => 'cassandra.aliyuncs.com', + 'cn-qingdao' => 'cassandra.aliyuncs.com', + 'cn-beijing' => 'cassandra.aliyuncs.com', + 'cn-hangzhou' => 'cassandra.aliyuncs.com', + 'cn-shanghai' => 'cassandra.aliyuncs.com', + 'cn-shenzhen' => 'cassandra.aliyuncs.com', + 'cn-hongkong' => 'cassandra.aliyuncs.com', + 'cn-chengdu' => 'cassandra.aliyuncs.com', + 'cn-zhangjiakou' => 'cassandra.aliyuncs.com', + 'cn-huhehaote' => 'cassandra.aliyuncs.com', + 'ap-southeast-2' => 'cassandra.aliyuncs.com', + 'ap-southeast-3' => 'cassandra.aliyuncs.com', + 'ap-southeast-5' => 'cassandra.aliyuncs.com', + 'eu-west-1' => 'cassandra.aliyuncs.com', + 'us-west-1' => 'cassandra.aliyuncs.com', + 'us-east-1' => 'cassandra.aliyuncs.com', + 'eu-central-1' => 'cassandra.aliyuncs.com', + 'me-east-1' => 'cassandra.aliyuncs.com', + 'ap-south-1' => 'cassandra.aliyuncs.com', + 'ap-northeast-1' => 'cassandra.aliyuncs.com', + ], + 'ads' => + [ + 'cn-qingdao' => 'adb.aliyuncs.com', + 'cn-beijing' => 'adb.aliyuncs.com', + 'cn-zhangjiakou' => 'adb.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'adb.aliyuncs.com', + 'cn-shanghai' => 'adb.aliyuncs.com', + 'cn-shenzhen' => 'adb.aliyuncs.com', + 'cn-hongkong' => 'adb.aliyuncs.com', + 'ap-southeast-1' => 'adb.aliyuncs.com', + 'ap-northeast-1' => 'adb.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'adb.eu-west-1.aliyuncs.com', + 'us-west-1' => 'adb.aliyuncs.com', + 'us-east-1' => 'adb.aliyuncs.com', + 'ap-southeast-2' => 'adb.ap-southeast-2.aliyuncs.com', + 'eu-central-1' => 'adb.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'adb.ap-south-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'adb.aliyuncs.com', + 'cn-chengdu' => 'adb.cn-chengdu.aliyuncs.com', + 'cn-huhehaote' => 'adb.cn-huhehaote.aliyuncs.com', + 'ap-southeast-3' => 'adb.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'adb.ap-southeast-5.aliyuncs.com', + 'cn-hangzhou-finance' => 'adb.aliyuncs.com', + 'cn-shanghai-finance-1' => 'adb.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'adb.aliyuncs.com', + ], + 'csb' => + [ + 'cn-beijing' => 'csb.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'csb.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'csb.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'csb.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'csb.cn-hongkong.aliyuncs.com', + 'cn-north-2-gov-1' => 'csb.cn-north-2-gov-1.aliyuncs.com', + ], + 'cityvisual' => + [ + 'cn-hangzhou' => 'cityvisual.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'cityvisual.cn-shanghai.aliyuncs.com', + ], + 'dbaudit' => + [ + 'cn-hangzhou' => 'yundun-dbaudit.aliyuncs.com', + 'cn-qingdao' => 'yundun-dbaudit.aliyuncs.com', + 'cn-beijing' => 'yundun-dbaudit.aliyuncs.com', + 'cn-zhangjiakou' => 'yundun-dbaudit.aliyuncs.com', + 'cn-huhehaote' => 'yundun-dbaudit.aliyuncs.com', + 'cn-shanghai' => 'yundun-dbaudit.aliyuncs.com', + 'cn-shenzhen' => 'yundun-dbaudit.aliyuncs.com', + 'cn-hongkong' => 'yundun-dbaudit.aliyuncs.com', + 'ap-southeast-1' => 'yundun-dbaudit.aliyuncs.com', + 'ap-southeast-2' => 'yundun-dbaudit.aliyuncs.com', + 'ap-southeast-3' => 'yundun-dbaudit.aliyuncs.com', + 'ap-southeast-5' => 'yundun-dbaudit.aliyuncs.com', + 'ap-northeast-1' => 'yundun-dbaudit.aliyuncs.com', + 'us-west-1' => 'yundun-dbaudit.aliyuncs.com', + 'us-east-1' => 'yundun-dbaudit.aliyuncs.com', + 'eu-central-1' => 'yundun-dbaudit.aliyuncs.com', + 'me-east-1' => 'yundun-dbaudit.aliyuncs.com', + 'ap-south-1' => 'yundun-dbaudit.aliyuncs.com', + 'cn-shanghai-finance-1' => 'yundun-dbaudit.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'yundun-dbaudit.aliyuncs.com', + 'cn-north-2-gov-1' => 'yundun-dbaudit.aliyuncs.com', + 'cn-chengdu' => 'yundun-dbaudit.aliyuncs.com', + 'eu-west-1' => 'yundun-dbaudit.aliyuncs.com', + 'cn-huhehaote-nebula-1' => 'yundun-dbaudit.aliyuncs.com', + ], + 'bssopenapi' => + [ + 'cn-hangzhou' => 'business.aliyuncs.com', + 'cn-shanghai' => 'business.aliyuncs.com', + 'ap-southeast-1' => 'business.ap-southeast-1.aliyuncs.com', + ], + 'indvi' => + [ + 'cn-hangzhou' => 'indvi.cn-hangzhou.aliyuncs.com', + ], + 'swcopyright' => + [ + 'cn-hangzhou' => 'copyright.aliyuncs.com', + ], + 'multimediaai' => + [ + 'cn-beijing' => 'multimediaai.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'multimediaai.cn-hangzhou.aliyuncs.com', + ], + 'rsimganalys' => + [ + 'cn-hangzhou' => 'rsimganalys.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'rsimganalys.cn-shanghai.aliyuncs.com', + ], + 'tdsr' => + [ + 'cn-hangzhou' => 'lyj.cn-hangzhou.aliyuncs.com', + ], + 'eslogstash' => + [ + 'cn-qingdao' => 'elasticsearch.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'elasticsearch.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'elasticsearch.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'elasticsearch.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'elasticsearch.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'elasticsearch.cn-shenzhen.aliyuncs.com', + ], + 'vcoverimage' => + [ + 'cn-beijing' => 'vcoverimage.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'vcoverimage.cn-hangzhou.aliyuncs.com', + ], + 'ahas' => + [ + 'cn-beijing' => 'ahas.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'ahas.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'ahas.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'ahas.cn-shenzhen.aliyuncs.com', + 'cn-zhangjiakou' => 'ahas.cn-zhangjiakou.aliyuncs.com', + ], + 'vstruction' => + [ + 'cn-beijing' => 'vstruction.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'vstruction.cn-hangzhou.aliyuncs.com', + ], + 'vcovergif' => + [ + 'cn-beijing' => 'vcovergif.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'vcovergif.cn-hangzhou.aliyuncs.com', + ], + 'aiccs' => + [ + 'cn-hangzhou' => 'aiccs.aliyuncs.com', + ], + 'nls' => + [ + 'cn-shanghai' => 'nls-slp.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'nls-slp.cn-shanghai.aliyuncs.com', + ], + 'antcloudauth' => + [ + 'cn-shanghai' => 'antcloudauth.cn-shanghai.aliyuncs.com', + ], + 'prepaid_ads' => + [ + 'cn-hangzhou-finance' => 'ads.cn-hangzhou-finance.aliyuncs.com', + 'cn-beijing' => 'ads.cn-beijing.aliyuncs.com', + 'cn-chengdu' => 'ads.cn-chengdu.aliyuncs.com', + 'cn-zhangjiakou' => 'ads.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'ads.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'ads.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'ads.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'ads.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'ads.ap-southeast-1.aliyuncs.com', + 'ap-southeast-3' => 'ads.ap-southeast-3.aliyuncs.com', + 'ap-northeast-1' => 'ads-share.ap-northeast-1.aliyuncs.com', + 'us-west-1' => 'ads.us-west-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'ads.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'ads.cn-north-2-gov-1.aliyuncs.com', + ], + 'hdr' => + [ + 'cn-qingdao' => 'hdr.cn-shanghai.aliyuncs.com', + 'cn-beijing' => 'hdr.cn-shanghai.aliyuncs.com', + 'cn-zhangjiakou' => 'hdr.cn-shanghai.aliyuncs.com', + 'cn-hangzhou' => 'hdr.cn-shanghai.aliyuncs.com', + 'cn-shanghai' => 'hdr.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'hdr.cn-shanghai.aliyuncs.com', + 'cn-hongkong' => 'hdr.cn-shanghai.aliyuncs.com', + 'cn-chengdu' => 'hdr.cn-shanghai.aliyuncs.com', + ], + 'cbs' => + [ + 'cn-qingdao' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-beijing' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-zhangjiakou' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-huhehaote' => 'dbs-api.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-hongkong' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'dbs-api.ap-southeast-1.aliyuncs.com', + 'ap-northeast-1' => 'dbs-api.ap-northeast-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-shanghai-finance-1' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'cn-chengdu' => 'dbs-api.cn-chengdu.aliyuncs.com', + 'ap-southeast-2' => 'dbs-api.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'dbs-api.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'dbs-api.ap-southeast-5.aliyuncs.com', + 'us-west-1' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'us-east-1' => 'dbs-api.cn-hangzhou.aliyuncs.com', + 'eu-central-1' => 'dbs-api.eu-central-1.aliyuncs.com', + ], + 'datag' => + [ + 'cn-beijing' => 'datag.cn-beijing.aliyuncs.com', + ], + 'retailir' => + [ + 'cn-hangzhou' => 'retailir.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'retailir.cn-shanghai.aliyuncs.com', + ], + 'mpaas' => + [ + 'cn-hangzhou' => 'mpaas.aliyuncs.com', + ], + 'iqa' => + [ + 'cn-hangzhou' => 'iqa.cn-hangzhou.aliyuncs.com', + ], + 'sofa' => + [ + 'cn-hangzhou' => 'sofa.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'sofa.cn-shanghai.aliyuncs.com', + 'cn-hangzhou-finance' => 'sofa.cn-shanghai.aliyuncs.com', + ], + 'edas' => + [ + 'cn-hangzhou' => 'edas.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'edas.cn-shanghai.aliyuncs.com', + 'cn-qingdao' => 'edas.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'edas.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'edas.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'edas.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'edas.cn-shanghai.aliyuncs.com', + 'ap-southeast-1' => 'edas.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'edas.ap-southeast-1.aliyuncs.com', + 'us-east-1' => 'edas.ap-southeast-1.aliyuncs.com', + 'eu-central-1' => 'edas.ap-southeast-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'edas.cn-shanghai.aliyuncs.com', + ], + 'gwsservice' => + [ + 'cn-shanghai' => 'gws.cn-shanghai.aliyuncs.com', + 'cn-beijing' => 'gws.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'gws.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'gws.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'gws.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen' => 'gws.cn-shenzhen.aliyuncs.com', + 'cn-chengdu' => 'gws.cn-chengdu.aliyuncs.com', + 'ap-southeast-1' => 'gws.ap-southeast-1.aliyuncs.com', + 'cn-hongkong' => 'gws.cn-hongkong.aliyuncs.com', + 'ap-southeast-2' => 'gws.ap-southeast-2.aliyuncs.com', + 'us-west-1' => 'gws.us-west-1.aliyuncs.com', + 'us-east-1' => 'gws.us-east-1.aliyuncs.com', + 'eu-central-1' => 'gws.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'gws.ap-south-1.aliyuncs.com', + 'cn-qingdao' => 'gws.cn-qingdao.aliyuncs.com', + 'ap-southeast-3' => 'gws.ap-northeast-3.aliyuncs.com', + 'ap-southeast-5' => 'gws.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'gws.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'gws.eu-west-1.aliyuncs.com', + ], + 'gds' => + [ + 'ap-southeast-1' => 'gdb-api.aliyuncs.com', + 'cn-beijing' => 'gdb-api.aliyuncs.com', + 'cn-zhangjiakou' => 'gdb-api.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'gdb-api.aliyuncs.com', + 'cn-shanghai' => 'gdb-api.aliyuncs.com', + 'cn-shenzhen' => 'gdb-api.aliyuncs.com', + 'ap-southeast-5' => 'gdb-api.ap-southeast-5.aliyuncs.com', + 'cn-qingdao' => 'gdb-api.aliyuncs.com', + 'cn-chengdu' => 'gdb-api.cn-chengdu.aliyuncs.com', + 'cn-huhehaote' => 'gdb-api.cn-huhehaote.aliyuncs.com', + 'cn-hongkong' => 'gdb-api.aliyuncs.com', + 'ap-southeast-2' => 'gdb-api.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'gdb-api.ap-southeast-3.aliyuncs.com', + 'eu-west-1' => 'gdb-api.eu-west-1.aliyuncs.com', + 'us-west-1' => 'gdb-api.aliyuncs.com', + 'us-east-1' => 'gdb-api.aliyuncs.com', + 'eu-central-1' => 'gdb-api.eu-central-1.aliyuncs.com', + 'me-east-1' => 'gdb-api.me-east-1.aliyuncs.com', + 'ap-south-1' => 'gdb-api.ap-south-1.aliyuncs.com', + ], + 'eais' => + [ + 'cn-beijing' => 'eais.cn-beijing.aliyuncs.com', + 'cn-shenzhen' => 'eais.cn-shenzhen.aliyuncs.com', + ], + 'clickhouse' => + [ + 'cn-beijing' => 'clickhouse.aliyuncs.com', + 'cn-hangzhou' => 'clickhouse.aliyuncs.com', + 'cn-shanghai' => 'clickhouse.aliyuncs.com', + 'cn-shenzhen' => 'clickhouse.aliyuncs.com', + 'ap-southeast-1' => 'clickhouse.aliyuncs.com', + ], + 'msepost' => + [ + 'cn-beijing' => 'mse.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'mse.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'mse.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'mse.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'mse.cn-shenzhen.aliyuncs.com', + 'us-east-1' => 'mse.us-east-1.aliyuncs.com', + ], + 'visionai' => + [ + 'cn-beijing' => 'visionai.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'visionai.cn-hangzhou.aliyuncs.com', + ], + 'mseprepaid' => + [ + 'cn-beijing' => 'mse.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'mse.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'mse.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'mse.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'mse.cn-shenzhen.aliyuncs.com', + 'us-east-1' => 'mse.us-east-1.aliyuncs.com', + ], + 'adam' => + [ + 'cn-beijing' => 'adam.cn-beijing.aliyuncs.com', + ], + 'onsmqtt' => + [ + 'cn-beijing' => 'onsmqtt.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'onsmqtt.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'onsmqtt.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'onsmqtt.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'onsmqtt.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'onsmqtt.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'onsmqtt.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'onsmqtt.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'onsmqtt.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'onsmqtt.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'onsmqtt.ap-southeast-5.aliyuncs.com', + 'us-west-1' => 'onsmqtt.us-west-1.aliyuncs.com', + 'eu-central-1' => 'onsmqtt.eu-central-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'onsmqtt.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'onsmqtt.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-qingdao' => 'onsmqtt.cn-qingdao.aliyuncs.com', + 'ap-northeast-1' => 'onsmqtt.ap-northeast-1.aliyuncs.com', + 'cn-chengdu' => 'onsmqtt.cn-chengdu.aliyuncs.com', + 'us-east-1' => 'onsmqtt.us-east-1.aliyuncs.com', + 'ap-south-1' => 'onsmqtt.ap-south-1.aliyuncs.com', + ], + 'dypls' => + [ + 'cn-hangzhou' => 'dyplsapi.aliyuncs.com', + ], + 'resourcemanager' => + [ + 'cn-hangzhou' => 'resourcemanager.aliyuncs.com', + 'cn-shanghai' => 'resourcemanager.aliyuncs.com', + ], + 'nlpautoml' => + [ + 'cn-hangzhou' => 'nlp-automl.cn-hangzhou.aliyuncs.com', + ], + 'companyreg' => + [ + 'cn-hangzhou' => 'companyreg.aliyuncs.com', + ], + 'aliyuncvc' => + [ + 'cn-hangzhou' => 'aliyuncvc.cn-hangzhou.aliyuncs.com', + ], + 'alimtautoml' => + [ + 'cn-hangzhou' => 'alimtautoml.cn-hangzhou.aliyuncs.com', + ], + 'dbfs' => + [ + 'cn-hangzhou' => 'dbfs.cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'dbfs.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'dbfs.cn-beijing.aliyuncs.com', + 'cn-chengdu' => 'dbfs.cn-chengdu.aliyuncs.com', + 'cn-zhangjiakou' => 'dbfs.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'dbfs.cn-huhehaote.aliyuncs.com', + 'cn-shanghai' => 'dbfs.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'dbfs.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'dbfs.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'dbfs.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'dbfs.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'dbfs.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'dbfs.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'dbfs.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'dbfs.eu-west-1.aliyuncs.com', + 'us-west-1' => 'dbfs.us-west-1.aliyuncs.com', + 'us-east-1' => 'dbfs.us-east-1.aliyuncs.com', + 'eu-central-1' => 'dbfs.eu-central-1.aliyuncs.com', + 'me-east-1' => 'dbfs.me-east-1.aliyuncs.com', + 'ap-south-1' => 'dbfs.ap-south-1.aliyuncs.com', + 'cn-heyuan' => 'dbfs.cn-heyuan.aliyuncs.com', + ], + 'addrp' => + [ + 'cn-hangzhou' => 'address-purification.cn-hangzhou.aliyuncs.com', + ], + 'gaplus' => + [ + 'cn-hangzhou' => 'ga.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'ga.cn-hangzhou.aliyuncs.com', + ], + 'datav' => + [ + 'cn-hangzhou' => 'datav.cn-hangzhou.aliyuncs.com', + ], + 'ocr' => + [ + 'cn-shanghai' => 'ocr.cn-shanghai.aliyuncs.com', + ], + 'objectdet' => + [ + 'cn-shanghai' => 'objectdet.cn-shanghai.aliyuncs.com', + ], + 'assetservice' => + [ + 'cn-shanghai' => 'assettech.cn-shanghai.aliyuncs.com', + ], + 'imageenhan' => + [ + 'cn-shanghai' => 'imageenhan.cn-shanghai.aliyuncs.com', + ], + 'imageaudit' => + [ + 'cn-shanghai' => 'imageaudit.cn-shanghai.aliyuncs.com', + ], + 'imagerecog' => + [ + 'cn-shanghai' => 'imagerecog.cn-shanghai.aliyuncs.com', + ], + 'imageseg' => + [ + 'cn-shanghai' => 'imageseg.cn-shanghai.aliyuncs.com', + ], + 'goodstech' => + [ + 'cn-shanghai' => 'goodstech.cn-shanghai.aliyuncs.com', + ], + 'facebody' => + [ + 'cn-shanghai' => 'facebody.cn-shanghai.aliyuncs.com', + ], + 'voicebot' => + [ + 'cn-hangzhou' => 'voicenavigator.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'voicenavigator.cn-shanghai.aliyuncs.com', + ], + 'dyiot' => + [ + 'cn-hangzhou' => 'dyiotapi.aliyuncs.com', + ], + 'drp' => + [ + 'cn-hangzhou' => 'drp-share.cn-hangzhou.aliyuncs.com', + ], + 'uem' => + [ + 'cn-hangzhou' => 'uem.aliyuncs.com', + ], + 'outboundbot' => + [ + 'cn-hangzhou' => 'outboundbot.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'outboundbot.cn-shanghai.aliyuncs.com', + ], + 'hcs_hgw' => + [ + 'cn-shanghai' => 'hgw.cn-shanghai.aliyuncs.com', + ], + 'acms' => + [ + 'cn-qingdao' => 'acm.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'acm.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'acm.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'acm.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'acm.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'acm.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'acm.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'acm.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'acm.ap-southeast-2.aliyuncs.com', + 'us-west-1' => 'acm.us-west-1.aliyuncs.com', + 'us-east-1' => 'acm.us-east-1.aliyuncs.com', + 'eu-central-1' => 'acm.eu-central-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'acm.cn-hangzhou-finance.aliyuncs.com', + 'cn-shanghai-finance-1' => 'acm.cn-shanghai-finance-1.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'acm.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'acm.cn-north-2-gov-1.aliyuncs.com', + 'ap-south-1' => 'acm.ap-south-1.aliyuncs.com', + ], + 'onsproxy' => + [ + 'cn-qingdao' => 'amqp-open.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'amqp-open.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'amqp-open.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'amqp-open.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'amqp-open.cn-shenzhen.aliyuncs.com', + 'cn-zhangjiakou' => 'amqp-open.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'amqp-open.cn-huhehaote.aliyuncs.com', + 'cn-hongkong' => 'amqp-open.cn-hongkong.aliyuncs.com', + ], + 'drdsro' => + [ + 'cn-qingdao' => 'drds.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'drds.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'drds.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'drds.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'drds.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'drds.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'drds.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'drds.cn-hangzhou.aliyuncs.com', + 'ap-southeast-1' => 'drds.ap-southeast-1.aliyuncs.com', + 'us-east-1' => 'drds.us-east-1.aliyuncs.com', + 'cn-shanghai-finance-1' => 'drds.cn-hangzhou.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'drds.cn-hangzhou.aliyuncs.com', + 'cn-north-2-gov-1' => 'drds.cn-hangzhou.aliyuncs.com', + ], + 'opensearch' => + [ + 'cn-qingdao' => 'opensearch.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'opensearch.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'opensearch.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'opensearch.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'opensearch.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'opensearch.cn-shenzhen.aliyuncs.com', + 'ap-southeast-1' => 'opensearch.ap-southeast-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'opensearch.cn-north-2-gov-1.aliyuncs.com', + ], + 'edasschedulerx' => + [ + 'cn-beijing' => 'schedulerx.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'schedulerx.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'schedulerx.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'schedulerx.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'schedulerx.cn-shenzhen.aliyuncs.com', + 'us-east-1' => 'schedulerx.us-east-1.aliyuncs.com', + ], + 'tag' => + [ + 'cn-beijing' => 'tag.aliyuncs.com', + 'cn-shenzhen' => 'tag.aliyuncs.com', + 'cn-qingdao' => 'tag.aliyuncs.com', + 'cn-chengdu' => 'tag.cn-chengdu.aliyuncs.com', + 'cn-zhangjiakou' => 'tag.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'tag.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'tag.aliyuncs.com', + 'cn-shanghai' => 'tag.aliyuncs.com', + 'cn-hongkong' => 'tag.aliyuncs.com', + 'ap-southeast-1' => 'tag.aliyuncs.com', + 'ap-southeast-2' => 'tag.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'tag.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'tag.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'tag.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'tag.eu-west-1.aliyuncs.com', + 'us-west-1' => 'tag.aliyuncs.com', + 'us-east-1' => 'tag.aliyuncs.com', + 'eu-central-1' => 'tag.eu-central-1.aliyuncs.com', + 'me-east-1' => 'tag.me-east-1.aliyuncs.com', + 'ap-south-1' => 'tag.ap-south-1.aliyuncs.com', + 'cn-hangzhou-finance' => 'tag.aliyuncs.com', + 'cn-shanghai-finance-1' => 'tag.aliyuncs.com', + 'cn-shenzhen-finance-1' => 'tag.cn-shenzhen-finance-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'tag.cn-north-2-gov-1.aliyuncs.com', + 'cn-fujian' => 'tag.aliyuncs.com', + 'cn-haidian-cm12-c01' => 'tag.aliyuncs.com', + 'cn-hangzhou-internal-test-2' => 'tag.aliyuncs.com', + 'cn-hangzhou-internal-test-3' => 'tag.aliyuncs.com', + 'cn-hangzhou-test-306' => 'tag.aliyuncs.com', + 'cn-shanghai-et15-b01' => 'tag.aliyuncs.com', + 'cn-zhangbei-na61-b01' => 'tag.aliyuncs.com', + 'eu-west-1-oxs' => 'tag.cn-shenzhen-cloudstone.aliyuncs.com', + 'cn-heyuan' => 'tag.cn-heyuan.aliyuncs.com', + 'cn-wulanchabu' => 'tag.cn-wulanchabu.aliyuncs.com', + ], + 'servicemesh' => + [ + 'cn-beijing' => 'servicemesh.aliyuncs.com', + 'cn-zhangjiakou' => 'servicemesh.aliyuncs.com', + 'cn-hangzhou' => 'servicemesh.aliyuncs.com', + 'cn-shanghai' => 'servicemesh.aliyuncs.com', + 'cn-shenzhen' => 'servicemesh.aliyuncs.com', + 'ap-southeast-1' => 'servicemesh.aliyuncs.com', + 'us-west-1' => 'servicemesh.aliyuncs.com', + ], + 'rdc' => + [ + 'cn-beijing' => 'rdc.cn-beijing.aliyuncs.com', + ], + 'sddprsrc' => + [ + 'cn-zhangjiakou' => 'sddp-rsrc.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'sddprsrc.cn-hangzhou.aliyuncs.com', + 'cn-north-2-gov-1' => 'sddprsrc.cn-north-2-gov-1.aliyuncs.com', + ], + 'polardbx' => + [ + 'cn-hangzhou' => 'polardbx.cn-hangzhou.aliyuncs.com', + 'cn-qingdao' => 'polardbx.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'polardbx.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'polardbx.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'polardbx.cn-huhehaote.aliyuncs.com', + 'cn-shanghai' => 'polardbx.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'polardbx.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'polardbx.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'polardbx.ap-southeast-1.aliyuncs.com', + ], + 'dytns' => + [ + 'cn-hangzhou' => 'dytnsapi.aliyuncs.com', + ], + 'datahub' => + [ + 'cn-hangzhou' => 'datahub.aliyuncs.com', + 'cn-shanghai' => 'datahub.aliyuncs.com', + ], + 'geoip' => + [ + 'cn-hangzhou' => 'geoip.aliyuncs.com', + ], + 'digitalstore' => + [ + 'cn-hangzhou' => 'digitalstore.cn-hangzhou.aliyuncs.com', + ], + 'quickbi' => + [ + 'cn-hangzhou' => 'quickbi-public-share.aliyuncs.com', + 'cn-hongkong' => 'quickbi-public-share.aliyuncs.com', + 'ap-southeast-1' => 'quickbi-public-share.aliyuncs.com', + 'ap-southeast-3' => 'quickbi-public-share.aliyuncs.com', + 'eu-central-1' => 'quickbi-public-share.aliyuncs.com', + ], + 'alimtdt' => + [ + 'cn-hangzhou' => 'mt.cn-hangzhou.aliyuncs.com', + ], + 'sofamq' => + [ + 'cn-shanghai' => 'sofa.cn-shanghai.aliyuncs.com', + 'cn-hangzhou-finance' => 'sofa.cn-hangzhou-finance.aliyuncs.com', + ], + 'sofaodp' => + [ + 'cn-shanghai' => 'sofa.cn-shanghai.aliyuncs.com', + 'cn-hangzhou-finance' => 'sofa.cn-hangzhou-finance.aliyuncs.com', + ], + 'dascharge' => + [ + 'cn-shanghai' => 'das.aliyuncs.com', + 'cn-hangzhou' => 'das.aliyuncs.com', + ], + 'sofadst' => + [ + 'cn-shanghai' => 'sofa.cn-shanghai.aliyuncs.com', + ], + 'springcloud' => + [ + 'cn-qingdao' => 'ms.aliyuncs.com', + 'cn-beijing' => 'ms.aliyuncs.com', + 'cn-zhangjiakou' => 'ms.aliyuncs.com', + 'cn-hangzhou' => 'ms.aliyuncs.com', + 'cn-shanghai' => 'ms.aliyuncs.com', + 'cn-shenzhen' => 'ms.aliyuncs.com', + ], + 'edasmsc' => + [ + 'cn-qingdao' => 'edasmsc.aliyuncs.com', + 'cn-beijing' => 'edasmsc.aliyuncs.com', + 'cn-zhangjiakou' => 'edasmsc.aliyuncs.com', + 'cn-hangzhou' => 'edasmsc.aliyuncs.com', + 'cn-shanghai' => 'edasmsc.aliyuncs.com', + 'cn-shenzhen' => 'edasmsc.aliyuncs.com', + 'cn-hongkong' => 'edasmsc.aliyuncs.com', + ], + 'polarx' => + [ + 'cn-qingdao' => 'polardbx-share.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'polardbx-share.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'polardbx-share.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'polardbx-share.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'polardbx-share.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'polardbx-share.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'polardbx-share.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'polardbx-share.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'polardbx-share.ap-southeast-1.aliyuncs.com', + ], + 'cddc' => + [ + 'cn-qingdao' => 'cddc.aliyuncs.com', + 'cn-beijing' => 'cddc.aliyuncs.com', + 'cn-chengdu' => 'cddc.cn-chengdu.aliyuncs.com', + 'cn-zhangjiakou' => 'cddc.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'cddc.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'cddc.aliyuncs.com', + 'cn-shanghai' => 'cddc.aliyuncs.com', + 'cn-shenzhen' => 'cddc.aliyuncs.com', + 'cn-hongkong' => 'cddc.aliyuncs.com', + 'ap-southeast-1' => 'cddc.aliyuncs.com', + 'ap-southeast-2' => 'cddc.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'cddc.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'cddc.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'cddc.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'cddc.eu-west-1.aliyuncs.com', + 'us-west-1' => 'cddc.aliyuncs.com', + 'us-east-1' => 'cddc.aliyuncs.com', + 'eu-central-1' => 'cddc.eu-central-1.aliyuncs.com', + 'me-east-1' => 'cddc.me-east-1.aliyuncs.com', + 'ap-south-1' => 'cddc.ap-south-1.aliyuncs.com', + 'cn-heyuan' => 'cddc.aliyuncs.com', + ], + 'dlasparkpre' => + [ + 'cn-qingdao' => 'dlaspark.aliyuncs.com', + 'cn-beijing' => 'dlaspark.aliyuncs.com', + 'cn-zhangjiakou' => 'dlaspark.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'dlaspark.aliyuncs.com', + 'cn-shanghai' => 'dlaspark.aliyuncs.com', + 'cn-shenzhen' => 'dlaspark.aliyuncs.com', + ], + 'spark' => + [ + 'cn-qingdao' => 'ddi.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'ddi.aliyuncs.com', + 'cn-chengdu' => 'ddi.cn-chengdu.aliyuncs.com', + 'cn-zhangjiakou' => 'ddi.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'ddi.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'ddi.aliyuncs.com', + 'cn-shanghai' => 'ddi.aliyuncs.com', + 'cn-shenzhen' => 'ddi.aliyuncs.com', + 'cn-hongkong' => 'ddi.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'ddi.aliyuncs.com', + 'ap-southeast-2' => 'ddi.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'ddi.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'ddi.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'ddi.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'ddi.eu-west-1.aliyuncs.com', + 'us-west-1' => 'ddi.aliyuncs.com', + 'us-east-1' => 'ddi.us-east-1.aliyuncs.com', + 'eu-central-1' => 'ddi.eu-central-1.aliyuncs.com', + 'me-east-1' => 'ddi.me-east-1.aliyuncs.com', + 'ap-south-1' => 'ddi.ap-south-1.aliyuncs.com', + 'cn-heyuan' => 'ddi.aliyuncs.com', + ], + 'multisearch' => + [ + 'cn-beijing' => 'multisearch.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'multisearch.cn-hangzhou.aliyuncs.com', + ], + 'pai' => + [ + 'cn-beijing' => 'pai.cn-beijing.aliyuncs.com', + 'cn-hangzhou' => 'pai.cn-hangzhou.data.aliyun.com', + 'cn-shanghai' => 'pai.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'pai.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'pai.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'pai.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'pai.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'pai.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'pai.ap-southeast-5.aliyuncs.com', + 'us-west-1' => 'pai.us-west-1.aliyuncs.com', + 'us-east-1' => 'pai.us-east-1.aliyuncs.com', + 'eu-central-1' => 'pai.eu-central-1.aliyuncs.com', + 'me-east-1' => 'pai.me-east-1.aliyuncs.com', + 'ap-south-1' => 'pai.ap-south-1.aliyuncs.com', + ], + 'fcpre' => + [ + 'cn-chengdu' => 'cn-chengdu.fc.aliyuncs.com', + 'ap-southeast-3' => 'ap-southeast-3.fc.aliyuncs.com', + 'eu-west-1' => 'eu-west-1.fc.aliyuncs.com', + 'cn-hangzhou-finance' => 'cn-hangzhou-finance.fc.aliyuncs.com', + ], + 'ahaschaospre' => + [ + 'cn-zhangjiakou' => 'ahas.cn-zhangjiakou.aliyuncs.com', + ], + 'sasti' => + [ + 'cn-zhangjiakou' => 'sasti.aliyuncs.com', + ], + 'config' => + [ + 'cn-hangzhou' => 'config.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'config.cn-shanghai.aliyuncs.com', + ], + 'ledgerdb' => + [ + 'cn-hangzhou' => 'ledgerdb.cn-hangzhou.aliyuncs.com', + ], + 'nlpvision' => + [ + 'cn-hangzhou' => 'nlp-vision.cn-hangzhou.aliyuncs.com', + ], + 'alimtld' => + [ + 'cn-hangzhou' => 'mt.cn-hangzhou.aliyuncs.com', + ], + 'databot' => + [ + 'cn-hangzhou' => 'databot.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'databot.cn-shanghai.aliyuncs.com', + ], + 'livinglink' => + [ + 'cn-hangzhou' => 'livinglink.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'livinglink.cn-shanghai.aliyuncs.com', + 'ap-southeast-1' => 'livinglink.ap-southeast-1.aliyuncs.com', + 'us-east-1' => 'livinglink.us-east-1.aliyuncs.com', + 'eu-central-1' => 'livinglink.eu-central-1.aliyuncs.com', + ], + 'eipanycast' => + [ + 'cn-hangzhou' => 'eipanycast.cn-hangzhou.aliyuncs.com', + ], + 'alimtct' => + [ + 'cn-hangzhou' => 'mt.cn-hangzhou.aliyuncs.com', + ], + 'videorecog' => + [ + 'cn-shanghai' => 'videorecog.cn-shanghai.aliyuncs.com', + ], + 'imageprocess' => + [ + 'cn-shanghai' => 'imageprocess.cn-shanghai.aliyuncs.com', + ], + 'sofats' => + [ + 'cn-shanghai' => 'sofa.cn-shanghai.aliyuncs.com', + 'cn-hangzhou-finance' => 'sofa.cn-hangzhou-finance.aliyuncs.com', + ], + 'videoenhan' => + [ + 'cn-shanghai' => 'videoenhan.cn-shanghai.aliyuncs.com', + ], + 'imgsearch' => + [ + 'cn-shanghai' => 'imgsearch.cn-shanghai.aliyuncs.com', + ], + 'videoseg' => + [ + 'cn-shanghai' => 'videoseg.cn-shanghai.aliyuncs.com', + ], + 'sofacaferms' => + [ + 'cn-hangzhou-finance' => 'sofa.cn-hangzhou-finance.aliyuncs.com', + ], + 'retailadvqa' => + [ + 'cn-zhangjiakou' => 'quicka-public.cn-zhangjiakou.aliyuncs.com', + 'cn-shanghai' => 'quicka-public.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'quicka-public.cn-shenzhen.aliyuncs.com', + ], + 'linkanalytics' => + [ + 'cn-hangzhou' => 'linkanalytics.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'linkanalytics.cn-shanghai.aliyuncs.com', + ], + 'swas' => + [ + 'cn-qingdao' => 'swas.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'swas.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'swas.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'swas.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'swas.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'swas.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'swas.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'swas.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'swas.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'swas.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'swas.ap-southeast-3.aliyuncs.com', + 'ap-southeast-5' => 'swas.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'swas.ap-northeast-1.aliyuncs.com', + 'eu-west-1' => 'swas.eu-west-1.aliyuncs.com', + 'us-west-1' => 'swas.us-west-1.aliyuncs.com', + 'us-east-1' => 'swas.us-east-1.aliyuncs.com', + 'eu-central-1' => 'swas.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'swas.ap-south-1.aliyuncs.com', + ], + 'gws' => + [ + 'cn-qingdao' => 'gws.cn-qingdao.aliyuncs.com', + 'cn-beijing' => 'gws.cn-beijing.aliyuncs.com', + 'cn-chengdu' => 'gws.cn-chengdu.aliyuncs.com', + 'cn-zhangjiakou' => 'gws.cn-zhangjiakou.aliyuncs.com', + 'cn-huhehaote' => 'gws.cn-huhehaote.aliyuncs.com', + 'cn-hangzhou' => 'gws.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'gws.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'gws.cn-shenzhen.aliyuncs.com', + 'cn-hongkong' => 'gws.cn-hongkong.aliyuncs.com', + 'ap-southeast-1' => 'gws.ap-southeast-1.aliyuncs.com', + 'ap-southeast-2' => 'gws.ap-southeast-2.aliyuncs.com', + 'ap-southeast-3' => 'gws.ap-northeast-3.aliyuncs.com', + 'ap-southeast-5' => 'gws.ap-southeast-5.aliyuncs.com', + 'ap-northeast-1' => 'gws.ap-northeast-1.aliyuncs.com', + 'us-west-1' => 'gws.us-west-1.aliyuncs.com', + 'us-east-1' => 'gws.us-east-1.aliyuncs.com', + 'eu-central-1' => 'gws.eu-central-1.aliyuncs.com', + 'ap-south-1' => 'gws.ap-south-1.aliyuncs.com', + ], + 'dlacupost' => + [ + 'cn-beijing' => 'openanalytics.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'openanalytics.cn-hongkong.aliyuncs.com', + 'cn-hangzhou' => 'openanalytics.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'openanalytics.cn-shanghai.aliyuncs.com', + 'cn-shenzhen' => 'openanalytics.cn-beijing.aliyuncs.com', + 'cn-hongkong' => 'openanalytics.cn-hongkong.aliyuncs.com', + ], + 'ressharing' => + [ + 'cn-beijing' => 'resourcesharing.cn-beijing.aliyuncs.com', + 'cn-zhangjiakou' => 'resourcesharing.cn-zhangjiakou.aliyuncs.com', + 'cn-hangzhou' => 'resourcesharing.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'resourcesharing.cn-shanghai.aliyuncs.com', + 'ap-southeast-1' => 'resourcesharing.ap-southeast-1.aliyuncs.com', + 'cn-north-2-gov-1' => 'resourcesharing.cn-north-2-gov-1.aliyuncs.com', + ], + 'uisplus' => + [ + 'cn-huhehaote' => 'uisplus.cn-huhehaote.aliyuncs.com', + 'cn-shenzhen' => 'uisplus.cn-shenzhen.aliyuncs.com', + ], + 'idrsservice' => + [ + 'cn-hangzhou' => 'idrsservice.cn-hangzhou.aliyuncs.com', + ], + 'alinlp' => + [ + 'cn-hangzhou' => 'alinlp.cn-hangzhou.aliyuncs.com', + ], + 'miniapplcdp' => + [ + 'cn-hangzhou' => 'miniapplcdp.aliyuncs.com', + 'cn-shanghai' => 'miniapplcdp.aliyuncs.com', + ], + 'baasdis' => + [ + 'cn-hangzhou' => 'baasdis.cn-hangzhou.aliyuncs.com', + ], + 'baasodats' => + [ + 'cn-hangzhou' => 'baasodats.cn-hangzhou.aliyuncs.com', + ], + 'baascccs' => + [ + 'cn-hangzhou' => 'baascccs.cn-hangzhou.aliyuncs.com', + ], + 'pam' => + [ + 'cn-hangzhou' => 'pam.cn-hangzhou.aliyuncs.com', + ], + 'alimtec' => + [ + 'cn-hangzhou' => 'mt.cn-hangzhou.aliyuncs.com', + ], + 'cloudgame' => + [ + 'cn-hangzhou' => 'cloudgame.cn-hangzhou.aliyuncs.com', + 'cn-shanghai' => 'cloudgame.cn-shanghai.aliyuncs.com', + ], + 'csas' => + [ + 'cn-hangzhou' => 'csas.aliyuncs.com', + ], + 'facebodyqps' => + [ + 'cn-shanghai' => 'facebody.cn-shanghai.aliyuncs.com', + ], + 'face' => + [ + 'cn-shanghai' => 'face.cn-shanghai.aliyuncs.com', + ], + 'cams' => + [ + 'ap-southeast-1' => 'cams.ap-southeast-1.aliyuncs.com', + ], + 'mpaasfin' => + [ + 'cn-hangzhou-finance' => 'mpaas.cn-hangzhou-finance.aliyuncs.com', + ], + 'mpaasgov' => + [ + 'cn-north-2-gov-1' => 'mpaas.cn-north-2-gov-1.aliyuncs.com', + ], + ], +]; diff --git a/vendor/alibabacloud/client/src/Credentials/AccessKeyCredential.php b/vendor/alibabacloud/client/src/Credentials/AccessKeyCredential.php new file mode 100644 index 0000000..bacaecc --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/AccessKeyCredential.php @@ -0,0 +1,65 @@ +accessKeyId = $accessKeyId; + $this->accessKeySecret = $accessKeySecret; + } + + /** + * @return string + */ + public function getAccessKeyId() + { + return $this->accessKeyId; + } + + /** + * @return string + */ + public function getAccessKeySecret() + { + return $this->accessKeySecret; + } + + /** + * @return string + */ + public function __toString() + { + return "$this->accessKeyId#$this->accessKeySecret"; + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/BearerTokenCredential.php b/vendor/alibabacloud/client/src/Credentials/BearerTokenCredential.php new file mode 100644 index 0000000..db69a7c --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/BearerTokenCredential.php @@ -0,0 +1,66 @@ +bearerToken = $bearerToken; + } + + /** + * @return string + */ + public function getBearerToken() + { + return $this->bearerToken; + } + + /** + * @return string + */ + public function getAccessKeyId() + { + return ''; + } + + /** + * @return string + */ + public function getAccessKeySecret() + { + return ''; + } + + /** + * @return string + */ + public function __toString() + { + return "bearerToken#$this->bearerToken"; + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/CredentialsInterface.php b/vendor/alibabacloud/client/src/Credentials/CredentialsInterface.php new file mode 100644 index 0000000..96ee50a --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/CredentialsInterface.php @@ -0,0 +1,18 @@ +roleName = $roleName; + } + + /** + * @return string + */ + public function getRoleName() + { + return $this->roleName; + } + + /** + * @return string + */ + public function __toString() + { + return "roleName#$this->roleName"; + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Ini/CreateTrait.php b/vendor/alibabacloud/client/src/Credentials/Ini/CreateTrait.php new file mode 100644 index 0000000..2ec7511 --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Ini/CreateTrait.php @@ -0,0 +1,181 @@ +missingRequired('type', $clientName); + } + + return $this->createClientByType($clientName, $credential)->name($clientName); + } + + /** + * @param string $clientName + * @param array $credential + * + * @return AccessKeyClient|BearerTokenClient|EcsRamRoleClient|RamRoleArnClient|RsaKeyPairClient + * @throws ClientException + */ + private function createClientByType($clientName, array $credential) + { + switch (\strtolower($credential['type'])) { + case 'access_key': + return $this->accessKeyClient($clientName, $credential); + case 'ecs_ram_role': + return $this->ecsRamRoleClient($clientName, $credential); + case 'ram_role_arn': + return $this->ramRoleArnClient($clientName, $credential); + case 'bearer_token': + return $this->bearerTokenClient($clientName, $credential); + case 'rsa_key_pair': + return $this->rsaKeyPairClient($clientName, $credential); + default: + throw new ClientException( + "Invalid type '{$credential['type']}' for '$clientName' in {$this->filename}", + SDK::INVALID_CREDENTIAL + ); + } + } + + /** + * @param array $credential + * @param string $clientName + * + * @return AccessKeyClient + * @throws ClientException + */ + private function accessKeyClient($clientName, array $credential) + { + if (!isset($credential['access_key_id'])) { + $this->missingRequired('access_key_id', $clientName); + } + + if (!isset($credential['access_key_secret'])) { + $this->missingRequired('access_key_secret', $clientName); + } + + return new AccessKeyClient( + $credential['access_key_id'], + $credential['access_key_secret'] + ); + } + + /** + * @param string $clientName + * @param array $credential + * + * @return EcsRamRoleClient + * @throws ClientException + */ + private function ecsRamRoleClient($clientName, array $credential) + { + if (!isset($credential['role_name'])) { + $this->missingRequired('role_name', $clientName); + } + + return new EcsRamRoleClient($credential['role_name']); + } + + /** + * @param string $clientName + * @param array $credential + * + * @return RamRoleArnClient + * @throws ClientException + */ + private function ramRoleArnClient($clientName, array $credential) + { + if (!isset($credential['access_key_id'])) { + $this->missingRequired('access_key_id', $clientName); + } + + if (!isset($credential['access_key_secret'])) { + $this->missingRequired('access_key_secret', $clientName); + } + + if (!isset($credential['role_arn'])) { + $this->missingRequired('role_arn', $clientName); + } + + if (!isset($credential['role_session_name'])) { + $this->missingRequired('role_session_name', $clientName); + } + + return new RamRoleArnClient( + $credential['access_key_id'], + $credential['access_key_secret'], + $credential['role_arn'], + $credential['role_session_name'] + ); + } + + /** + * @param string $clientName + * @param array $credential + * + * @return BearerTokenClient + * @throws ClientException + */ + private function bearerTokenClient($clientName, array $credential) + { + if (!isset($credential['bearer_token'])) { + $this->missingRequired('bearer_token', $clientName); + } + + return new BearerTokenClient($credential['bearer_token']); + } + + /** + * @param array $credential + * @param string $clientName + * + * @return RsaKeyPairClient + * @throws ClientException + */ + private function rsaKeyPairClient($clientName, array $credential) + { + if (!isset($credential['public_key_id'])) { + $this->missingRequired('public_key_id', $clientName); + } + + if (!isset($credential['private_key_file'])) { + $this->missingRequired('private_key_file', $clientName); + } + + return new RsaKeyPairClient( + $credential['public_key_id'], + $credential['private_key_file'] + ); + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Ini/IniCredential.php b/vendor/alibabacloud/client/src/Credentials/Ini/IniCredential.php new file mode 100644 index 0000000..94ec7fb --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Ini/IniCredential.php @@ -0,0 +1,209 @@ +filename = $filename ?: $this->getDefaultFile(); + } + + /** + * Get the default credential file. + * + * @return string + */ + public function getDefaultFile() + { + return self::getHomeDirectory() . DIRECTORY_SEPARATOR . '.alibabacloud' . DIRECTORY_SEPARATOR . 'credentials'; + } + + /** + * Gets the environment's HOME directory. + * + * @return null|string + */ + private static function getHomeDirectory() + { + if (getenv('HOME')) { + return getenv('HOME'); + } + + return (getenv('HOMEDRIVE') && getenv('HOMEPATH')) + ? getenv('HOMEDRIVE') . getenv('HOMEPATH') + : null; + } + + /** + * Clear credential cache. + * + * @return void + */ + public static function forgetLoadedCredentialsFile() + { + self::$hasLoaded = []; + } + + /** + * Get the credential file. + * + * @return string + */ + public function getFilename() + { + return $this->filename; + } + + /** + * @param array $array + * @param string $key + * + * @return bool + */ + protected static function isNotEmpty(array $array, $key) + { + return isset($array[$key]) && !empty($array[$key]); + } + + /** + * @param string $key + * @param string $clientName + * + * @throws ClientException + */ + public function missingRequired($key, $clientName) + { + throw new ClientException( + "Missing required '$key' option for '$clientName' in " . $this->getFilename(), + SDK::INVALID_CREDENTIAL + ); + } + + /** + * @return array|mixed + * @throws ClientException + */ + public function load() + { + // If it has been loaded, assign the client directly. + if (isset(self::$hasLoaded[$this->filename])) { + /** + * @var $client Client + */ + foreach (self::$hasLoaded[$this->filename] as $projectName => $client) { + $client->name($projectName); + } + + return self::$hasLoaded[$this->filename]; + } + + return $this->loadFile(); + } + + /** + * Exceptions will be thrown if the file is unreadable and not the default file. + * + * @return array|mixed + * @throws ClientException + */ + private function loadFile() + { + if (!\AlibabaCloud\Client\inOpenBasedir($this->filename)) { + return []; + } + + if (!\is_readable($this->filename) || !\is_file($this->filename)) { + if ($this->filename === $this->getDefaultFile()) { + // @codeCoverageIgnoreStart + return []; + // @codeCoverageIgnoreEnd + } + throw new ClientException( + 'Credential file is not readable: ' . $this->getFilename(), + SDK::INVALID_CREDENTIAL + ); + } + + return $this->parseFile(); + } + + /** + * Decode the ini file into an array. + * + * @return array|mixed + * @throws ClientException + */ + private function parseFile() + { + try { + $file = \parse_ini_file($this->filename, true); + if (\is_array($file) && $file !== []) { + return $this->initClients($file); + } + throw new ClientException( + 'Format error: ' . $this->getFilename(), + SDK::INVALID_CREDENTIAL + ); + } catch (\Exception $e) { + throw new ClientException( + $e->getMessage(), + SDK::INVALID_CREDENTIAL, + $e + ); + } + } + + /** + * Initialize clients. + * + * @param array $array + * + * @return array|mixed + * @throws ClientException + */ + private function initClients($array) + { + foreach (\array_change_key_case($array) as $clientName => $configures) { + $configures = \array_change_key_case($configures); + $clientInstance = $this->createClient($clientName, $configures); + if ($clientInstance instanceof Client) { + self::$hasLoaded[$this->filename][$clientName] = $clientInstance; + self::setClientAttributes($configures, $clientInstance); + self::setCert($configures, $clientInstance); + self::setProxy($configures, $clientInstance); + } + } + + return isset(self::$hasLoaded[$this->filename]) + ? self::$hasLoaded[$this->filename] + : []; + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Ini/OptionsTrait.php b/vendor/alibabacloud/client/src/Credentials/Ini/OptionsTrait.php new file mode 100644 index 0000000..192d494 --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Ini/OptionsTrait.php @@ -0,0 +1,111 @@ +regionId($configures['region_id']); + } + + if (isset($configures['debug'])) { + $client->options( + [ + 'debug' => (bool)$configures['debug'], + ] + ); + } + + if (self::isNotEmpty($configures, 'timeout')) { + $client->options( + [ + 'timeout' => $configures['timeout'], + ] + ); + } + + if (self::isNotEmpty($configures, 'connect_timeout')) { + $client->options( + [ + 'connect_timeout' => $configures['connect_timeout'], + ] + ); + } + } + + /** + * @param array $configures + * @param Client $client + */ + private static function setProxy($configures, Client $client) + { + if (self::isNotEmpty($configures, 'proxy')) { + $client->options( + [ + 'proxy' => $configures['proxy'], + ] + ); + } + $proxy = []; + if (self::isNotEmpty($configures, 'proxy_http')) { + $proxy['http'] = $configures['proxy_http']; + } + if (self::isNotEmpty($configures, 'proxy_https')) { + $proxy['https'] = $configures['proxy_https']; + } + if (self::isNotEmpty($configures, 'proxy_no')) { + $proxy['no'] = \explode(',', $configures['proxy_no']); + } + if ($proxy !== []) { + $client->options( + [ + 'proxy' => $proxy, + ] + ); + } + } + + /** + * @param array $configures + * @param Client $client + */ + private static function setCert($configures, Client $client) + { + if (self::isNotEmpty($configures, 'cert_file') && !self::isNotEmpty($configures, 'cert_password')) { + $client->options( + [ + 'cert' => $configures['cert_file'], + ] + ); + } + + if (self::isNotEmpty($configures, 'cert_file') && self::isNotEmpty($configures, 'cert_password')) { + $client->options( + [ + 'cert' => [ + $configures['cert_file'], + $configures['cert_password'], + ], + ] + ); + } + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Providers/CredentialsProvider.php b/vendor/alibabacloud/client/src/Credentials/Providers/CredentialsProvider.php new file mode 100644 index 0000000..21aec9b --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Providers/CredentialsProvider.php @@ -0,0 +1,170 @@ +asDefaultClient(); + } + }; + } + + /** + * @return Closure + */ + public static function ini() + { + return static function () { + $ini = \AlibabaCloud\Client\envNotEmpty('ALIBABA_CLOUD_CREDENTIALS_FILE'); + + if ($ini) { + AlibabaCloud::load($ini); + } else { + // @codeCoverageIgnoreStart + AlibabaCloud::load(); + // @codeCoverageIgnoreEnd + } + + self::compatibleWithGlobal(); + }; + } + + /** + * @codeCoverageIgnore + * + * Compatible with global + * + * @throws ClientException + */ + private static function compatibleWithGlobal() + { + if (AlibabaCloud::has('global') && !AlibabaCloud::has(self::getDefaultName())) { + AlibabaCloud::get('global')->name(self::getDefaultName()); + } + } + + /** + * @return array|false|string + * @throws ClientException + */ + public static function getDefaultName() + { + $name = \AlibabaCloud\Client\envNotEmpty('ALIBABA_CLOUD_PROFILE'); + + if ($name) { + return $name; + } + + return 'default'; + } + + /** + * @return Closure + */ + public static function instance() + { + return static function () { + $instance = \AlibabaCloud\Client\envNotEmpty('ALIBABA_CLOUD_ECS_METADATA'); + if ($instance) { + AlibabaCloud::ecsRamRoleClient($instance)->asDefaultClient(); + } + }; + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Providers/EcsRamRoleProvider.php b/vendor/alibabacloud/client/src/Credentials/Providers/EcsRamRoleProvider.php new file mode 100644 index 0000000..0515ca6 --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Providers/EcsRamRoleProvider.php @@ -0,0 +1,128 @@ +getCredentialsInCache(); + + if ($result === null) { + $result = $this->request(); + + if (!isset($result['AccessKeyId'], $result['AccessKeySecret'], $result['SecurityToken'])) { + throw new ServerException($result, $this->error, SDK::INVALID_CREDENTIAL); + } + + $this->cache($result->toArray()); + } + + return new StsCredential( + $result['AccessKeyId'], + $result['AccessKeySecret'], + $result['SecurityToken'] + ); + } + + /** + * Get credentials by request. + * + * @return Result + * @throws ClientException + * @throws ServerException + */ + public function request() + { + $result = $this->getResponse(); + + if ($result->getStatusCode() === 404) { + $message = 'The role was not found in the instance'; + throw new ClientException($message, SDK::INVALID_CREDENTIAL); + } + + if (!$result->isSuccess()) { + $message = 'Error retrieving credentials from result'; + throw new ServerException($result, $message, SDK::INVALID_CREDENTIAL); + } + + return $result; + } + + /** + * Get data from meta. + * + * @return mixed|ResponseInterface + * @throws ClientException + * @throws Exception + */ + public function getResponse() + { + /** + * @var EcsRamRoleCredential $credential + */ + $credential = $this->client->getCredential(); + $url = $this->uri . $credential->getRoleName(); + + $options = [ + 'http_errors' => false, + 'timeout' => 1, + 'connect_timeout' => 1, + 'debug' => $this->client->isDebug(), + ]; + + try { + return RpcRequest::createClient()->request('GET', $url, $options); + } catch (GuzzleException $exception) { + if (Stringy::contains($exception->getMessage(), 'timed')) { + $message = 'Timeout or instance does not belong to Alibaba Cloud'; + } else { + $message = $exception->getMessage(); + } + + throw new ClientException( + $message, + SDK::SERVER_UNREACHABLE, + $exception + ); + } + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Providers/Provider.php b/vendor/alibabacloud/client/src/Credentials/Providers/Provider.php new file mode 100644 index 0000000..b64dab8 --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Providers/Provider.php @@ -0,0 +1,88 @@ +client = $client; + } + + /** + * Get the credentials from the cache in the validity period. + * + * @return array|null + */ + public function getCredentialsInCache() + { + if (isset(self::$credentialsCache[$this->key()])) { + $result = self::$credentialsCache[$this->key()]; + if (\strtotime($result['Expiration']) - \time() >= $this->expirationSlot) { + return $result; + } + unset(self::$credentialsCache[$this->key()]); + } + + return null; + } + + /** + * Get the toString of the credentials as the key. + * + * @return string + */ + protected function key() + { + return (string)$this->client->getCredential(); + } + + /** + * Cache credentials. + * + * @param array $credential + */ + protected function cache(array $credential) + { + self::$credentialsCache[$this->key()] = $credential; + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Providers/RamRoleArnProvider.php b/vendor/alibabacloud/client/src/Credentials/Providers/RamRoleArnProvider.php new file mode 100644 index 0000000..ce4de41 --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Providers/RamRoleArnProvider.php @@ -0,0 +1,84 @@ +getCredentialsInCache(); + + if (null === $credential) { + $result = $this->request($timeout, $connectTimeout); + + if (!isset($result['Credentials']['AccessKeyId'], + $result['Credentials']['AccessKeySecret'], + $result['Credentials']['SecurityToken'])) { + throw new ServerException($result, $this->error, SDK::INVALID_CREDENTIAL); + } + + $credential = $result['Credentials']; + $this->cache($credential); + } + + return new StsCredential( + $credential['AccessKeyId'], + $credential['AccessKeySecret'], + $credential['SecurityToken'] + ); + } + + /** + * Get credentials by request. + * + * @param $timeout + * @param $connectTimeout + * + * @return Result + * @throws ClientException + * @throws ServerException + */ + private function request($timeout, $connectTimeout) + { + $clientName = __CLASS__ . \uniqid('ak', true); + $credential = $this->client->getCredential(); + + AlibabaCloud::accessKeyClient( + $credential->getAccessKeyId(), + $credential->getAccessKeySecret() + )->name($clientName); + + return (new AssumeRole($credential)) + ->client($clientName) + ->timeout($timeout) + ->connectTimeout($connectTimeout) + ->debug($this->client->isDebug()) + ->request(); + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Providers/RsaKeyPairProvider.php b/vendor/alibabacloud/client/src/Credentials/Providers/RsaKeyPairProvider.php new file mode 100644 index 0000000..e78fc1c --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Providers/RsaKeyPairProvider.php @@ -0,0 +1,86 @@ +getCredentialsInCache(); + + if ($credential === null) { + $result = $this->request($timeout, $connectTimeout); + + if (!isset($result['SessionAccessKey']['SessionAccessKeyId'], + $result['SessionAccessKey']['SessionAccessKeySecret'])) { + throw new ServerException($result, $this->error, SDK::INVALID_CREDENTIAL); + } + + $credential = $result['SessionAccessKey']; + $this->cache($credential); + } + + return new StsCredential( + $credential['SessionAccessKeyId'], + $credential['SessionAccessKeySecret'] + ); + } + + /** + * Get credentials by request. + * + * @param $timeout + * @param $connectTimeout + * + * @return Result + * @throws ClientException + * @throws ServerException + */ + private function request($timeout, $connectTimeout) + { + $clientName = __CLASS__ . \uniqid('rsa', true); + $credential = $this->client->getCredential(); + + AlibabaCloud::client( + new AccessKeyCredential( + $credential->getPublicKeyId(), + $credential->getPrivateKey() + ), + new ShaHmac256WithRsaSignature() + )->name($clientName); + + return (new GenerateSessionAccessKey($credential->getPublicKeyId())) + ->client($clientName) + ->timeout($timeout) + ->connectTimeout($connectTimeout) + ->debug($this->client->isDebug()) + ->request(); + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/RamRoleArnCredential.php b/vendor/alibabacloud/client/src/Credentials/RamRoleArnCredential.php new file mode 100644 index 0000000..6bdf5be --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/RamRoleArnCredential.php @@ -0,0 +1,110 @@ +accessKeyId = $accessKeyId; + $this->accessKeySecret = $accessKeySecret; + $this->roleArn = $roleArn; + $this->roleSessionName = $roleSessionName; + $this->policy = $policy; + } + + /** + * @return string + */ + public function getAccessKeyId() + { + return $this->accessKeyId; + } + + /** + * @return string + */ + public function getAccessKeySecret() + { + return $this->accessKeySecret; + } + + /** + * @return string + */ + public function getRoleArn() + { + return $this->roleArn; + } + + /** + * @return string + */ + public function getRoleSessionName() + { + return $this->roleSessionName; + } + + /** + * @return string + */ + public function getPolicy() + { + return $this->policy; + } + + /** + * @return string + */ + public function __toString() + { + return "$this->accessKeyId#$this->accessKeySecret#$this->roleArn#$this->roleSessionName"; + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Requests/AssumeRole.php b/vendor/alibabacloud/client/src/Credentials/Requests/AssumeRole.php new file mode 100644 index 0000000..a3935aa --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Requests/AssumeRole.php @@ -0,0 +1,47 @@ +product('Sts'); + $this->version('2015-04-01'); + $this->action('AssumeRole'); + $this->host('sts.aliyuncs.com'); + $this->scheme('https'); + $this->regionId('cn-hangzhou'); + $this->options['verify'] = false; + $this->options['query']['RoleArn'] = $arnCredential->getRoleArn(); + $this->options['query']['RoleSessionName'] = $arnCredential->getRoleSessionName(); + $this->options['query']['DurationSeconds'] = Provider::DURATION_SECONDS; + if ($arnCredential->getPolicy()) { + if (is_array($arnCredential->getPolicy())) { + $this->options['query']['Policy'] = json_encode($arnCredential->getPolicy()); + } + if (is_string($arnCredential->getPolicy())) { + $this->options['query']['Policy'] = $arnCredential->getPolicy(); + } + } + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/Requests/GenerateSessionAccessKey.php b/vendor/alibabacloud/client/src/Credentials/Requests/GenerateSessionAccessKey.php new file mode 100644 index 0000000..4ac1ee1 --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/Requests/GenerateSessionAccessKey.php @@ -0,0 +1,37 @@ +product('Sts'); + $this->version('2015-04-01'); + $this->action('GenerateSessionAccessKey'); + $this->host('sts.ap-northeast-1.aliyuncs.com'); + $this->scheme('https'); + $this->regionId('cn-hangzhou'); + $this->options['verify'] = false; + $this->options['query']['PublicKeyId'] = $publicKeyId; + $this->options['query']['DurationSeconds'] = Provider::DURATION_SECONDS; + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/RsaKeyPairCredential.php b/vendor/alibabacloud/client/src/Credentials/RsaKeyPairCredential.php new file mode 100644 index 0000000..876909e --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/RsaKeyPairCredential.php @@ -0,0 +1,75 @@ +publicKeyId = $publicKeyId; + try { + $this->privateKey = file_get_contents($privateKeyFile); + } catch (Exception $exception) { + throw new ClientException( + $exception->getMessage(), + SDK::INVALID_CREDENTIAL + ); + } + } + + /** + * @return mixed + */ + public function getPrivateKey() + { + return $this->privateKey; + } + + /** + * @return string + */ + public function getPublicKeyId() + { + return $this->publicKeyId; + } + + /** + * @return string + */ + public function __toString() + { + return "publicKeyId#$this->publicKeyId"; + } +} diff --git a/vendor/alibabacloud/client/src/Credentials/StsCredential.php b/vendor/alibabacloud/client/src/Credentials/StsCredential.php new file mode 100644 index 0000000..d333fa8 --- /dev/null +++ b/vendor/alibabacloud/client/src/Credentials/StsCredential.php @@ -0,0 +1,80 @@ +accessKeyId = $accessKeyId; + $this->accessKeySecret = $accessKeySecret; + $this->securityToken = $securityToken; + } + + /** + * @return string + */ + public function getAccessKeyId() + { + return $this->accessKeyId; + } + + /** + * @return string + */ + public function getAccessKeySecret() + { + return $this->accessKeySecret; + } + + /** + * @return string + */ + public function getSecurityToken() + { + return $this->securityToken; + } + + /** + * @return string + */ + public function __toString() + { + return "$this->accessKeyId#$this->accessKeySecret#$this->securityToken"; + } +} diff --git a/vendor/alibabacloud/client/src/DefaultAcsClient.php b/vendor/alibabacloud/client/src/DefaultAcsClient.php new file mode 100644 index 0000000..ff5ecd7 --- /dev/null +++ b/vendor/alibabacloud/client/src/DefaultAcsClient.php @@ -0,0 +1,55 @@ +randClientName = \uniqid('', true); + $client->name($this->randClientName); + } + + /** + * @param Request|Result $request + * + * @return Result|string + * @throws ClientException + * @throws ServerException + */ + public function getAcsResponse($request) + { + if ($request instanceof Result) { + return $request; + } + + return $request->client($this->randClientName)->request(); + } +} diff --git a/vendor/alibabacloud/client/src/Encode.php b/vendor/alibabacloud/client/src/Encode.php new file mode 100644 index 0000000..203ceb4 --- /dev/null +++ b/vendor/alibabacloud/client/src/Encode.php @@ -0,0 +1,68 @@ +data = $data; + } + + /** + * @return bool|string + */ + public function toString() + { + $string = ''; + foreach ($this->data as $key => $value) { + $encode = rawurlencode($value); + if ($encode === '') { + $string .= "$key&"; + } else { + $string .= "$key=$encode&"; + } + } + + if (0 < count($this->data)) { + $string = substr($string, 0, -1); + } + + return $string; + } + + /** + * @return $this + */ + public function ksort() + { + ksort($this->data); + + return $this; + } +} diff --git a/vendor/alibabacloud/client/src/Exception/AlibabaCloudException.php b/vendor/alibabacloud/client/src/Exception/AlibabaCloudException.php new file mode 100644 index 0000000..cee21d8 --- /dev/null +++ b/vendor/alibabacloud/client/src/Exception/AlibabaCloudException.php @@ -0,0 +1,70 @@ +errorCode; + } + + /** + * @codeCoverageIgnore + * @deprecated + */ + public function setErrorCode() + { + throw new RuntimeException('deprecated since 2.0.'); + } + + /** + * @return string + */ + public function getErrorMessage() + { + return $this->errorMessage; + } + + /** + * @codeCoverageIgnore + * + * @param $errorMessage + * + * @deprecated + */ + public function setErrorMessage($errorMessage) + { + $this->errorMessage = $errorMessage; + } + + /** + * @codeCoverageIgnore + * @deprecated + */ + public function setErrorType() + { + } +} diff --git a/vendor/alibabacloud/client/src/Exception/ClientException.php b/vendor/alibabacloud/client/src/Exception/ClientException.php new file mode 100644 index 0000000..0877e87 --- /dev/null +++ b/vendor/alibabacloud/client/src/Exception/ClientException.php @@ -0,0 +1,38 @@ +errorMessage = $errorMessage; + $this->errorCode = $errorCode; + } + + /** + * @codeCoverageIgnore + * @deprecated + */ + public function getErrorType() + { + return 'Client'; + } +} diff --git a/vendor/alibabacloud/client/src/Exception/ServerException.php b/vendor/alibabacloud/client/src/Exception/ServerException.php new file mode 100644 index 0000000..4be26e8 --- /dev/null +++ b/vendor/alibabacloud/client/src/Exception/ServerException.php @@ -0,0 +1,158 @@ +result = $result; + $this->errorMessage = $errorMessage; + $this->errorCode = $errorCode; + $this->resolvePropertiesByReturn(); + $this->distinguishSignatureErrors(); + $this->bodyAsErrorMessage(); + + parent::__construct( + $this->getMessageString(), + $this->result->getStatusCode() + ); + } + + /** + * Resolve the error message based on the return of the server. + * + * @return void + */ + private function resolvePropertiesByReturn() + { + if (isset($this->result['message'])) { + $this->errorMessage = $this->result['message']; + $this->errorCode = $this->result['code']; + } + if (isset($this->result['Message'])) { + $this->errorMessage = $this->result['Message']; + $this->errorCode = $this->result['Code']; + } + if (isset($this->result['errorMsg'])) { + $this->errorMessage = $this->result['errorMsg']; + $this->errorCode = $this->result['errorCode']; + } + if (isset($this->result['requestId'])) { + $this->requestId = $this->result['requestId']; + } + if (isset($this->result['RequestId'])) { + $this->requestId = $this->result['RequestId']; + } + } + + /** + * If the string to be signed are the same with server's, it is considered a credential error. + */ + private function distinguishSignatureErrors() + { + if ($this->result->getRequest() + && Stringy::contains($this->errorMessage, $this->result->getRequest()->stringToSign())) { + $this->errorCode = 'InvalidAccessKeySecret'; + $this->errorMessage = 'Specified Access Key Secret is not valid.'; + } + } + + /** + * If the error message matches the default message and + * the server has returned content, use the return content + */ + private function bodyAsErrorMessage() + { + $body = (string)$this->result->getBody(); + if ($this->errorMessage === SDK::RESPONSE_EMPTY && $body) { + $this->errorMessage = $body; + } + } + + /** + * Get standard exception message. + * + * @return string + */ + private function getMessageString() + { + $message = "$this->errorCode: $this->errorMessage RequestId: $this->requestId"; + + if ($this->getResult()->getRequest()) { + $method = $this->getResult()->getRequest()->method; + $uri = (string)$this->getResult()->getRequest()->uri; + $message .= " $method \"$uri\""; + if ($this->result) { + $message .= ' ' . $this->result->getStatusCode(); + } + } + + return $message; + } + + /** + * @return Result + */ + public function getResult() + { + return $this->result; + } + + /** + * @return string + */ + public function getRequestId() + { + return $this->requestId; + } + + /** + * @codeCoverageIgnore + * @deprecated + */ + public function getErrorType() + { + return 'Server'; + } + + /** + * @codeCoverageIgnore + * @deprecated + */ + public function getHttpStatus() + { + return $this->getResult()->getStatusCode(); + } +} diff --git a/vendor/alibabacloud/client/src/Filter/ApiFilter.php b/vendor/alibabacloud/client/src/Filter/ApiFilter.php new file mode 100644 index 0000000..f6d26f2 --- /dev/null +++ b/vendor/alibabacloud/client/src/Filter/ApiFilter.php @@ -0,0 +1,259 @@ +br(); + if ($flank !== null) { + cliMate()->backgroundRed()->flank($flank, $char, $length); + cliMate()->br(); + } + cliMate()->backgroundRed($string); + cliMate()->br(); +} + +/** + * @param string $string + * @param string|null $flank + * @param string|null $char + * @param int|null $length + * + * @return void + */ +function backgroundGreen($string, $flank = null, $char = null, $length = null) +{ + cliMate()->br(); + if ($flank !== null) { + cliMate()->backgroundGreen()->flank($flank, $char, $length); + } + cliMate()->backgroundGreen($string); + cliMate()->br(); +} + +/** + * @param string $string + * @param string|null $flank + * @param string|null $char + * @param int|null $length + * + * @return void + */ +function backgroundBlue($string, $flank = null, $char = null, $length = null) +{ + cliMate()->br(); + if ($flank !== null) { + cliMate()->backgroundBlue()->flank($flank, $char, $length); + } + cliMate()->backgroundBlue($string); + cliMate()->br(); +} + +/** + * @param string $string + * @param string|null $flank + * @param string|null $char + * @param int|null $length + * + * @return void + */ +function backgroundMagenta($string, $flank = null, $char = null, $length = null) +{ + cliMate()->br(); + if ($flank !== null) { + cliMate()->backgroundMagenta()->flank($flank, $char, $length); + } + cliMate()->backgroundMagenta($string); + cliMate()->br(); +} + +/** + * @param array $array + */ +function json(array $array) +{ + cliMate()->br(); + cliMate()->backgroundGreen()->json($array); + cliMate()->br(); +} + +/** + * @param array $array + * + * @return void + */ +function redTable($array) +{ + /** + * @noinspection PhpUndefinedMethodInspection + */ + cliMate()->redTable($array); +} + +/** + * @param mixed $result + * @param string $title + * + * @return void + */ +function block($result, $title) +{ + cliMate()->backgroundGreen()->flank($title, '--', 20); + dump($result); +} + +/** + * Gets the value of an environment variable. + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ +function env($key, $default = null) +{ + $value = getenv($key); + + if ($value === false) { + return value($default); + } + + if (envSubstr($value)) { + return substr($value, 1, -1); + } + + return envConversion($value); +} + +/** + * @param $value + * + * @return bool|string|null + */ +function envConversion($value) +{ + $key = strtolower($value); + + if ($key === 'null' || $key === '(null)') { + return null; + } + + $list = [ + 'true' => true, + '(true)' => true, + 'false' => false, + '(false)' => false, + 'empty' => '', + '(empty)' => '', + ]; + + return isset($list[$key]) ? $list[$key] : $value; +} + +/** + * @param $key + * + * @return bool|mixed + * @throws ClientException + */ +function envNotEmpty($key) +{ + $value = env($key, false); + if ($value !== false && !$value) { + throw new ClientException( + "Environment variable '$key' cannot be empty", + SDK::INVALID_ARGUMENT + ); + } + if ($value) { + return $value; + } + + return false; +} + +/** + * @param $value + * + * @return bool + */ +function envSubstr($value) +{ + return ($valueLength = strlen($value)) > 1 && strpos($value, '"') === 0 && $value[$valueLength - 1] === '"'; +} + +/** + * Return the default value of the given value. + * + * @param mixed $value + * + * @return mixed + */ +function value($value) +{ + return $value instanceof Closure ? $value() : $value; +} diff --git a/vendor/alibabacloud/client/src/Log/LogFormatter.php b/vendor/alibabacloud/client/src/Log/LogFormatter.php new file mode 100644 index 0000000..a33185b --- /dev/null +++ b/vendor/alibabacloud/client/src/Log/LogFormatter.php @@ -0,0 +1,79 @@ +template = $template; + $timezone = new DateTimeZone(date_default_timezone_get() ?: 'UTC'); + if (PHP_VERSION_ID < 70100) { + self::$ts = DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), $timezone); + } else { + self::$ts = new DateTime('now', $timezone); + } + } + + /** + * Returns a formatted message string. + * + * @param RequestInterface $request Request that was sent + * @param ResponseInterface $response Response that was received + * @param Exception $error Exception that was received + * + * @return string + */ + public function format( + RequestInterface $request, + ResponseInterface $response = null, + Exception $error = null + ) { + $this->template = str_replace('{pid}', getmypid(), $this->template); + $this->template = str_replace('{cost}', self::getCost(), $this->template); + $this->template = str_replace('{start_time}', self::$ts->format('Y-m-d H:i:s.u'), $this->template); + + return (new MessageFormatter($this->template))->format($request, $response, $error); + } + + /** + * @return float|mixed + */ + private static function getCost() + { + return microtime(true) - self::$logStartTime; + } +} diff --git a/vendor/alibabacloud/client/src/Profile/DefaultProfile.php b/vendor/alibabacloud/client/src/Profile/DefaultProfile.php new file mode 100644 index 0000000..b1b3707 --- /dev/null +++ b/vendor/alibabacloud/client/src/Profile/DefaultProfile.php @@ -0,0 +1,74 @@ +regionId($regionId); + } + + /** + * @param string $regionId + * @param string $accessKeyId + * @param string $accessKeySecret + * @param string $roleArn + * @param string $roleSessionName + * + * @return Client + * @throws ClientException + */ + public static function getRamRoleArnProfile($regionId, $accessKeyId, $accessKeySecret, $roleArn, $roleSessionName) + { + return AlibabaCloud::ramRoleArnClient($accessKeyId, $accessKeySecret, $roleArn, $roleSessionName) + ->regionId($regionId); + } + + /** + * @param string $regionId + * @param string $roleName + * + * @return Client + * @throws ClientException + */ + public static function getEcsRamRoleProfile($regionId, $roleName) + { + return AlibabaCloud::ecsRamRoleClient($roleName) + ->regionId($regionId); + } + + /** + * @param string $regionId + * @param string $bearerToken + * + * @return Client + * @throws ClientException + */ + public static function getBearerTokenProfile($regionId, $bearerToken) + { + return AlibabaCloud::bearerTokenClient($bearerToken) + ->regionId($regionId); + } +} diff --git a/vendor/alibabacloud/client/src/Regions/EndpointProvider.php b/vendor/alibabacloud/client/src/Regions/EndpointProvider.php new file mode 100644 index 0000000..5e8e555 --- /dev/null +++ b/vendor/alibabacloud/client/src/Regions/EndpointProvider.php @@ -0,0 +1,18 @@ +request = $request; + } + + /** + * @param Request $request + * @param string $domain + * + * @return string + * @throws ClientException + * @throws ServerException + * @deprecated + * @codeCoverageIgnore + */ + public static function findProductDomain(Request $request, $domain = 'location.aliyuncs.com') + { + return self::resolveHost($request, $domain); + } + + /** + * @param $regionId + * @param $product + * @param $domain + * + * @throws ClientException + * @deprecated + * @codeCoverageIgnore + */ + public static function addEndPoint($regionId, $product, $domain) + { + self::addHost($product, $domain, $regionId); + } + + + /** + * @param Request $request + * @param string $domain + * + * @return string + * @throws ClientException + * @throws ServerException + */ + public static function resolveHost(Request $request, $domain = 'location.aliyuncs.com') + { + $locationService = new static($request); + $product = $locationService->request->product; + $regionId = $locationService->request->realRegionId(); + + if (!isset(self::$hosts[$product][$regionId])) { + self::$hosts[$product][$regionId] = self::getResult($locationService, $domain); + } + + return self::$hosts[$product][$regionId]; + } + + /** + * @param static $locationService + * @param string $domain + * + * @return string + * @throws ClientException + * @throws ServerException + */ + private static function getResult($locationService, $domain) + { + $locationRequest = new LocationServiceRequest($locationService->request, $domain); + + $result = $locationRequest->request(); + + if (!isset($result['Endpoints']['Endpoint'][0]['Endpoint'])) { + throw new ClientException( + 'Not found Region ID in ' . $domain, + SDK::INVALID_REGION_ID + ); + } + + return $result['Endpoints']['Endpoint'][0]['Endpoint']; + } + + /** + * @param string $product + * @param string $host + * @param string $regionId + * + * @throws ClientException + */ + public static function addHost($product, $host, $regionId = self::GLOBAL_REGION) + { + ApiFilter::product($product); + + HttpFilter::host($host); + + ClientFilter::regionId($regionId); + + self::$hosts[$product][$regionId] = $host; + } + + /** + * Update endpoints from OSS. + * + * @codeCoverageIgnore + * @throws Exception + */ + public static function updateEndpoints() + { + $ossUrl = 'https://openapi-endpoints.oss-cn-hangzhou.aliyuncs.com/endpoints.json'; + $json = \file_get_contents($ossUrl); + $list = \json_decode($json, true); + + foreach ($list['endpoints'] as $endpoint) { + Config::set( + "endpoints.{$endpoint['service']}.{$endpoint['regionid']}", + \strtolower($endpoint['endpoint']) + ); + } + } +} diff --git a/vendor/alibabacloud/client/src/Regions/LocationServiceRequest.php b/vendor/alibabacloud/client/src/Regions/LocationServiceRequest.php new file mode 100644 index 0000000..94a267d --- /dev/null +++ b/vendor/alibabacloud/client/src/Regions/LocationServiceRequest.php @@ -0,0 +1,46 @@ +product('Location'); + $this->version('2015-06-12'); + $this->action('DescribeEndpoints'); + $this->regionId('cn-hangzhou'); + $this->format('JSON'); + $this->options['query']['Id'] = $request->realRegionId(); + $this->options['query']['ServiceCode'] = $request->serviceCode; + $this->options['query']['Type'] = $request->endpointType; + $this->client($request->client); + $this->host($domain); + if (isset($request->options['timeout'])) { + $this->timeout($request->options['timeout']); + } + + if (isset($request->options['connect_timeout'])) { + $this->connectTimeout($request->options['connect_timeout']); + } + } +} diff --git a/vendor/alibabacloud/client/src/Release.php b/vendor/alibabacloud/client/src/Release.php new file mode 100644 index 0000000..0be9c1b --- /dev/null +++ b/vendor/alibabacloud/client/src/Release.php @@ -0,0 +1,112 @@ +getArguments(); + if (count($arguments) <= 1) { + echo 'Missing ChangeLog'; + + return; + } + self::updateChangelogFile($arguments[0], $arguments[1]); + self::changeVersionInCode($arguments[0]); + } + + /** + * @param $version + * @param $changeLog + */ + private static function updateChangelogFile($version, $changeLog) + { + $content = preg_replace( + '/# CHANGELOG/', + '# CHANGELOG' + . "\n" + . "\n" + . "## $version - " . date('Y-m-d') + . self::log($changeLog), + self::getChangeLogContent() + ); + + file_put_contents(self::getChangeLogFile(), $content); + } + + /** + * @param $changeLog + * + * @return string + */ + private static function log($changeLog) + { + $logs = explode('|', $changeLog); + $string = "\n"; + foreach ($logs as $log) { + if ($log) { + $string .= "- $log." . "\n"; + } + } + + return $string; + } + + /** + * @return string + */ + private static function getChangeLogContent() + { + return file_get_contents(self::getChangeLogFile()); + } + + /** + * @return string + */ + private static function getChangeLogFile() + { + return __DIR__ . '/../CHANGELOG.md'; + } + + /** + * @param $version + */ + private static function changeVersionInCode($version) + { + $content = preg_replace( + "/const VERSION = \'(.*)\';/", + "const VERSION = '" . $version . "';", + self::getCodeContent() + ); + + file_put_contents(self::getCodeFile(), $content); + } + + /** + * @return string + */ + private static function getCodeContent() + { + return file_get_contents(self::getCodeFile()); + } + + /** + * @return string + */ + private static function getCodeFile() + { + return __DIR__ . '/AlibabaCloud.php'; + } +} diff --git a/vendor/alibabacloud/client/src/Request/Request.php b/vendor/alibabacloud/client/src/Request/Request.php new file mode 100644 index 0000000..e18532e --- /dev/null +++ b/vendor/alibabacloud/client/src/Request/Request.php @@ -0,0 +1,451 @@ +client = CredentialsProvider::getDefaultName(); + $this->uri = new Uri(); + $this->uri = $this->uri->withScheme($this->scheme); + $this->options['http_errors'] = false; + $this->options['connect_timeout'] = self::CONNECT_TIMEOUT; + $this->options['timeout'] = self::TIMEOUT; + + // Turn on debug mode based on environment variable. + if (null !== \AlibabaCloud\Client\env('DEBUG') && strtolower(\AlibabaCloud\Client\env('DEBUG')) === 'sdk') { + $this->options['debug'] = true; + } + + // Rewrite configuration if the user has a configuration. + if ($options !== []) { + $this->options($options); + } + } + + /** + * @param string $name + * @param string $value + * + * @return $this + * @throws ClientException + */ + public function appendUserAgent($name, $value) + { + $filter_name = Filter::name($name); + + if (!UserAgent::isGuarded($filter_name)) { + $this->userAgent[$filter_name] = Filter::value($value); + } + + return $this; + } + + /** + * @param array $userAgent + * + * @return $this + */ + public function withUserAgent(array $userAgent) + { + $this->userAgent = UserAgent::clean($userAgent); + + return $this; + } + + /** + * Set Accept format. + * + * @param string $format + * + * @return $this + * @throws ClientException + */ + public function format($format) + { + $this->format = ApiFilter::format($format); + + return $this; + } + + /** + * @param $contentType + * + * @return $this + * @throws ClientException + */ + public function contentType($contentType) + { + $this->options['headers']['Content-Type'] = HttpFilter::contentType($contentType); + + return $this; + } + + /** + * @param string $accept + * + * @return $this + * @throws ClientException + */ + public function accept($accept) + { + $this->options['headers']['Accept'] = HttpFilter::accept($accept); + + return $this; + } + + /** + * Set the request body. + * + * @param string $body + * + * @return $this + * @throws ClientException + */ + public function body($body) + { + $this->options['body'] = HttpFilter::body($body); + + return $this; + } + + /** + * Set the json as body. + * + * @param array|object $content + * + * @return $this + * @throws ClientException + */ + public function jsonBody($content) + { + if (!\is_array($content) && !\is_object($content)) { + throw new ClientException( + 'jsonBody only accepts an array or object', + SDK::INVALID_ARGUMENT + ); + } + + return $this->body(\json_encode($content)); + } + + /** + * Set the request scheme. + * + * @param string $scheme + * + * @return $this + * @throws ClientException + */ + public function scheme($scheme) + { + $this->scheme = HttpFilter::scheme($scheme); + $this->uri = $this->uri->withScheme($scheme); + + return $this; + } + + /** + * Set the request host. + * + * @param string $host + * + * @return $this + * @throws ClientException + */ + public function host($host) + { + $this->uri = $this->uri->withHost(HttpFilter::host($host)); + + return $this; + } + + /** + * @param string $method + * + * @return $this + * @throws ClientException + */ + public function method($method) + { + $this->method = HttpFilter::method($method); + + return $this; + } + + /** + * @param string $clientName + * + * @return $this + * @throws ClientException + */ + public function client($clientName) + { + $this->client = ClientFilter::clientName($clientName); + + return $this; + } + + /** + * @return bool + * @throws ClientException + */ + public function isDebug() + { + if (isset($this->options['debug'])) { + return $this->options['debug'] === true; + } + + if (isset($this->httpClient()->options['debug'])) { + return $this->httpClient()->options['debug'] === true; + } + + return false; + } + + /** + * @throws ClientException + * @throws ServerException + */ + public function resolveOption() + { + $this->options['headers']['User-Agent'] = UserAgent::toString($this->userAgent); + + $this->cleanQuery(); + $this->cleanFormParams(); + $this->resolveHost(); + $this->resolveParameter(); + + if (isset($this->options['form_params'])) { + if (function_exists('\GuzzleHttp\Psr7\parse_query')) { + $this->options['form_params'] = \GuzzleHttp\Psr7\parse_query( + Encode::create($this->options['form_params'])->toString() + ); + } else { + $this->options['form_params'] = \GuzzleHttp\Psr7\Query::parse( + Encode::create($this->options['form_params'])->toString() + ); + } + } + + $this->mergeOptionsIntoClient(); + } + + /** + * @return Result + * @throws ClientException + * @throws ServerException + */ + public function request() + { + $this->resolveOption(); + $result = $this->response(); + + if ($this->shouldServerRetry($result)) { + return $this->request(); + } + + if (!$result->isSuccess()) { + throw new ServerException($result); + } + + return $result; + } + + /*** + * @return PromiseInterface + * @throws Exception + */ + public function requestAsync() + { + $this->resolveOption(); + + return self::createClient($this)->requestAsync( + $this->method, + (string)$this->uri, + $this->options + ); + } + + /** + * @param Request $request + * + * @return Client + * @throws Exception + */ + public static function createClient(Request $request = null) + { + if (AlibabaCloud::hasMock()) { + $stack = HandlerStack::create(AlibabaCloud::getMock()); + } else { + $stack = HandlerStack::create(); + } + + if (AlibabaCloud::isRememberHistory()) { + $stack->push(Middleware::history(AlibabaCloud::referenceHistory())); + } + + if (AlibabaCloud::getLogger()) { + $stack->push(Middleware::log( + AlibabaCloud::getLogger(), + new MessageFormatter(AlibabaCloud::getLogFormat()) + )); + } + + $stack->push(Middleware::mapResponse(static function (ResponseInterface $response) use ($request) { + return new Result($response, $request); + })); + + self::$config['handler'] = $stack; + + return new Client(self::$config); + } + + /** + * @throws ClientException + * @throws Exception + */ + private function response() + { + try { + return self::createClient($this)->request( + $this->method, + (string)$this->uri, + $this->options + ); + } catch (GuzzleException $exception) { + if ($this->shouldClientRetry($exception)) { + return $this->response(); + } + throw new ClientException( + $exception->getMessage(), + SDK::SERVER_UNREACHABLE, + $exception + ); + } + } + + /** + * Remove redundant Query + * + * @codeCoverageIgnore + */ + private function cleanQuery() + { + if (isset($this->options['query']) && $this->options['query'] === []) { + unset($this->options['query']); + } + } + + /** + * Remove redundant Headers + * + * @codeCoverageIgnore + */ + private function cleanFormParams() + { + if (isset($this->options['form_params']) && $this->options['form_params'] === []) { + unset($this->options['form_params']); + } + } +} diff --git a/vendor/alibabacloud/client/src/Request/RoaRequest.php b/vendor/alibabacloud/client/src/Request/RoaRequest.php new file mode 100644 index 0000000..2993f14 --- /dev/null +++ b/vendor/alibabacloud/client/src/Request/RoaRequest.php @@ -0,0 +1,333 @@ +resolveQuery(); + $this->resolveHeaders(); + $this->resolveBody(); + $this->resolveUri(); + $this->resolveSignature(); + } + + private function resolveQuery() + { + if (!isset($this->options['query']['Version'])) { + $this->options['query']['Version'] = $this->version; + } + } + + private function resolveBody() + { + // If the body has already been specified, it will not be resolved. + if (isset($this->options['body'])) { + return; + } + + if (!isset($this->options['form_params'])) { + return; + } + + // Merge data, compatible with parameters set from constructor. + $params = Arrays::merge( + [ + $this->data, + $this->options['form_params'] + ] + ); + + $this->encodeBody($params); + + unset($this->options['form_params']); + } + + /** + * Determine the body format based on the Content-Type and calculate the MD5 value. + * + * @param array $params + */ + private function encodeBody(array $params) + { + if (Stringy::contains($this->options['headers']['Content-Type'], 'application/json', false)) { + $this->options['body'] = json_encode($params); + $this->options['headers']['Content-MD5'] = base64_encode(md5($this->options['body'], true)); + + return; + } + + $this->options['body'] = Encode::create($params)->ksort()->toString(); + $this->options['headers']['Content-MD5'] = base64_encode(md5($this->options['body'], true)); + $this->options['headers']['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; + } + + /** + * @throws ClientException + * @throws ServerException + * @throws Exception + */ + private function resolveHeaders() + { + $this->options['headers']['x-acs-version'] = $this->version; + $this->options['headers']['x-acs-region-id'] = $this->realRegionId(); + $this->options['headers']['Date'] = gmdate($this->dateTimeFormat); + + $signature = $this->httpClient()->getSignature(); + $this->options['headers']['x-acs-signature-method'] = $signature->getMethod(); + $this->options['headers']['x-acs-signature-nonce'] = Sign::uuid($this->product . $this->action); + $this->options['headers']['x-acs-signature-version'] = $signature->getVersion(); + if ($signature->getType()) { + $this->options['headers']['x-acs-signature-type'] = $signature->getType(); + } + + $this->resolveAccept(); + $this->resolveContentType(); + $this->resolveSecurityToken(); + $this->resolveBearerToken(); + } + + /** + * @throws ClientException + * @throws Exception + */ + private function resolveSignature() + { + $this->options['headers']['Authorization'] = $this->signature(); + } + + /** + * If accept is not specified, it is determined by format. + */ + private function resolveAccept() + { + if (!isset($this->options['headers']['Accept'])) { + $this->options['headers']['Accept'] = Accept::create($this->format)->toString(); + } + } + + /** + * If the Content-Type is not specified, it is determined according to accept. + */ + private function resolveContentType() + { + if (!isset($this->options['headers']['Content-Type'])) { + $this->options['headers']['Content-Type'] = "{$this->options['headers']['Accept']}; charset=utf-8"; + } + } + + /** + * @throws ClientException + * @throws ServerException + */ + private function resolveSecurityToken() + { + if (!$this->credential() instanceof StsCredential) { + return; + } + + if (!$this->credential()->getSecurityToken()) { + return; + } + + $this->options['headers']['x-acs-security-token'] = $this->credential()->getSecurityToken(); + } + + /** + * @throws ClientException + * @throws ServerException + */ + private function resolveBearerToken() + { + if ($this->credential() instanceof BearerTokenCredential) { + $this->options['headers']['x-acs-bearer-token'] = $this->credential()->getBearerToken(); + } + } + + /** + * Sign the request message. + * + * @return string + * @throws ClientException + * @throws ServerException + */ + private function signature() + { + /** + * @var AccessKeyCredential $credential + */ + $credential = $this->credential(); + $access_key_id = $credential->getAccessKeyId(); + $signature = $this->httpClient() + ->getSignature() + ->sign( + $this->stringToSign(), + $credential->getAccessKeySecret() + ); + + return "acs $access_key_id:$signature"; + } + + /** + * @return void + */ + private function resolveUri() + { + $path = Path::assign($this->pathPattern, $this->pathParameters); + + $this->uri = $this->uri->withPath($path) + ->withQuery( + $this->queryString() + ); + } + + /** + * @return string + */ + public function stringToSign() + { + $request = new \GuzzleHttp\Psr7\Request( + $this->method, + $this->uri, + $this->options['headers'] + ); + + return Sign::roaString($request); + } + + /** + * @return bool|string + */ + private function queryString() + { + $query = isset($this->options['query']) + ? $this->options['query'] + : []; + + return Encode::create($query)->ksort()->toString(); + } + + /** + * Set path parameter by name. + * + * @param string $name + * @param string $value + * + * @return RoaRequest + * @throws ClientException + */ + public function pathParameter($name, $value) + { + Filter::name($name); + + if ($value === '') { + throw new ClientException( + 'Value cannot be empty', + SDK::INVALID_ARGUMENT + ); + } + + $this->pathParameters[$name] = $value; + + return $this; + } + + /** + * Set path pattern. + * + * @param string $pattern + * + * @return self + * @throws ClientException + */ + public function pathPattern($pattern) + { + ApiFilter::pattern($pattern); + + $this->pathPattern = $pattern; + + return $this; + } + + /** + * Magic method for set or get request parameters. + * + * @param string $name + * @param mixed $arguments + * + * @return $this + */ + public function __call($name, $arguments) + { + if (strncmp($name, 'get', 3) === 0) { + $parameter_name = \mb_strcut($name, 3); + + return $this->__get($parameter_name); + } + + if (strncmp($name, 'with', 4) === 0) { + $parameter_name = \mb_strcut($name, 4); + $this->__set($parameter_name, $arguments[0]); + $this->pathParameters[$parameter_name] = $arguments[0]; + + return $this; + } + + if (strncmp($name, 'set', 3) === 0) { + $parameter_name = \mb_strcut($name, 3); + $with_method = "with$parameter_name"; + + throw new RuntimeException("Please use $with_method instead of $name"); + } + + throw new RuntimeException('Call to undefined method ' . __CLASS__ . '::' . $name . '()'); + } +} diff --git a/vendor/alibabacloud/client/src/Request/RpcRequest.php b/vendor/alibabacloud/client/src/Request/RpcRequest.php new file mode 100644 index 0000000..389c949 --- /dev/null +++ b/vendor/alibabacloud/client/src/Request/RpcRequest.php @@ -0,0 +1,203 @@ +resolveBoolInParameters(); + $this->resolveCommonParameters(); + $this->repositionParameters(); + } + + /** + * Convert a Boolean value to a string + */ + private function resolveBoolInParameters() + { + if (isset($this->options['query'])) { + $this->options['query'] = array_map( + static function ($value) { + return self::boolToString($value); + }, + $this->options['query'] + ); + } + } + + /** + * Convert a Boolean value to a string. + * + * @param bool|string $value + * + * @return string + */ + public static function boolToString($value) + { + if (is_bool($value)) { + return $value ? 'true' : 'false'; + } + + return $value; + } + + /** + * Resolve Common Parameters. + * + * @throws ClientException + * @throws Exception + */ + private function resolveCommonParameters() + { + $signature = $this->httpClient()->getSignature(); + $this->options['query']['RegionId'] = $this->realRegionId(); + $this->options['query']['Format'] = $this->format; + $this->options['query']['SignatureMethod'] = $signature->getMethod(); + $this->options['query']['SignatureVersion'] = $signature->getVersion(); + $this->options['query']['SignatureNonce'] = Sign::uuid($this->product . $this->action); + $this->options['query']['Timestamp'] = gmdate($this->dateTimeFormat); + $this->options['query']['Action'] = $this->action; + if ($this->credential()->getAccessKeyId()) { + $this->options['query']['AccessKeyId'] = $this->credential()->getAccessKeyId(); + } + if ($signature->getType()) { + $this->options['query']['SignatureType'] = $signature->getType(); + } + if (!isset($this->options['query']['Version'])) { + $this->options['query']['Version'] = $this->version; + } + $this->resolveSecurityToken(); + $this->resolveBearerToken(); + $this->options['query']['Signature'] = $this->signature(); + } + + /** + * @throws ClientException + * @throws ServerException + */ + private function resolveSecurityToken() + { + if (!$this->credential() instanceof StsCredential) { + return; + } + + if (!$this->credential()->getSecurityToken()) { + return; + } + + $this->options['query']['SecurityToken'] = $this->credential()->getSecurityToken(); + } + + /** + * @throws ClientException + * @throws ServerException + */ + private function resolveBearerToken() + { + if ($this->credential() instanceof BearerTokenCredential) { + $this->options['query']['BearerToken'] = $this->credential()->getBearerToken(); + } + } + + /** + * Sign the parameters. + * + * @return mixed + * @throws ClientException + * @throws ServerException + */ + private function signature() + { + return $this->httpClient() + ->getSignature() + ->sign( + $this->stringToSign(), + $this->credential()->getAccessKeySecret() . '&' + ); + } + + /** + * @return string + */ + public function stringToSign() + { + $query = isset($this->options['query']) ? $this->options['query'] : []; + $form_params = isset($this->options['form_params']) ? $this->options['form_params'] : []; + $parameters = Arrays::merge([$query, $form_params]); + + return Sign::rpcString($this->method, $parameters); + } + + /** + * Adjust parameter position + */ + private function repositionParameters() + { + if ($this->method === 'POST' || $this->method === 'PUT') { + foreach ($this->options['query'] as $api_key => $api_value) { + $this->options['form_params'][$api_key] = $api_value; + } + unset($this->options['query']); + } + } + + /** + * Magic method for set or get request parameters. + * + * @param string $name + * @param mixed $arguments + * + * @return $this + */ + public function __call($name, $arguments) + { + if (strncmp($name, 'get', 3) === 0) { + $parameter_name = \mb_strcut($name, 3); + + return $this->__get($parameter_name); + } + + if (strncmp($name, 'with', 4) === 0) { + $parameter_name = \mb_strcut($name, 4); + $this->__set($parameter_name, $arguments[0]); + $this->options['query'][$parameter_name] = $arguments[0]; + + return $this; + } + + if (strncmp($name, 'set', 3) === 0) { + $parameter_name = \mb_strcut($name, 3); + $with_method = "with$parameter_name"; + + throw new RuntimeException("Please use $with_method instead of $name"); + } + + throw new RuntimeException('Call to undefined method ' . __CLASS__ . '::' . $name . '()'); + } +} diff --git a/vendor/alibabacloud/client/src/Request/Traits/AcsTrait.php b/vendor/alibabacloud/client/src/Request/Traits/AcsTrait.php new file mode 100644 index 0000000..5b2dd6b --- /dev/null +++ b/vendor/alibabacloud/client/src/Request/Traits/AcsTrait.php @@ -0,0 +1,259 @@ +action = ApiFilter::action($action); + + return $this; + } + + /** + * @codeCoverageIgnore + * + * @param string $endpointSuffix + * + * @return AcsTrait + * @throws ClientException + */ + public function endpointSuffix($endpointSuffix) + { + $this->endpointSuffix = ApiFilter::endpointSuffix($endpointSuffix); + + return $this; + } + + /** + * @param string $network + */ + public function network($network) + { + $this->network = ApiFilter::network($network); + + return $this; + } + + /** + * @param string $version + * + * @return $this + * @throws ClientException + */ + public function version($version) + { + $this->version = ApiFilter::version($version); + + return $this; + } + + /** + * @param string $product + * + * @return $this + * @throws ClientException + */ + public function product($product) + { + $this->product = ApiFilter::product($product); + + return $this; + } + + /** + * @param string $endpointType + * + * @return $this + * @throws ClientException + */ + public function endpointType($endpointType) + { + $this->endpointType = ApiFilter::endpointType($endpointType); + + return $this; + } + + /** + * @param string $serviceCode + * + * @return $this + * @throws ClientException + */ + public function serviceCode($serviceCode) + { + $this->serviceCode = ApiFilter::serviceCode($serviceCode); + + return $this; + } + + /** + * Resolve Host. + * + * @throws ClientException + * @throws ServerException + */ + public function resolveHost() + { + // Return if specified + if ($this->uri->getHost() !== 'localhost') { + return; + } + + $region_id = $this->realRegionId(); + $host = ''; + + $this->resolveHostWays($host, $region_id); + + if (!$host) { + throw new ClientException( + "No host found for {$this->product} in the {$region_id}, you can specify host by host() method. " . + 'Like $request->host(\'xxx.xxx.aliyuncs.com\')', + SDK::HOST_NOT_FOUND + ); + } + + $this->uri = $this->uri->withHost($host); + } + + /** + * @param string $host + * @param string $region_id + * + * @throws ClientException + * @throws ServerException + */ + private function resolveHostWays(&$host, $region_id) + { + $host = AlibabaCloud::resolveHostByStatic($this->product, $region_id); + + // 1. Find host by map. + if (!$host && $this->network === 'public' && isset($this->endpointMap[$region_id])) { + $host = $this->endpointMap[$region_id]; + } + + if (!$host) { + $this->hostResolver($host, $region_id); + } + } + + /** + * @codeCoverageIgnore + * + * @param string $host + * @param string $region_id + * + * @throws ClientException + * @throws ServerException + */ + private function hostResolver(&$host, $region_id) + { + // 2. Find host by rules. + if ($this->endpointRegional !== null) { + $host = AlibabaCloud::resolveHostByRule($this); + } + + // 3. Find in the local array file. + if (!$host) { + $host = AlibabaCloud::resolveHost($this->product, $region_id); + } + + // 4. Find in the Location service. + if (!$host && $this->serviceCode) { + $host = LocationService::resolveHost($this); + } + } + + /** + * @return string + * @throws ClientException + */ + public function realRegionId() + { + if ($this->regionId !== null) { + return $this->regionId; + } + + if ($this->httpClient()->regionId !== null) { + return $this->httpClient()->regionId; + } + + if (AlibabaCloud::getDefaultRegionId() !== null) { + return AlibabaCloud::getDefaultRegionId(); + } + + if ($this->product && AlibabaCloud::isGlobalProduct($this->product)) { + return 'global'; + } + + throw new ClientException("Missing required 'RegionId' for Request", SDK::INVALID_REGION_ID); + } +} diff --git a/vendor/alibabacloud/client/src/Request/Traits/ClientTrait.php b/vendor/alibabacloud/client/src/Request/Traits/ClientTrait.php new file mode 100644 index 0000000..37a2d22 --- /dev/null +++ b/vendor/alibabacloud/client/src/Request/Traits/ClientTrait.php @@ -0,0 +1,98 @@ +httpClient()->getCredential(); + } + + $timeout = isset($this->options['timeout']) + ? $this->options['timeout'] + : Request::TIMEOUT; + + $connectTimeout = isset($this->options['connect_timeout']) + ? $this->options['connect_timeout'] + : Request::CONNECT_TIMEOUT; + + return $this->httpClient()->getSessionCredential($timeout, $connectTimeout); + } + + /** + * Get the client based on the request's settings. + * + * @return Client + * @throws ClientException + */ + public function httpClient() + { + if (!AlibabaCloud::all()) { + if (CredentialsProvider::hasCustomChain()) { + CredentialsProvider::customProvider($this->client); + } else { + CredentialsProvider::defaultProvider($this->client); + } + } + + return AlibabaCloud::get($this->client); + } + + /** + * Merged with the client's options, the same name will be overwritten. + * + * @throws ClientException + */ + public function mergeOptionsIntoClient() + { + $this->options = Arrays::merge( + [ + $this->httpClient()->options, + $this->options + ] + ); + } +} diff --git a/vendor/alibabacloud/client/src/Request/Traits/DeprecatedRoaTrait.php b/vendor/alibabacloud/client/src/Request/Traits/DeprecatedRoaTrait.php new file mode 100644 index 0000000..ee64e52 --- /dev/null +++ b/vendor/alibabacloud/client/src/Request/Traits/DeprecatedRoaTrait.php @@ -0,0 +1,55 @@ +pathParameter($name, $value); + } + + /** + * @param $pathPattern + * + * @return $this + * @deprecated + * @codeCoverageIgnore + */ + public function setUriPattern($pathPattern) + { + return $this->pathPattern($pathPattern); + } + + /** + * @return string + * @deprecated + * @codeCoverageIgnore + */ + public function getUriPattern() + { + return $this->pathPattern; + } + + /** + * @return array + * @deprecated + * @codeCoverageIgnore + */ + public function getPathParameters() + { + return $this->pathParameters; + } +} diff --git a/vendor/alibabacloud/client/src/Request/Traits/DeprecatedTrait.php b/vendor/alibabacloud/client/src/Request/Traits/DeprecatedTrait.php new file mode 100644 index 0000000..406e6ed --- /dev/null +++ b/vendor/alibabacloud/client/src/Request/Traits/DeprecatedTrait.php @@ -0,0 +1,246 @@ +body($content); + } + + /** + * @param $method + * + * @return $this + * @throws ClientException + * @deprecated + * @codeCoverageIgnore + */ + public function setMethod($method) + { + return $this->method($method); + } + + /** + * @param $scheme + * + * @return $this + * @throws ClientException + * @deprecated + * @codeCoverageIgnore + */ + public function setProtocol($scheme) + { + return $this->scheme($scheme); + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getProtocolType() + { + return $this->uri->getScheme(); + } + + /** + * @param $scheme + * + * @return $this + * @throws ClientException + * @deprecated + * @codeCoverageIgnore + */ + public function setProtocolType($scheme) + { + return $this->scheme($scheme); + } + + /** + * @param $actionName + * + * @return $this + * @throws ClientException + * @deprecated + * @codeCoverageIgnore + */ + public function setActionName($actionName) + { + return $this->action($actionName); + } + + /** + * @param $format + * + * @return $this + * @throws ClientException + * @deprecated + * @codeCoverageIgnore + */ + public function setAcceptFormat($format) + { + return $this->format($format); + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getProtocol() + { + return $this->uri->getScheme(); + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getContent() + { + return isset($this->options['body']) + ? $this->options['body'] + : null; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getMethod() + { + return $this->method; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getHeaders() + { + return isset($this->options['headers']) + ? $this->options['headers'] + : []; + } + + /** + * @param $headerKey + * @param $headerValue + * + * @return $this + * @deprecated + * @codeCoverageIgnore + */ + public function addHeader($headerKey, $headerValue) + { + $this->options['headers'][$headerKey] = $headerValue; + + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getQueryParameters() + { + return isset($this->options['query']) + ? $this->options['query'] + : []; + } + + /** + * @param $name + * @param $value + * + * @return $this + * @deprecated + * @codeCoverageIgnore + */ + public function setQueryParameters($name, $value) + { + $this->options['query'][$name] = $value; + + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getDomainParameter() + { + return isset($this->options['form_params']) + ? $this->options['form_params'] + : []; + } + + /** + * @param $name + * @param $value + * + * @return $this + * @deprecated + * @codeCoverageIgnore + */ + public function putDomainParameters($name, $value) + { + $this->options['form_params'][$name] = $value; + + return $this; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getActionName() + { + return $this->action; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getAcceptFormat() + { + return $this->format; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getLocationEndpointType() + { + return $this->endpointType; + } + + /** + * @deprecated + * @codeCoverageIgnore + */ + public function getLocationServiceCode() + { + return $this->serviceCode; + } +} diff --git a/vendor/alibabacloud/client/src/Request/Traits/RetryTrait.php b/vendor/alibabacloud/client/src/Request/Traits/RetryTrait.php new file mode 100644 index 0000000..be1d002 --- /dev/null +++ b/vendor/alibabacloud/client/src/Request/Traits/RetryTrait.php @@ -0,0 +1,149 @@ +serverRetry = ClientFilter::retry($times); + $this->serverRetryStrings = $strings; + $this->serverRetryStatusCodes = $statusCodes; + + return $this; + } + + /** + * @param int $times + * @param array $strings + * @param array $codes + * + * @return $this + * @throws ClientException + */ + public function retryByClient($times, array $strings, array $codes = []) + { + $this->clientRetry = ClientFilter::retry($times); + $this->clientRetryStrings = $strings; + $this->clientRetryStatusCodes = $codes; + + return $this; + } + + /** + * @param Result $result + * + * @return bool + */ + private function shouldServerRetry(Result $result) + { + if ($this->serverRetry <= 0) { + return false; + } + + if (in_array($result->getStatusCode(), $this->serverRetryStatusCodes)) { + $this->serverRetry--; + + return true; + } + + foreach ($this->serverRetryStrings as $message) { + if (Stringy::contains($result->getBody(), $message)) { + $this->serverRetry--; + + return true; + } + } + + return false; + } + + /** + * @param Exception $exception + * + * @return bool + */ + private function shouldClientRetry(Exception $exception) + { + if ($this->clientRetry <= 0) { + return false; + } + + if (in_array($exception->getCode(), $this->clientRetryStatusCodes, true)) { + $this->clientRetry--; + + return true; + } + + foreach ($this->clientRetryStrings as $message) { + if (Stringy::contains($exception->getMessage(), $message)) { + $this->clientRetry--; + + return true; + } + } + + return false; + } +} diff --git a/vendor/alibabacloud/client/src/Request/UserAgent.php b/vendor/alibabacloud/client/src/Request/UserAgent.php new file mode 100644 index 0000000..beb3283 --- /dev/null +++ b/vendor/alibabacloud/client/src/Request/UserAgent.php @@ -0,0 +1,142 @@ + $value) { + if ($value === null) { + $newUserAgent[] = $key; + continue; + } + $newUserAgent[] = "$key/$value"; + } + + return $userAgent . \implode(' ', $newUserAgent); + } + + /** + * UserAgent constructor. + */ + private static function defaultFields() + { + if (self::$userAgent === []) { + self::$userAgent = [ + 'Client' => AlibabaCloud::VERSION, + 'PHP' => \PHP_VERSION, + ]; + } + } + + /** + * @param array $append + * + * @return array + */ + public static function clean(array $append) + { + foreach ($append as $key => $value) { + if (self::isGuarded($key)) { + unset($append[$key]); + continue; + } + } + + return $append; + } + + /** + * @param $name + * + * @return bool + */ + public static function isGuarded($name) + { + return in_array(strtolower($name), self::$guard, true); + } + + /** + * set User Agent of Alibaba Cloud. + * + * @param string $name + * @param string $value + * + * @throws ClientException + */ + public static function append($name, $value) + { + Filter::name($name); + Filter::value($value); + + self::defaultFields(); + + if (!self::isGuarded($name)) { + self::$userAgent[$name] = $value; + } + } + + /** + * @param array $userAgent + */ + public static function with(array $userAgent) + { + self::$userAgent = self::clean($userAgent); + } + + /** + * Clear all of the User Agent. + */ + public static function clear() + { + self::$userAgent = []; + } +} diff --git a/vendor/alibabacloud/client/src/Resolver/ActionResolverTrait.php b/vendor/alibabacloud/client/src/Resolver/ActionResolverTrait.php new file mode 100644 index 0000000..f375567 --- /dev/null +++ b/vendor/alibabacloud/client/src/Resolver/ActionResolverTrait.php @@ -0,0 +1,50 @@ +action) { + $array = explode('\\', get_class($this)); + $this->action = array_pop($array); + } + } + + /** + * Append SDK version into User-Agent + * + * @throws ClientException + * @throws ReflectionException + */ + private function appendSdkUA() + { + if (!(new ReflectionClass(AlibabaCloud::class))->hasMethod('appendUserAgent')) { + return; + } + + if (!class_exists('AlibabaCloud\Release')) { + return; + } + + AlibabaCloud::appendUserAgent('SDK', \AlibabaCloud\Release::VERSION); + } +} diff --git a/vendor/alibabacloud/client/src/Resolver/ApiResolver.php b/vendor/alibabacloud/client/src/Resolver/ApiResolver.php new file mode 100644 index 0000000..7a2bc2b --- /dev/null +++ b/vendor/alibabacloud/client/src/Resolver/ApiResolver.php @@ -0,0 +1,113 @@ +__call($name, $arguments); + } + + /** + * @param $api + * @param $arguments + * + * @return mixed + * @throws ClientException + */ + public function __call($api, $arguments) + { + $product_name = $this->getProductName(); + $class = $this->getNamespace() . '\\' . \ucfirst($api); + + if (\class_exists($class)) { + if (isset($arguments[0])) { + return $this->warpEndpoint(new $class($arguments[0])); + } + + return $this->warpEndpoint(new $class()); + } + + throw new ClientException( + "{$product_name} contains no $api", + 'SDK.ApiNotFound' + ); + } + + /** + * @param Request $request + * + * @return Request + */ + public function warpEndpoint(Request $request) + { + $reflect = new ReflectionObject($request); + $product_dir = dirname(dirname($reflect->getFileName())); + $endpoints_json = "$product_dir/endpoints.json"; + if (file_exists($endpoints_json)) { + $endpoints = json_decode(file_get_contents($endpoints_json), true); + if (isset($endpoints['endpoint_map'])) { + $request->endpointMap = $endpoints['endpoint_map']; + } + if (isset($endpoints['endpoint_regional'])) { + $request->endpointRegional = $endpoints['endpoint_regional']; + } + } + + return $request; + } + + /** + * @return mixed + * @throws ClientException + */ + private function getProductName() + { + $array = \explode('\\', \get_class($this)); + if (isset($array[3])) { + return str_replace('ApiResolver', '', $array[3]); + } + throw new ClientException( + 'Service name not found.', + 'SDK.ServiceNotFound' + ); + } + + /** + * @return string + * @throws ClientException + */ + private function getNamespace() + { + $array = \explode('\\', \get_class($this)); + + if (!isset($array[3])) { + throw new ClientException( + 'Get namespace error.', + 'SDK.ParseError' + ); + } + + unset($array[3]); + + return \implode('\\', $array); + } +} diff --git a/vendor/alibabacloud/client/src/Resolver/CallTrait.php b/vendor/alibabacloud/client/src/Resolver/CallTrait.php new file mode 100644 index 0000000..520c03b --- /dev/null +++ b/vendor/alibabacloud/client/src/Resolver/CallTrait.php @@ -0,0 +1,66 @@ +__get($parameter); + } + + if (strncmp($name, 'with', 4) === 0) { + $parameter = \mb_strcut($name, 4); + + $value = $this->getCallArguments($name, $arguments); + $this->data[$parameter] = $value; + $this->parameterPosition()[$parameter] = $value; + + return $this; + } + + if (strncmp($name, 'set', 3) === 0) { + $parameter = \mb_strcut($name, 3); + $with_method = "with$parameter"; + + return $this->$with_method($this->getCallArguments($name, $arguments)); + } + + throw new RuntimeException('Call to undefined method ' . __CLASS__ . '::' . $name . '()'); + } + + /** + * @param string $name + * @param array $arguments + * @param int $index + * + * @return mixed + */ + private function getCallArguments($name, array $arguments, $index = 0) + { + if (!isset($arguments[$index])) { + throw new \InvalidArgumentException("Missing arguments to method $name"); + } + + return $arguments[$index]; + } +} diff --git a/vendor/alibabacloud/client/src/Resolver/Roa.php b/vendor/alibabacloud/client/src/Resolver/Roa.php new file mode 100644 index 0000000..719cb0a --- /dev/null +++ b/vendor/alibabacloud/client/src/Resolver/Roa.php @@ -0,0 +1,43 @@ +resolveActionName(); + $this->appendSdkUA(); + } + + /** + * @return mixed + */ + private function ¶meterPosition() + { + return $this->pathParameters; + } +} diff --git a/vendor/alibabacloud/client/src/Resolver/Rpc.php b/vendor/alibabacloud/client/src/Resolver/Rpc.php new file mode 100644 index 0000000..0926ca4 --- /dev/null +++ b/vendor/alibabacloud/client/src/Resolver/Rpc.php @@ -0,0 +1,41 @@ +resolveActionName(); + $this->appendSdkUA(); + } + + /** + * @return mixed + */ + private function ¶meterPosition() + { + return $this->options['query']; + } +} diff --git a/vendor/alibabacloud/client/src/Resolver/VersionResolver.php b/vendor/alibabacloud/client/src/Resolver/VersionResolver.php new file mode 100644 index 0000000..5662718 --- /dev/null +++ b/vendor/alibabacloud/client/src/Resolver/VersionResolver.php @@ -0,0 +1,74 @@ +__call($name, $arguments); + } + + /** + * @param string $version + * @param array $arguments + * + * @return mixed + * @throws ClientException + */ + public function __call($version, $arguments) + { + $version = \ucfirst($version); + $product = $this->getProductName(); + + $position = strpos($product, 'Version'); + if ($position !== false && $position !== 0) { + $product = \str_replace('Version', '', $product); + } + + $class = "AlibabaCloud\\{$product}\\$version\\{$product}ApiResolver"; + + if (\class_exists($class)) { + return new $class(); + } + + throw new ClientException( + "$product Versions contains no {$version}", + 'SDK.VersionNotFound' + ); + } + + /** + * @return mixed + * @throws ClientException + */ + private function getProductName() + { + $array = \explode('\\', \get_class($this)); + + if (is_array($array) && isset($array[1])) { + return $array[1]; + } + + throw new ClientException( + 'Service name not found.', + 'SDK.ServiceNotFound' + ); + } +} diff --git a/vendor/alibabacloud/client/src/Result/Result.php b/vendor/alibabacloud/client/src/Result/Result.php new file mode 100644 index 0000000..7c2910e --- /dev/null +++ b/vendor/alibabacloud/client/src/Result/Result.php @@ -0,0 +1,151 @@ +getStatusCode(), + $response->getHeaders(), + $response->getBody(), + $response->getProtocolVersion(), + $response->getReasonPhrase() + ); + + $this->request = $request; + + $this->resolveData(); + } + + private function resolveData() + { + $content = $this->getBody()->getContents(); + + switch ($this->getRequestFormat()) { + case 'JSON': + $result_data = $this->jsonToArray($content); + break; + case 'XML': + $result_data = $this->xmlToArray($content); + break; + case 'RAW': + $result_data = $this->jsonToArray($content); + break; + default: + $result_data = $this->jsonToArray($content); + } + + if (!$result_data) { + $result_data = []; + } + + $this->dot($result_data); + } + + /** + * @return string + */ + private function getRequestFormat() + { + return ($this->request instanceof Request) + ? \strtoupper($this->request->format) + : 'JSON'; + } + + /** + * @param string $response + * + * @return array + */ + private function jsonToArray($response) + { + try { + return \GuzzleHttp\json_decode($response, true); + } catch (InvalidArgumentException $exception) { + return []; + } + } + + /** + * @param string $string + * + * @return array + */ + private function xmlToArray($string) + { + try { + return json_decode(json_encode(simplexml_load_string($string)), true); + } catch (Exception $exception) { + return []; + } + } + + /** + * @return string + */ + public function __toString() + { + return (string)$this->getBody(); + } + + /** + * @return Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * @codeCoverageIgnore + * @return Response + * @deprecated + */ + public function getResponse() + { + return $this; + } + + /** + * @return bool + */ + public function isSuccess() + { + return 200 <= $this->getStatusCode() + && 300 > $this->getStatusCode(); + } +} diff --git a/vendor/alibabacloud/client/src/SDK.php b/vendor/alibabacloud/client/src/SDK.php new file mode 100644 index 0000000..8976cd0 --- /dev/null +++ b/vendor/alibabacloud/client/src/SDK.php @@ -0,0 +1,57 @@ +getMessage(), + SDK::INVALID_CREDENTIAL + ); + } + + return base64_encode($binarySignature); + } +} diff --git a/vendor/alibabacloud/client/src/Signature/Signature.php b/vendor/alibabacloud/client/src/Signature/Signature.php new file mode 100644 index 0000000..3b01e69 --- /dev/null +++ b/vendor/alibabacloud/client/src/Signature/Signature.php @@ -0,0 +1,49 @@ +sign($string, $accessKeySecret); + + return "acs $accessKeyId:$signature"; + } + + /** + * @codeCoverageIgnore + * + * @param string $accessKeySecret + * @param string $method + * @param array $parameters + * + * @return string + */ + public function rpc($accessKeySecret, $method, array $parameters) + { + $string = Sign::rpcString($method, $parameters); + + return $this->sign($string, $accessKeySecret . '&'); + } +} diff --git a/vendor/alibabacloud/client/src/Signature/SignatureInterface.php b/vendor/alibabacloud/client/src/Signature/SignatureInterface.php new file mode 100644 index 0000000..afa82c8 --- /dev/null +++ b/vendor/alibabacloud/client/src/Signature/SignatureInterface.php @@ -0,0 +1,35 @@ + $value) { + if (is_int($key)) { + $result[] = $value; + continue; + } + + if (isset($result[$key]) && is_array($result[$key])) { + $result[$key] = self::merge( + [$result[$key], $value] + ); + continue; + } + + $result[$key] = $value; + } + } + + return $result; + } +} diff --git a/vendor/alibabacloud/client/src/Support/Path.php b/vendor/alibabacloud/client/src/Support/Path.php new file mode 100644 index 0000000..e1a6464 --- /dev/null +++ b/vendor/alibabacloud/client/src/Support/Path.php @@ -0,0 +1,28 @@ + $value) { + $pattern = str_replace("[$key]", $value, $pattern); + } + + return $pattern; + } +} diff --git a/vendor/alibabacloud/client/src/Support/Sign.php b/vendor/alibabacloud/client/src/Support/Sign.php new file mode 100644 index 0000000..1310d3d --- /dev/null +++ b/vendor/alibabacloud/client/src/Support/Sign.php @@ -0,0 +1,143 @@ + $headerValue) { + $key = strtolower($headerKey); + if (strncmp($key, 'x-acs-', 6) === 0) { + $array[$key] = $headerValue; + } + } + ksort($array); + $string = ''; + foreach ($array as $sortMapKey => $sortMapValue) { + $string .= $sortMapKey . ':' . $sortMapValue[0] . self::$headerSeparator; + } + + return $string; + } + + /** + * @param UriInterface $uri + * + * @return string + */ + private static function resourceString(UriInterface $uri) + { + return $uri->getPath() . '?' . rawurldecode($uri->getQuery()); + } + + /** + * @param string $method + * @param array $headers + * + * @return string + */ + private static function headerString($method, array $headers) + { + $string = $method . self::$headerSeparator; + if (isset($headers['Accept'][0])) { + $string .= $headers['Accept'][0]; + } + $string .= self::$headerSeparator; + + if (isset($headers['Content-MD5'][0])) { + $string .= $headers['Content-MD5'][0]; + } + $string .= self::$headerSeparator; + + if (isset($headers['Content-Type'][0])) { + $string .= $headers['Content-Type'][0]; + } + $string .= self::$headerSeparator; + + if (isset($headers['Date'][0])) { + $string .= $headers['Date'][0]; + } + $string .= self::$headerSeparator; + + $string .= self::acsHeaderString($headers); + + return $string; + } + + /** + * @param string $string + * + * @return null|string|string[] + */ + private static function percentEncode($string) + { + $result = urlencode($string); + $result = str_replace(['+', '*'], ['%20', '%2A'], $result); + $result = preg_replace('/%7E/', '~', $result); + + return $result; + } + + /** + * @param string $method + * @param array $parameters + * + * @return string + */ + public static function rpcString($method, array $parameters) + { + ksort($parameters); + $canonicalized = ''; + foreach ($parameters as $key => $value) { + if ($value === null || $value === '') { + continue; + } + $canonicalized .= '&' . self::percentEncode($key) . '=' . self::percentEncode($value); + } + + return $method . '&%2F&' . self::percentEncode(substr($canonicalized, 1)); + } + + /** + * @param Request $request + * + * @return string + */ + public static function roaString(Request $request) + { + return self::headerString($request->getMethod(), $request->getHeaders()) . + self::resourceString($request->getUri()); + } + + /** + * @param string $salt + * + * @return string + */ + public static function uuid($salt) + { + return md5($salt . uniqid(md5(microtime(true)), true)) . microtime(); + } +} diff --git a/vendor/alibabacloud/client/src/Support/Stringy.php b/vendor/alibabacloud/client/src/Support/Stringy.php new file mode 100644 index 0000000..f4c1099 --- /dev/null +++ b/vendor/alibabacloud/client/src/Support/Stringy.php @@ -0,0 +1,47 @@ +data[$offset])) { + return $this->data[$offset]; + } + + $value = null; + + return $value; + } + + /** + * @param string $offset + * @param string|mixed $value + */ + #[\ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + /** + * @param string $offset + * + * @return bool + */ + #[\ReturnTypeWillChange] + public function offsetExists($offset) + { + return isset($this->data[$offset]); + } + + /** + * @param string $offset + */ + #[\ReturnTypeWillChange] + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } +} diff --git a/vendor/alibabacloud/client/src/Traits/ClientTrait.php b/vendor/alibabacloud/client/src/Traits/ClientTrait.php new file mode 100644 index 0000000..2cb5309 --- /dev/null +++ b/vendor/alibabacloud/client/src/Traits/ClientTrait.php @@ -0,0 +1,273 @@ +load(); + } + $list = []; + foreach (\func_get_args() as $filename) { + $list[$filename] = (new IniCredential($filename))->load(); + } + + return $list; + } + + /** + * Custom Client. + * + * @param CredentialsInterface $credentials + * @param SignatureInterface $signature + * + * @return Client + */ + public static function client(CredentialsInterface $credentials, SignatureInterface $signature) + { + return new Client($credentials, $signature); + } + + /** + * Use the AccessKey to complete the authentication. + * + * @param string $accessKeyId + * @param string $accessKeySecret + * + * @return AccessKeyClient + * @throws ClientException + */ + public static function accessKeyClient($accessKeyId, $accessKeySecret) + { + if (null === $accessKeyId || strpos($accessKeyId, ' ') !== false) { + throw new ClientException( + 'AccessKey ID format is invalid', + SDK::INVALID_ARGUMENT + ); + } + + if (null === $accessKeySecret || strpos($accessKeySecret, ' ') !== false) { + throw new ClientException( + 'AccessKey Secret format is invalid', + SDK::INVALID_ARGUMENT + ); + } + + return new AccessKeyClient($accessKeyId, $accessKeySecret); + } + + /** + * Use the AssumeRole of the RAM account to complete the authentication. + * + * @param string $accessKeyId + * @param string $accessKeySecret + * @param string $roleArn + * @param string $roleSessionName + * @param string|array $policy + * + * @return RamRoleArnClient + * @throws ClientException + */ + public static function ramRoleArnClient($accessKeyId, $accessKeySecret, $roleArn, $roleSessionName, $policy = '') + { + return new RamRoleArnClient($accessKeyId, $accessKeySecret, $roleArn, $roleSessionName, $policy); + } + + /** + * Use the RAM role of an ECS instance to complete the authentication. + * + * @param string $roleName + * + * @return EcsRamRoleClient + * @throws ClientException + */ + public static function ecsRamRoleClient($roleName) + { + return new EcsRamRoleClient($roleName); + } + + /** + * Use the Bearer Token to complete the authentication. + * + * @param string $bearerToken + * + * @return BearerTokenClient + * @throws ClientException + */ + public static function bearerTokenClient($bearerToken) + { + return new BearerTokenClient($bearerToken); + } + + /** + * Use the STS Token to complete the authentication. + * + * @param string $accessKeyId Access key ID + * @param string $accessKeySecret Access Key Secret + * @param string $securityToken Security Token + * + * @return StsClient + * @throws ClientException + */ + public static function stsClient($accessKeyId, $accessKeySecret, $securityToken = '') + { + return new StsClient($accessKeyId, $accessKeySecret, $securityToken); + } + + /** + * Use the RSA key pair to complete the authentication (supported only on Japanese site) + * + * @param string $publicKeyId + * @param string $privateKeyFile + * + * @return RsaKeyPairClient + * @throws ClientException + */ + public static function rsaKeyPairClient($publicKeyId, $privateKeyFile) + { + return new RsaKeyPairClient($publicKeyId, $privateKeyFile); + } +} diff --git a/vendor/alibabacloud/client/src/Traits/DefaultRegionTrait.php b/vendor/alibabacloud/client/src/Traits/DefaultRegionTrait.php new file mode 100644 index 0000000..5d5c75a --- /dev/null +++ b/vendor/alibabacloud/client/src/Traits/DefaultRegionTrait.php @@ -0,0 +1,66 @@ +network ?: 'public'; + $suffix = $request->endpointSuffix; + if ($network === 'public') { + $network = ''; + } + + if ($request->endpointRegional === 'regional') { + $regionId = $request->realRegionId(); + return "{$request->product}{$suffix}{$network}.{$regionId}.aliyuncs.com"; + } + + if ($request->endpointRegional === 'central') { + return "{$request->product}{$suffix}{$network}.aliyuncs.com"; + } + + throw new InvalidArgumentException('endpointRegional is invalid.'); + } +} diff --git a/vendor/alibabacloud/client/src/Traits/HasDataTrait.php b/vendor/alibabacloud/client/src/Traits/HasDataTrait.php new file mode 100644 index 0000000..03c4b9d --- /dev/null +++ b/vendor/alibabacloud/client/src/Traits/HasDataTrait.php @@ -0,0 +1,324 @@ +dot->all()); + } + + /** + * Delete the contents of a given key or keys + * + * @param array|int|string|null $keys + */ + public function clear($keys = null) + { + $this->dot->clear($keys); + } + + /** + * Flatten an array with the given character as a key delimiter + * + * @param string $delimiter + * @param array|null $items + * @param string $prepend + * + * @return array + */ + public function flatten($delimiter = '.', $items = null, $prepend = '') + { + return $this->dot->flatten($delimiter, $items, $prepend); + } + + /** + * Return the value of a given key + * + * @param int|string|null $key + * @param mixed $default + * + * @return mixed + */ + public function get($key = null, $default = null) + { + return $this->dot->get($key, $default); + } + + /** + * Set a given key / value pair or pairs + * + * @param array|int|string $keys + * @param mixed $value + */ + public function set($keys, $value = null) + { + $this->dot->set($keys, $value); + } + + /** + * Check if a given key or keys are empty + * + * @param array|int|string|null $keys + * + * @return bool + */ + public function isEmpty($keys = null) + { + return $this->dot->isEmpty($keys); + } + + /** + * Replace all items with a given array as a reference + * + * @param array $items + */ + public function setReference(array &$items) + { + $this->dot->setReference($items); + } + + /** + * Return the value of a given key or all the values as JSON + * + * @param mixed $key + * @param int $options + * + * @return string + */ + public function toJson($key = null, $options = 0) + { + return $this->dot->toJson($key, $options); + } + + /** + * @return array + */ + public function toArray() + { + return $this->dot->all(); + } + + /** + * Check if a given key exists + * + * @param int|string $key + * + * @return bool + */ + #[\ReturnTypeWillChange] + public function offsetExists($key) + { + return $this->dot->has($key); + } + + /** + * Return the value of a given key + * + * @param int|string $key + * + * @return mixed + */ + #[\ReturnTypeWillChange] + public function offsetGet($key) + { + return $this->dot->offsetGet($key); + } + + /** + * Set a given value to the given key + * + * @param int|string|null $key + * @param mixed $value + */ + #[\ReturnTypeWillChange] + public function offsetSet($key, $value) + { + $this->dot->offsetSet($key, $value); + } + + /** + * Delete the given key + * + * @param int|string $key + */ + #[\ReturnTypeWillChange] + public function offsetUnset($key) + { + $this->delete($key); + } + + /** + * Delete the given key or keys + * + * @param array|int|string $keys + */ + public function delete($keys) + { + $this->dot->delete($keys); + } + + /* + * -------------------------------------------------------------- + * ArrayAccess interface + * -------------------------------------------------------------- + */ + + /** + * Return the number of items in a given key + * + * @param int|string|null $key + * + * @return int + */ + #[\ReturnTypeWillChange] + public function count($key = null) + { + return $this->dot->count($key); + } + + /** + * Get an iterator for the stored items + * + * @return ArrayIterator + */ + #[\ReturnTypeWillChange] + public function getIterator() + { + return $this->dot->getIterator(); + } + + /** + * Return items for JSON serialization + * + * @return array + */ + #[\ReturnTypeWillChange] + public function jsonSerialize() + { + return $this->dot->jsonSerialize(); + } + + /** + * @param string $name + * + * @return mixed|null + */ + public function __get($name) + { + if (!isset($this->all()[$name])) { + return null; + } + + return \json_decode(\json_encode($this->all()))->$name; + } + + /* + * -------------------------------------------------------------- + * Countable interface + * -------------------------------------------------------------- + */ + + /** + * Return all the stored items + * + * @return array + */ + public function all() + { + return $this->dot->all(); + } + + /** + * @param string $name + * @param mixed $value + */ + public function __set($name, $value) + { + $this->add($name, $value); + } + + /** + * Set a given key / value pair or pairs + * if the key doesn't exist already + * + * @param array|int|string $keys + * @param mixed $value + */ + public function add($keys, $value = null) + { + $this->dot->add($keys, $value); + } + + + /* + * -------------------------------------------------------------- + * ObjectAccess + * -------------------------------------------------------------- + */ + + /** + * @param string $name + * + * @return bool + */ + public function __isset($name) + { + return $this->has($name); + } + + /** + * Check if a given key or keys exists + * + * @param array|int|string $keys + * + * @return bool + */ + public function has($keys) + { + return $this->dot->has($keys); + } + + /** + * @param $name + * + * @return void + */ + public function __unset($name) + { + $this->delete($name); + } + + /** + * @param array $data + */ + protected function dot(array $data = []) + { + $this->dot = new Dot($data); + } +} diff --git a/vendor/alibabacloud/client/src/Traits/HistoryTrait.php b/vendor/alibabacloud/client/src/Traits/HistoryTrait.php new file mode 100644 index 0000000..f70bb1d --- /dev/null +++ b/vendor/alibabacloud/client/src/Traits/HistoryTrait.php @@ -0,0 +1,68 @@ +options['timeout'] = ClientFilter::timeout($seconds); + + return $this; + } + + /** + * @param int $milliseconds + * + * @return $this + * @throws ClientException + */ + public function timeoutMilliseconds($milliseconds) + { + ClientFilter::milliseconds($milliseconds); + $seconds = $milliseconds / 1000; + + return $this->timeout($seconds); + } + + /** + * @param int|float $seconds + * + * @return $this + * @throws ClientException + */ + public function connectTimeout($seconds) + { + $this->options['connect_timeout'] = ClientFilter::connectTimeout($seconds); + + return $this; + } + + /** + * @param int $milliseconds + * + * @return $this + * @throws ClientException + */ + public function connectTimeoutMilliseconds($milliseconds) + { + ClientFilter::milliseconds($milliseconds); + $seconds = $milliseconds / 1000; + + return $this->connectTimeout($seconds); + } + + /** + * @param bool $debug + * + * @return $this + */ + public function debug($debug) + { + $this->options['debug'] = $debug; + + return $this; + } + + /** + * @codeCoverageIgnore + * + * @param array $cert + * + * @return $this + */ + public function cert($cert) + { + $this->options['cert'] = $cert; + + return $this; + } + + /** + * @codeCoverageIgnore + * + * @param array|string $proxy + * + * @return $this + */ + public function proxy($proxy) + { + $this->options['proxy'] = $proxy; + + return $this; + } + + /** + * @param mixed $verify + * + * @return $this + */ + public function verify($verify) + { + $this->options['verify'] = $verify; + + return $this; + } + + /** + * @param array $options + * + * @return $this + */ + public function options(array $options) + { + if ($options !== []) { + $this->options = Arrays::merge([$this->options, $options]); + } + + return $this; + } +} diff --git a/vendor/alibabacloud/client/src/Traits/LogTrait.php b/vendor/alibabacloud/client/src/Traits/LogTrait.php new file mode 100644 index 0000000..0457602 --- /dev/null +++ b/vendor/alibabacloud/client/src/Traits/LogTrait.php @@ -0,0 +1,97 @@ +format('Y-m-d H:i:s.u')], + $template + ); + } + + /** + * Apache Common Log Format. + * + * @param string $formatter + * + * @link http://httpd.apache.org/docs/2.4/logs.html#common + * @see \GuzzleHttp\MessageFormatter + */ + public static function setLogFormat($formatter) + { + self::$logFormat = $formatter; + } + + /** + * @return float|mixed + */ + private static function getCost() + { + return microtime(true) - self::$logStartTime; + } +} diff --git a/vendor/alibabacloud/client/src/Traits/MockTrait.php b/vendor/alibabacloud/client/src/Traits/MockTrait.php new file mode 100644 index 0000000..28928d1 --- /dev/null +++ b/vendor/alibabacloud/client/src/Traits/MockTrait.php @@ -0,0 +1,97 @@ +data[$name])) { + return null; + } + + return \json_decode(\json_encode($this->data))->$name; + } + + /** + * @param string $name + * @param mixed $value + */ + public function __set($name, $value) + { + $this->data[$name] = $value; + } + + /** + * @param string $name + * + * @return bool + */ + public function __isset($name) + { + return isset($this->data[$name]); + } + + /** + * @param $name + * + * @return void + */ + public function __unset($name) + { + unset($this->data[$name]); + } +} diff --git a/vendor/alibabacloud/client/src/Traits/RegionTrait.php b/vendor/alibabacloud/client/src/Traits/RegionTrait.php new file mode 100644 index 0000000..da6bee4 --- /dev/null +++ b/vendor/alibabacloud/client/src/Traits/RegionTrait.php @@ -0,0 +1,33 @@ +regionId = ClientFilter::regionId($regionId); + + return $this; + } +} diff --git a/vendor/alibabacloud/client/src/Traits/RequestTrait.php b/vendor/alibabacloud/client/src/Traits/RequestTrait.php new file mode 100644 index 0000000..afcb9a4 --- /dev/null +++ b/vendor/alibabacloud/client/src/Traits/RequestTrait.php @@ -0,0 +1,90 @@ +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + return include("phpvfscomposer://" . __DIR__ . '/..'.'/nesbot/carbon/bin/carbon'); + } +} + +return include __DIR__ . '/..'.'/nesbot/carbon/bin/carbon'; diff --git a/vendor/bin/jp.php b/vendor/bin/jp.php new file mode 100644 index 0000000..fc4e0a7 --- /dev/null +++ b/vendor/bin/jp.php @@ -0,0 +1,119 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + return include("phpvfscomposer://" . __DIR__ . '/..'.'/mtdowling/jmespath.php/bin/jp.php'); + } +} + +return include __DIR__ . '/..'.'/mtdowling/jmespath.php/bin/jp.php'; diff --git a/vendor/bin/var-dump-server b/vendor/bin/var-dump-server new file mode 100644 index 0000000..18db1c1 --- /dev/null +++ b/vendor/bin/var-dump-server @@ -0,0 +1,119 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + return include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server'); + } +} + +return include __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server'; diff --git a/vendor/carbonphp/carbon-doctrine-types/LICENSE b/vendor/carbonphp/carbon-doctrine-types/LICENSE new file mode 100644 index 0000000..2ee1671 --- /dev/null +++ b/vendor/carbonphp/carbon-doctrine-types/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Carbon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/carbonphp/carbon-doctrine-types/README.md b/vendor/carbonphp/carbon-doctrine-types/README.md new file mode 100644 index 0000000..5a18121 --- /dev/null +++ b/vendor/carbonphp/carbon-doctrine-types/README.md @@ -0,0 +1,14 @@ +# carbonphp/carbon-doctrine-types + +Types to use Carbon in Doctrine + +## Documentation + +[Check how to use in the official Carbon documentation](https://carbon.nesbot.com/symfony/) + +This package is an externalization of [src/Carbon/Doctrine](https://github.com/briannesbitt/Carbon/tree/2.71.0/src/Carbon/Doctrine) +from `nestbot/carbon` package. + +Externalization allows to better deal with different versions of dbal. With +version 4.0 of dbal, it no longer sustainable to be compatible with all version +using a single code. diff --git a/vendor/carbonphp/carbon-doctrine-types/composer.json b/vendor/carbonphp/carbon-doctrine-types/composer.json new file mode 100644 index 0000000..b5fd8a5 --- /dev/null +++ b/vendor/carbonphp/carbon-doctrine-types/composer.json @@ -0,0 +1,36 @@ +{ + "name": "carbonphp/carbon-doctrine-types", + "description": "Types to use Carbon in Doctrine", + "type": "library", + "keywords": [ + "date", + "time", + "DateTime", + "Carbon", + "Doctrine" + ], + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/dbal": "^3.7.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "conflict": { + "doctrine/dbal": "<3.7.0 || >=4.0.0" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "minimum-stability": "dev" +} diff --git a/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php b/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php new file mode 100644 index 0000000..8c42dc0 --- /dev/null +++ b/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/CarbonDoctrineType.php @@ -0,0 +1,14 @@ + + */ + protected function getCarbonClassName(): string + { + return Carbon::class; + } + + public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string + { + $precision = min( + $fieldDeclaration['precision'] ?? DateTimeDefaultPrecision::get(), + $this->getMaximumPrecision($platform), + ); + + $type = parent::getSQLDeclaration($fieldDeclaration, $platform); + + if (!$precision) { + return $type; + } + + if (str_contains($type, '(')) { + return preg_replace('/\(\d+\)/', "($precision)", $type); + } + + [$before, $after] = explode(' ', "$type "); + + return trim("$before($precision) $after"); + } + + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * + * @return T|null + */ + public function convertToPHPValue($value, AbstractPlatform $platform) + { + $class = $this->getCarbonClassName(); + + if ($value === null || is_a($value, $class)) { + return $value; + } + + if ($value instanceof DateTimeInterface) { + return $class::instance($value); + } + + $date = null; + $error = null; + + try { + $date = $class::parse($value); + } catch (Exception $exception) { + $error = $exception; + } + + if (!$date) { + throw ConversionException::conversionFailedFormat( + $value, + $this->getTypeName(), + 'Y-m-d H:i:s.u or any format supported by '.$class.'::parse()', + $error + ); + } + + return $date; + } + + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string + { + if ($value === null) { + return $value; + } + + if ($value instanceof DateTimeInterface) { + return $value->format('Y-m-d H:i:s.u'); + } + + throw ConversionException::conversionFailedInvalidType( + $value, + $this->getTypeName(), + ['null', 'DateTime', 'Carbon'] + ); + } + + private function getTypeName(): string + { + $chunks = explode('\\', static::class); + $type = preg_replace('/Type$/', '', end($chunks)); + + return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $type)); + } + + private function getMaximumPrecision(AbstractPlatform $platform): int + { + if ($platform instanceof DB2Platform) { + return 12; + } + + if ($platform instanceof OraclePlatform) { + return 9; + } + + if ($platform instanceof SQLServerPlatform || $platform instanceof SqlitePlatform) { + return 3; + } + + return 6; + } +} diff --git a/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php b/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php new file mode 100644 index 0000000..3a9ff11 --- /dev/null +++ b/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeDefaultPrecision.php @@ -0,0 +1,28 @@ + */ + use CarbonTypeConverter; + + /** + * @return class-string + */ + protected function getCarbonClassName(): string + { + return CarbonImmutable::class; + } +} diff --git a/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php b/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php new file mode 100644 index 0000000..3bf07e9 --- /dev/null +++ b/vendor/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine/DateTimeType.php @@ -0,0 +1,12 @@ + */ + use CarbonTypeConverter; +} diff --git a/vendor/clagiordano/weblibs-configmanager/.github/workflows/php.yml b/vendor/clagiordano/weblibs-configmanager/.github/workflows/php.yml new file mode 100644 index 0000000..7a9e14e --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/.github/workflows/php.yml @@ -0,0 +1,34 @@ +name: PHP Composer + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: [ ubuntu-18.04 ] + php: [ '5.4', '5.5', '5.6', '7.1', '7.2', '7.3', '7.4' ] + name: PHP ${{ matrix.operating-system }} ${{ matrix.php }} + + steps: + - uses: actions/checkout@v2 + - uses: nanasess/setup-php@master + with: + php-version: ${{ matrix.php }} + + - name: Validate composer.json and composer.lock + run: composer validate + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" + # Docs: https://getcomposer.org/doc/articles/scripts.md + + - name: Run test suite + run: ./vendor/bin/phpunit diff --git a/vendor/clagiordano/weblibs-configmanager/.gitignore b/vendor/clagiordano/weblibs-configmanager/.gitignore new file mode 100644 index 0000000..e01942f --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/.gitignore @@ -0,0 +1,2 @@ +composer.phar +vendor diff --git a/vendor/clagiordano/weblibs-configmanager/.travis.yml b/vendor/clagiordano/weblibs-configmanager/.travis.yml new file mode 100644 index 0000000..b13b30d --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/.travis.yml @@ -0,0 +1,17 @@ +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - 7.3 + - hhvm + +before_script: + - travis_retry composer self-update + - travis_retry composer update --prefer-source --no-interaction --dev + +script: phpunit diff --git a/vendor/clagiordano/weblibs-configmanager/README.md b/vendor/clagiordano/weblibs-configmanager/README.md new file mode 100644 index 0000000..f72bf5c --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/README.md @@ -0,0 +1,130 @@ +![BuildStatus](https://travis-ci.org/clagiordano/weblibs-configmanager.svg?branch=master) ![License](https://img.shields.io/github/license/clagiordano/weblibs-configmanager.svg) + +# weblibs-configmanager +weblibs-configmanager is a tool library for easily read and access to php config array file and direct read/write configuration file / object. + +[![SensioLabsInsight](https://insight.sensiolabs.com/projects/54c4e80c-ff15-4235-8bec-a4c71bbe3ba5/big.png)](https://insight.sensiolabs.com/projects/54c4e80c-ff15-4235-8bec-a4c71bbe3ba5) + +## Why use weblibs-configmanager ? +The purpose of this project is to propose a simple and lightweight library to manage php hierarchical configuration files. + +## Installation +The recommended way to install weblibs-configmanager is through [Composer](https://getcomposer.org). +```bash +composer require clagiordano/weblibs-configmanager +``` + +## Usage examples + +### Write a sample config file like this +``` + 'app_name', + 'db' => + array ( + 'host' => 'localhost', + 'user' => 'sample_user', + 'pass' => 'sample_pass', + 'port' => 3306, + ), + 'other' => + array ( + 'multi' => + array ( + 'deep' => + array ( + 'nested' => 'config_value', + ), + ), + ), +); + +``` + +### Instance ConfigManager object + +```php +use clagiordano\weblibs\configmanager\ConfigManager; + +/** + * Instance object to read argument file + */ +$config = new ConfigManager("configfile.php"); +``` + +### Check if a value exists into config file + +```php +/** + * Check if a value exists into config file + */ +$value = $config->existValue('app'); +``` + +### Read a simple element from config file + +```php +/** + * Read a simple element from config file + */ +$value = $config->getValue('app'); +``` + +### Access to a nested element from config + +```php +/** + * Access to a nested element from config + */ +$nestedValue = $config->getValue('other.multi.deep.nested'); +``` + +### Change config value at runtime + +```php +/** + * Change config value at runtime + */ +$this->config->setValue('other.multi.deep.nested', "SUPERNESTED"); +``` + +### Save config file with original name (OVERWRITE) + +```php +/** + * Save config file with original name (OVERWRITE) + */ +$this->config->saveConfigFile(); +``` + +### Or save config file with a different name + +```php +/** + * Save config file with original name (OVERWRITE) + */ +$this->config->saveConfigFile('/new/file/name/or/path/test.php'); +``` + +### Optionally you can also reload config file from disk after save + +```php +/** + * Optionally you can also reload config file from disk after save + */ +$this->config->saveConfigFile('/new/file/name/or/path/test.php', true); +``` + +### Load another configuration file without reinstance ConfigManager + +```php +/** + * Load another configuration file without reinstance ConfigManager + */ +$this->config->loadConfig('another_config_file.php'); +``` + +## Legal +*Copyright (C) Claudio Giordano * diff --git a/vendor/clagiordano/weblibs-configmanager/composer.json b/vendor/clagiordano/weblibs-configmanager/composer.json new file mode 100644 index 0000000..c159048 --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/composer.json @@ -0,0 +1,48 @@ +{ + "name": "clagiordano/weblibs-configmanager", + "description": "weblibs-configmanager is a tool library for easily read and access to php config array file and direct read/write configuration file / object", + "type": "library", + "license": "LGPL-3.0-or-later", + "keywords": ["clagiordano", "weblibs", "configuration", "manager", "tool"], + "authors": [ + { + "name": "Claudio Giordano", + "email": "claudio.giordano@autistici.org", + "role": "Developer" + } + ], + "autoload": { + "psr-4": { + "clagiordano\\weblibs\\configmanager\\": "src/" + } + }, + "require": { + "php": ">=5.4" + }, + "require-dev": { + "phpunit/phpunit": "^4.8", + "clagiordano/phpunit-result-printer": "^1" + }, + "autoload-dev": { + "psr-4": { + "clagiordano\\weblibs\\configmanager\\tests\\": "tests/", + "clagiordano\\weblibs\\configmanager\\testdata\\": "testdata/" + } + }, + "scripts": { + "test": [ + "Composer\\Config::disableProcessTimeout", + "./vendor/bin/phpunit --no-coverage" + ], + "coverage": [ + "Composer\\Config::disableProcessTimeout", + "php -dzend_extension=xdebug.so ./vendor/bin/phpunit" + ], + "debug": "php -dxdebug.remote_autostart=On -dzend_extension=xdebug.so ./vendor/bin/phpunit" + }, + "config": { + "platform": { + "php": "5.4" + } + } +} diff --git a/vendor/clagiordano/weblibs-configmanager/composer.lock b/vendor/clagiordano/weblibs-configmanager/composer.lock new file mode 100644 index 0000000..d306da0 --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/composer.lock @@ -0,0 +1,1095 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "6d2aba6439fb7be37e7120eed3311f56", + "packages": [], + "packages-dev": [ + { + "name": "clagiordano/phpunit-result-printer", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/clagiordano/phpunit-result-printer.git", + "reference": "b4351f747af7964bcdb1cc0d1aa9fe007022b3ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clagiordano/phpunit-result-printer/zipball/b4351f747af7964bcdb1cc0d1aa9fe007022b3ac", + "reference": "b4351f747af7964bcdb1cc0d1aa9fe007022b3ac", + "shasum": "" + }, + "require": { + "phpunit/phpunit": "4.8.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "clagiordano\\PhpunitResultPrinter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Phpunit custom result printer class", + "time": "2019-07-16T10:33:26+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/e6a969a640b00d8daa3c66518b0405fb41ae0c4b", + "reference": "e6a969a640b00d8daa3c66518b0405fb41ae0c4b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2016-01-25T08:17:30+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.10.3", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "451c3cd1418cf640de218914901e51b064abb093" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5 || ^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2020-03-05T15:02:03+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06T15:47:00+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2017-11-27T13:52:08+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.12", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2017-12-04T08:55:13+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.36", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.2.2", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.8.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2017-06-21T08:07:12+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "abandoned": true, + "time": "2015-10-02T06:51:40+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2017-05-22T07:24:03+00:00" + }, + { + "name": "sebastian/environment", + "version": "1.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-08-18T05:49:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-06-17T09:04:28+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2016-10-03T07:41:43+00:00" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21T13:59:46+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.19.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/aed596913b70fae57be53d86faa2e9ef85a2297b", + "reference": "aed596913b70fae57be53d86faa2e9ef85a2297b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.19-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-10-23T09:01:57+00:00" + }, + { + "name": "symfony/yaml", + "version": "v2.8.52", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "02c1859112aa779d9ab394ae4f3381911d84052b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/02c1859112aa779d9ab394ae4f3381911d84052b", + "reference": "02c1859112aa779d9ab394ae4f3381911d84052b", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/polyfill-ctype": "~1.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2018-11-11T11:18:13+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.4" + }, + "platform-dev": [], + "platform-overrides": { + "php": "5.4" + }, + "plugin-api-version": "1.1.0" +} diff --git a/vendor/clagiordano/weblibs-configmanager/phpunit.xml b/vendor/clagiordano/weblibs-configmanager/phpunit.xml new file mode 100644 index 0000000..4383135 --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/phpunit.xml @@ -0,0 +1,39 @@ + + + + + ./tests/ + + + + + + src/ + + + + + + + + + + + + + + + + + diff --git a/vendor/clagiordano/weblibs-configmanager/src/ConfigManager.php b/vendor/clagiordano/weblibs-configmanager/src/ConfigManager.php new file mode 100644 index 0000000..9db1d62 --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/src/ConfigManager.php @@ -0,0 +1,161 @@ +loadConfig($configFilePath); + } + + /** + * Load config data from file and store it into internal property + * + * @param null|string $configFilePath + * + * @return IConfigurable + */ + public function loadConfig($configFilePath = null) + { + if (!is_null($configFilePath)) { + $this->configFilePath = $configFilePath; + + if (file_exists($configFilePath)) { + $this->configData = require $configFilePath; + } + } + + return $this; + } + + /** + * Prepare and write config file on disk + * + * @param null|string $configFilePath + * @param bool $autoReloadConfig + * + * @return IConfigurable + * @throws RuntimeException + */ + public function saveConfigFile($configFilePath = null, $autoReloadConfig = false) + { + if (is_null($configFilePath)) { + $configFilePath = $this->configFilePath; + } + + $configFileContent = "configData, true); + $configFileContent .= ";\n\n"; + + try { + file_put_contents($configFilePath, $configFileContent); + + if (is_callable('opcache_invalidate')) { + /** + * Invalidate opcache for writed file if opcache is available + */ + opcache_invalidate($configFilePath, true); + } + } catch (Exception $exc) { + throw new RuntimeException( + __METHOD__ . ": Failed to write config file to path '{$configFilePath}'" + ); + } + + if ($autoReloadConfig) { + $this->loadConfig($configFilePath); + } + + return $this; + } + + /** + * Get value pointer from config for get/set value + * + * @param string $configPath + * + * @return mixed + */ + private function & getValuePointer($configPath) + { + $configData =& $this->configData; + $parts = explode('.', $configPath); + $length = count($parts); + + for ($i = 0; $i < $length; $i++) { + if (!isset($configData[ $parts[ $i ] ])) { + $configData[ $parts[ $i ] ] = ($i === $length) ? [] : null; + } + + $configData = &$configData[ $parts[ $i ] ]; + } + + return $configData; + } + + /** + * Get value from config data throught keyValue path + * + * @param string $configPath + * @param mixed $defaultValue + * + * @return mixed + */ + public function getValue($configPath, $defaultValue = null) + { + $stored = $this->getValuePointer($configPath); + + return (is_null($stored) + ? $defaultValue + : $stored); + } + + /** + * Check if exist required config for keyValue + * + * @param string $keyValue + * + * @return mixed + */ + public function existValue($keyValue) + { + return !is_null($this->getValue($keyValue)); + } + + /** + * Set value in config path + * + * @param string $configPath + * @param mixed $newValue + * + * @return IConfigurable + */ + public function setValue($configPath, $newValue) + { + $configData = &$this->getValuePointer($configPath); + $configData = $newValue; + + return $this; + } +} diff --git a/vendor/clagiordano/weblibs-configmanager/src/IConfigurable.php b/vendor/clagiordano/weblibs-configmanager/src/IConfigurable.php new file mode 100644 index 0000000..7ca8d6d --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/src/IConfigurable.php @@ -0,0 +1,61 @@ +config = new ConfigManager("TestConfigData.php"); + $this->assertInstanceOf('clagiordano\weblibs\configmanager\ConfigManager', $this->config); + + $this->assertFileExists($this->configFile); + $this->config->loadConfig($this->configFile); + } + + public function testBasicUsage() + { + $this->assertNotNull( + $this->config->getValue('app') + ); + } + + public function testFastUsage() + { + $this->assertNotNull( + $this->config->getValue('app') + ); + } + + public function testFastInvalidKey() + { + $this->assertNull( + $this->config->getValue('invalidKey') + ); + } + + public function testFastInvalidKeyWithDefault() + { + $this->assertEquals( + $this->config->getValue('invalidKey', 'defaultValue'), + 'defaultValue' + ); + } + + public function testFastNestedConfig() + { + $this->assertNotNull( + $this->config->getValue('other.multi.deep.nested') + ); + } + + public function testCheckExistConfig() + { + $this->assertTrue( + $this->config->existValue('other.multi.deep.nested') + ); + } + + public function testCheckNotExistConfig() + { + $this->assertFalse( + $this->config->existValue('invalid.config.path') + ); + } + + public function testSetValue() + { + $this->config->setValue('other.multi.deep.nested', __FUNCTION__); + + $this->assertEquals( + $this->config->getValue('other.multi.deep.nested'), + __FUNCTION__ + ); + } + + public function testFailedSaveConfig() + { + $this->setExpectedException('Exception'); + $this->config->saveConfigFile('/invalid/path'); + } + + public function testSuccessSaveConfigOnTempAndReload() + { + $this->config->setValue('other.multi.deep.nested', "SUPERNESTED"); + $this->config->saveConfigFile("/tmp/testconfig.php", true); + + $this->assertEquals( + $this->config->getValue('other.multi.deep.nested'), + "SUPERNESTED" + ); + } + + public function testOverwriteSameConfigFile() + { + $this->config->saveConfigFile(); + } + + public function testFailWriteConfig() + { + $this->setExpectedException('\RuntimeException'); + $this->config->saveConfigFile('/invalid/path/test.php'); + } +} \ No newline at end of file diff --git a/vendor/clagiordano/weblibs-configmanager/testsdata/sample_config_data.php b/vendor/clagiordano/weblibs-configmanager/testsdata/sample_config_data.php new file mode 100644 index 0000000..4a99ef0 --- /dev/null +++ b/vendor/clagiordano/weblibs-configmanager/testsdata/sample_config_data.php @@ -0,0 +1,23 @@ + 'app_name', + 'db' => + array ( + 'host' => 'localhost', + 'user' => 'sample_user', + 'pass' => 'sample_pass', + 'port' => 3306, + ), + 'other' => + array ( + 'multi' => + array ( + 'deep' => + array ( + 'nested' => 'config_value', + ), + ), + ), +); + diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php new file mode 100644 index 0000000..7824d8f --- /dev/null +++ b/vendor/composer/ClassLoader.php @@ -0,0 +1,579 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ + private $prefixesPsr0 = array(); + /** + * @var list + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..51e734a --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,359 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } + + return $installed; + } +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..730bac1 --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,15 @@ + $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => $vendorDir . '/myclabs/php-enum/stubs/Stringable.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', +); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php new file mode 100644 index 0000000..3fddb9b --- /dev/null +++ b/vendor/composer/autoload_files.php @@ -0,0 +1,24 @@ + $vendorDir . '/topthink/think-helper/src/helper.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', + '35fab96057f1bf5e7aba31a8a6d5fdde' => $vendorDir . '/topthink/think-orm/stubs/load_stubs.php', + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', + '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', + 'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php', + 'd767e4fc2dc52fe66584ab8c6684783e' => $vendorDir . '/adbario/php-dot-notation/src/helpers.php', + '2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php', + 'b067bc7112e384b61c701452d53a14a8' => $vendorDir . '/mtdowling/jmespath.php/src/JmesPath.php', + '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', + '66453932bc1be9fb2f910a27947d11b6' => $vendorDir . '/alibabacloud/client/src/Functions.php', + '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', + 'cc56288302d9df745d97c934d6a6e5f0' => $vendorDir . '/topthink/think-queue/src/common.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..e05fdeb --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,11 @@ + array($vendorDir . '/ezyang/htmlpurifier/library'), + '' => array($baseDir . '/extend'), +); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php new file mode 100644 index 0000000..1f0d316 --- /dev/null +++ b/vendor/composer/autoload_psr4.php @@ -0,0 +1,57 @@ + array($vendorDir . '/topthink/think-trace/src'), + 'think\\app\\' => array($vendorDir . '/topthink/think-multi-app/src'), + 'think\\' => array($vendorDir . '/topthink/think-helper/src', $vendorDir . '/topthink/think-orm/src', $vendorDir . '/topthink/framework/src/think', $vendorDir . '/topthink/think-filesystem/src', $vendorDir . '/topthink/think-queue/src'), + 'phpDocumentor\\Reflection\\' => array($vendorDir . '/phpdocumentor/reflection-common/src', $vendorDir . '/phpdocumentor/type-resolver/src', $vendorDir . '/phpdocumentor/reflection-docblock/src'), + 'itinysun\\model\\helper\\' => array($vendorDir . '/itinysun/tp-model-helper/src'), + 'clagiordano\\weblibs\\configmanager\\' => array($vendorDir . '/clagiordano/weblibs-configmanager/src'), + 'app\\' => array($baseDir . '/app'), + 'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'), + 'Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'), + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), + 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), + 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), + 'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'), + 'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'), + 'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'), + 'Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'), + 'Symfony\\Component\\ClassLoader\\' => array($vendorDir . '/symfony/class-loader'), + 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), + 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'), + 'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'), + 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), + 'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'), + 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'), + 'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'), + 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), + 'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'), + 'MaxMind\\WebService\\' => array($vendorDir . '/maxmind/web-service-common/src/WebService'), + 'MaxMind\\Exception\\' => array($vendorDir . '/maxmind/web-service-common/src/Exception'), + 'MaxMind\\Db\\' => array($vendorDir . '/maxmind-db/reader/src/MaxMind/Db'), + 'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'), + 'League\\MimeTypeDetection\\' => array($vendorDir . '/league/mime-type-detection/src'), + 'League\\Flysystem\\Cached\\' => array($vendorDir . '/league/flysystem-cached-adapter/src'), + 'League\\Flysystem\\' => array($vendorDir . '/league/flysystem/src'), + 'Lcobucci\\JWT\\' => array($vendorDir . '/lcobucci/jwt/src'), + 'Lcobucci\\Clock\\' => array($vendorDir . '/lcobucci/clock/src'), + 'JmesPath\\' => array($vendorDir . '/mtdowling/jmespath.php/src'), + 'GuzzleHttp\\Psr7\\' => array($vendorDir . '/guzzlehttp/psr7/src'), + 'GuzzleHttp\\Promise\\' => array($vendorDir . '/guzzlehttp/promises/src'), + 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), + 'GeoIp2\\' => array($vendorDir . '/geoip2/geoip2/src'), + 'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'), + 'Composer\\CaBundle\\' => array($vendorDir . '/composer/ca-bundle/src'), + 'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'), + 'Carbon\\Doctrine\\' => array($vendorDir . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine'), + 'Carbon\\' => array($vendorDir . '/nesbot/carbon/src/Carbon'), + 'AlibabaCloud\\Client\\' => array($vendorDir . '/alibabacloud/client/src'), + 'Adbar\\' => array($vendorDir . '/adbario/php-dot-notation/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000..a1a28f0 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,50 @@ +register(true); + + $filesToLoad = \Composer\Autoload\ComposerStaticInit1a568d2f898357e67a9223da2d6c2877::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); + } + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000..dfa8e6f --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,362 @@ + __DIR__ . '/..' . '/topthink/think-helper/src/helper.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + '35fab96057f1bf5e7aba31a8a6d5fdde' => __DIR__ . '/..' . '/topthink/think-orm/stubs/load_stubs.php', + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', + '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', + 'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php', + 'd767e4fc2dc52fe66584ab8c6684783e' => __DIR__ . '/..' . '/adbario/php-dot-notation/src/helpers.php', + '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', + '37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php', + 'b067bc7112e384b61c701452d53a14a8' => __DIR__ . '/..' . '/mtdowling/jmespath.php/src/JmesPath.php', + '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', + '66453932bc1be9fb2f910a27947d11b6' => __DIR__ . '/..' . '/alibabacloud/client/src/Functions.php', + '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', + 'cc56288302d9df745d97c934d6a6e5f0' => __DIR__ . '/..' . '/topthink/think-queue/src/common.php', + ); + + public static $prefixLengthsPsr4 = array ( + 't' => + array ( + 'think\\trace\\' => 12, + 'think\\app\\' => 10, + 'think\\' => 6, + ), + 'p' => + array ( + 'phpDocumentor\\Reflection\\' => 25, + ), + 'i' => + array ( + 'itinysun\\model\\helper\\' => 22, + ), + 'c' => + array ( + 'clagiordano\\weblibs\\configmanager\\' => 34, + ), + 'a' => + array ( + 'app\\' => 4, + ), + 'Z' => + array ( + 'ZipStream\\' => 10, + ), + 'W' => + array ( + 'Webmozart\\Assert\\' => 17, + ), + 'S' => + array ( + 'Symfony\\Polyfill\\Php80\\' => 23, + 'Symfony\\Polyfill\\Php72\\' => 23, + 'Symfony\\Polyfill\\Mbstring\\' => 26, + 'Symfony\\Contracts\\Translation\\' => 30, + 'Symfony\\Component\\VarDumper\\' => 28, + 'Symfony\\Component\\Translation\\' => 30, + 'Symfony\\Component\\Process\\' => 26, + 'Symfony\\Component\\ClassLoader\\' => 30, + ), + 'P' => + array ( + 'Psr\\SimpleCache\\' => 16, + 'Psr\\Log\\' => 8, + 'Psr\\Http\\Message\\' => 17, + 'Psr\\Http\\Client\\' => 16, + 'Psr\\Container\\' => 14, + 'Psr\\Clock\\' => 10, + 'Psr\\Cache\\' => 10, + 'PhpOffice\\PhpSpreadsheet\\' => 25, + 'PHPMailer\\PHPMailer\\' => 20, + ), + 'M' => + array ( + 'MyCLabs\\Enum\\' => 13, + 'MaxMind\\WebService\\' => 19, + 'MaxMind\\Exception\\' => 18, + 'MaxMind\\Db\\' => 11, + 'Matrix\\' => 7, + ), + 'L' => + array ( + 'League\\MimeTypeDetection\\' => 25, + 'League\\Flysystem\\Cached\\' => 24, + 'League\\Flysystem\\' => 17, + 'Lcobucci\\JWT\\' => 13, + 'Lcobucci\\Clock\\' => 15, + ), + 'J' => + array ( + 'JmesPath\\' => 9, + ), + 'G' => + array ( + 'GuzzleHttp\\Psr7\\' => 16, + 'GuzzleHttp\\Promise\\' => 19, + 'GuzzleHttp\\' => 11, + 'GeoIp2\\' => 7, + ), + 'F' => + array ( + 'Firebase\\JWT\\' => 13, + ), + 'C' => + array ( + 'Composer\\CaBundle\\' => 18, + 'Complex\\' => 8, + 'Carbon\\Doctrine\\' => 16, + 'Carbon\\' => 7, + ), + 'A' => + array ( + 'AlibabaCloud\\Client\\' => 20, + 'Adbar\\' => 6, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'think\\trace\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/think-trace/src', + ), + 'think\\app\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/think-multi-app/src', + ), + 'think\\' => + array ( + 0 => __DIR__ . '/..' . '/topthink/think-helper/src', + 1 => __DIR__ . '/..' . '/topthink/think-orm/src', + 2 => __DIR__ . '/..' . '/topthink/framework/src/think', + 3 => __DIR__ . '/..' . '/topthink/think-filesystem/src', + 4 => __DIR__ . '/..' . '/topthink/think-queue/src', + ), + 'phpDocumentor\\Reflection\\' => + array ( + 0 => __DIR__ . '/..' . '/phpdocumentor/reflection-common/src', + 1 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src', + 2 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src', + ), + 'itinysun\\model\\helper\\' => + array ( + 0 => __DIR__ . '/..' . '/itinysun/tp-model-helper/src', + ), + 'clagiordano\\weblibs\\configmanager\\' => + array ( + 0 => __DIR__ . '/..' . '/clagiordano/weblibs-configmanager/src', + ), + 'app\\' => + array ( + 0 => __DIR__ . '/../..' . '/app', + ), + 'ZipStream\\' => + array ( + 0 => __DIR__ . '/..' . '/maennchen/zipstream-php/src', + ), + 'Webmozart\\Assert\\' => + array ( + 0 => __DIR__ . '/..' . '/webmozart/assert/src', + ), + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), + 'Symfony\\Polyfill\\Php72\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', + ), + 'Symfony\\Polyfill\\Mbstring\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', + ), + 'Symfony\\Contracts\\Translation\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/translation-contracts', + ), + 'Symfony\\Component\\VarDumper\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/var-dumper', + ), + 'Symfony\\Component\\Translation\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/translation', + ), + 'Symfony\\Component\\Process\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/process', + ), + 'Symfony\\Component\\ClassLoader\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/class-loader', + ), + 'Psr\\SimpleCache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/simple-cache/src', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', + ), + 'Psr\\Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-message/src', + 1 => __DIR__ . '/..' . '/psr/http-factory/src', + ), + 'Psr\\Http\\Client\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-client/src', + ), + 'Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), + 'Psr\\Clock\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/clock/src', + ), + 'Psr\\Cache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/cache/src', + ), + 'PhpOffice\\PhpSpreadsheet\\' => + array ( + 0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet', + ), + 'PHPMailer\\PHPMailer\\' => + array ( + 0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src', + ), + 'MyCLabs\\Enum\\' => + array ( + 0 => __DIR__ . '/..' . '/myclabs/php-enum/src', + ), + 'MaxMind\\WebService\\' => + array ( + 0 => __DIR__ . '/..' . '/maxmind/web-service-common/src/WebService', + ), + 'MaxMind\\Exception\\' => + array ( + 0 => __DIR__ . '/..' . '/maxmind/web-service-common/src/Exception', + ), + 'MaxMind\\Db\\' => + array ( + 0 => __DIR__ . '/..' . '/maxmind-db/reader/src/MaxMind/Db', + ), + 'Matrix\\' => + array ( + 0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src', + ), + 'League\\MimeTypeDetection\\' => + array ( + 0 => __DIR__ . '/..' . '/league/mime-type-detection/src', + ), + 'League\\Flysystem\\Cached\\' => + array ( + 0 => __DIR__ . '/..' . '/league/flysystem-cached-adapter/src', + ), + 'League\\Flysystem\\' => + array ( + 0 => __DIR__ . '/..' . '/league/flysystem/src', + ), + 'Lcobucci\\JWT\\' => + array ( + 0 => __DIR__ . '/..' . '/lcobucci/jwt/src', + ), + 'Lcobucci\\Clock\\' => + array ( + 0 => __DIR__ . '/..' . '/lcobucci/clock/src', + ), + 'JmesPath\\' => + array ( + 0 => __DIR__ . '/..' . '/mtdowling/jmespath.php/src', + ), + 'GuzzleHttp\\Psr7\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/psr7/src', + ), + 'GuzzleHttp\\Promise\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/promises/src', + ), + 'GuzzleHttp\\' => + array ( + 0 => __DIR__ . '/..' . '/guzzlehttp/guzzle/src', + ), + 'GeoIp2\\' => + array ( + 0 => __DIR__ . '/..' . '/geoip2/geoip2/src', + ), + 'Firebase\\JWT\\' => + array ( + 0 => __DIR__ . '/..' . '/firebase/php-jwt/src', + ), + 'Composer\\CaBundle\\' => + array ( + 0 => __DIR__ . '/..' . '/composer/ca-bundle/src', + ), + 'Complex\\' => + array ( + 0 => __DIR__ . '/..' . '/markbaker/complex/classes/src', + ), + 'Carbon\\Doctrine\\' => + array ( + 0 => __DIR__ . '/..' . '/carbonphp/carbon-doctrine-types/src/Carbon/Doctrine', + ), + 'Carbon\\' => + array ( + 0 => __DIR__ . '/..' . '/nesbot/carbon/src/Carbon', + ), + 'AlibabaCloud\\Client\\' => + array ( + 0 => __DIR__ . '/..' . '/alibabacloud/client/src', + ), + 'Adbar\\' => + array ( + 0 => __DIR__ . '/..' . '/adbario/php-dot-notation/src', + ), + ); + + public static $prefixesPsr0 = array ( + 'H' => + array ( + 'HTMLPurifier' => + array ( + 0 => __DIR__ . '/..' . '/ezyang/htmlpurifier/library', + ), + ), + ); + + public static $fallbackDirsPsr0 = array ( + 0 => __DIR__ . '/../..' . '/extend', + ); + + public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => __DIR__ . '/..' . '/myclabs/php-enum/stubs/Stringable.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit1a568d2f898357e67a9223da2d6c2877::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit1a568d2f898357e67a9223da2d6c2877::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInit1a568d2f898357e67a9223da2d6c2877::$prefixesPsr0; + $loader->fallbackDirsPsr0 = ComposerStaticInit1a568d2f898357e67a9223da2d6c2877::$fallbackDirsPsr0; + $loader->classMap = ComposerStaticInit1a568d2f898357e67a9223da2d6c2877::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/ca-bundle/LICENSE b/vendor/composer/ca-bundle/LICENSE new file mode 100644 index 0000000..c5b5220 --- /dev/null +++ b/vendor/composer/ca-bundle/LICENSE @@ -0,0 +1,19 @@ +Copyright (C) 2016 Composer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/composer/ca-bundle/README.md b/vendor/composer/ca-bundle/README.md new file mode 100644 index 0000000..d8205ec --- /dev/null +++ b/vendor/composer/ca-bundle/README.md @@ -0,0 +1,85 @@ +composer/ca-bundle +================== + +Small utility library that lets you find a path to the system CA bundle, +and includes a fallback to the Mozilla CA bundle. + +Originally written as part of [composer/composer](https://github.com/composer/composer), +now extracted and made available as a stand-alone library. + + +Installation +------------ + +Install the latest version with: + +```bash +$ composer require composer/ca-bundle +``` + + +Requirements +------------ + +* PHP 5.3.2 is required but using the latest version of PHP is highly recommended. + + +Basic usage +----------- + +### `Composer\CaBundle\CaBundle` + +- `CaBundle::getSystemCaRootBundlePath()`: Returns the system CA bundle path, or a path to the bundled one as fallback +- `CaBundle::getBundledCaBundlePath()`: Returns the path to the bundled CA file +- `CaBundle::validateCaFile($filename)`: Validates a CA file using openssl_x509_parse only if it is safe to use +- `CaBundle::isOpensslParseSafe()`: Test if it is safe to use the PHP function openssl_x509_parse() +- `CaBundle::reset()`: Resets the static caches + + +#### To use with curl + +```php +$curl = curl_init("https://example.org/"); + +$caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(); +if (is_dir($caPathOrFile)) { + curl_setopt($curl, CURLOPT_CAPATH, $caPathOrFile); +} else { + curl_setopt($curl, CURLOPT_CAINFO, $caPathOrFile); +} + +$result = curl_exec($curl); +``` + +#### To use with php streams + +```php +$opts = array( + 'http' => array( + 'method' => "GET" + ) +); + +$caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(); +if (is_dir($caPathOrFile)) { + $opts['ssl']['capath'] = $caPathOrFile; +} else { + $opts['ssl']['cafile'] = $caPathOrFile; +} + +$context = stream_context_create($opts); +$result = file_get_contents('https://example.com', false, $context); +``` + +#### To use with Guzzle + +```php +$client = new \GuzzleHttp\Client([ + \GuzzleHttp\RequestOptions::VERIFY => \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath() +]); +``` + +License +------- + +composer/ca-bundle is licensed under the MIT License, see the LICENSE file for details. diff --git a/vendor/composer/ca-bundle/composer.json b/vendor/composer/ca-bundle/composer.json new file mode 100644 index 0000000..a998783 --- /dev/null +++ b/vendor/composer/ca-bundle/composer.json @@ -0,0 +1,54 @@ +{ + "name": "composer/ca-bundle", + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "type": "library", + "license": "MIT", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.2 || ^5", + "phpstan/phpstan": "^1.10", + "psr/log": "^1.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Composer\\CaBundle\\": "tests" + } + }, + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "scripts": { + "test": "vendor/bin/simple-phpunit", + "phpstan": "vendor/bin/phpstan analyse" + } +} diff --git a/vendor/composer/ca-bundle/res/cacert.pem b/vendor/composer/ca-bundle/res/cacert.pem new file mode 100644 index 0000000..f78a610 --- /dev/null +++ b/vendor/composer/ca-bundle/res/cacert.pem @@ -0,0 +1,3581 @@ +## +## Bundle of CA Root Certificates +## +## Certificate data from Mozilla as of: Mon Mar 11 15:25:27 2024 GMT +## +## This is a bundle of X.509 certificates of public Certificate Authorities +## (CA). These were automatically extracted from Mozilla's root certificates +## file (certdata.txt). This file can be found in the mozilla source tree: +## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt +## +## It contains the certificates in PEM format and therefore +## can be directly used with curl / libcurl / php_curl, or with +## an Apache+mod_ssl webserver for SSL client authentication. +## Just configure this file as the SSLCACertificateFile. +## +## Conversion done with mk-ca-bundle.pl version 1.29. +## SHA256: 4d96bd539f4719e9ace493757afbe4a23ee8579de1c97fbebc50bba3c12e8c1e +## + + +GlobalSign Root CA +================== +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx +GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds +b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD +VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa +DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc +THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb +Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP +c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX +gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF +AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj +Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG +j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH +hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC +X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +Entrust.net Premium 2048 Secure Server CA +========================================= +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp +bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV +BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl +MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u +ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL +Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr +hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW +nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +Baltimore CyberTrust Root +========================= +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE +ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li +ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC +SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs +dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME +uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB +UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C +G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 +XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr +l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI +VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB +BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh +cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 +hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa +Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H +RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +Entrust Root Certification Authority +==================================== +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw +b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG +A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 +MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu +MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu +Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v +dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz +A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww +Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 +j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN +rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 +MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH +hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM +Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa +v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS +W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 +tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +Comodo AAA Services root +======================== +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS +R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg +TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw +MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl +c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV +BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG +C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs +i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW +Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH +Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK +Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f +BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl +cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz +LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm +7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z +8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C +12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +QuoVadis Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx +ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 +XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk +lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB +lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy +lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt +66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn +wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh +D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy +BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie +J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud +DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU +a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv +Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 +UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm +VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK ++JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW +IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 +WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X +f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II +4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 +VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +QuoVadis Root CA 3 +================== +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT +EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx +OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg +DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij +KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K +DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv +BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp +p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 +nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX +MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM +Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz +uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT +BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj +YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB +BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 +ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE +AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV +qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s +hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z +POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 +Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp +8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC +bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu +g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p +vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr +qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +XRamp Global CA Root +==================== +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE +BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj +dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx +HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg +U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp +dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu +IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx +foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE +zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs +AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry +xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap +oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC +AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc +/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n +nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz +8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +Go Daddy Class 2 CA +=================== +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY +VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG +A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g +RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD +ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv +2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 +qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j +YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY +vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O +BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o +atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu +MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG +A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim +PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt +I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI +Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b +vZ8= +-----END CERTIFICATE----- + +Starfield Class 2 CA +==================== +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc +U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo +MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG +A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG +SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY +bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ +JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm +epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN +F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF +MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f +hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo +bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g +QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs +afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM +PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD +KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 +QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +DigiCert Assured ID Root CA +=========================== +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx +MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO +9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy +UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW +/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy +oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf +GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF +66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq +hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc +EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn +SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i +8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +DigiCert Global Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw +MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn +TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 +BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H +4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y +7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB +o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm +8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF +BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr +EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt +tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 +UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +DigiCert High Assurance EV Root CA +================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw +KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw +MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ +MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu +Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t +Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS +OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 +MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ +NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe +h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY +JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ +V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp +myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK +mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K +-----END CERTIFICATE----- + +SwissSign Gold CA - G2 +====================== +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw +EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN +MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp +c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq +t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C +jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg +vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF +ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR +AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend +jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO +peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR +7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi +GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 +OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm +5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr +44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf +Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m +Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp +mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk +vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf +KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br +NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj +viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- + +SwissSign Silver CA - G2 +======================== +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT +BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X +DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 +aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 +N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm ++/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH +6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu +MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h +qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 +FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs +ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc +celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X +CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB +tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P +4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F +kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L +3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx +/uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa +DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP +e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu +WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ +DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub +DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +SecureTrust CA +============== +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy +dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe +BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX +OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t +DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH +GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b +01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH +ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj +aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ +KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu +SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf +mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ +nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +Secure Global CA +================ +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG +EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH +bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg +MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx +YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ +bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g +8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV +HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi +0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn +oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA +MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ +OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn +CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 +3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +COMODO Certification Authority +============================== +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb +MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD +T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH ++7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww +xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV +4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA +1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI +rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k +b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC +AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP +OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc +IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN ++8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== +-----END CERTIFICATE----- + +COMODO ECC Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix +GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X +4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni +wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG +FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA +U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +Certigna +======== +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw +EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 +MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI +Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q +XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH +GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p +ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg +DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf +Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ +tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ +BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J +SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA +hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ +ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu +PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY +1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +ePKI Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx +MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq +MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs +IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi +lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv +qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX +12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O +WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ +ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao +lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ +vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi +Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi +MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 +1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq +KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV +xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP +NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r +GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE +xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx +gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy +sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD +BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +certSIGN ROOT CA +================ +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD +VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa +Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE +CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I +JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH +rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 +ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD +0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 +AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B +Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB +AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 +SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 +x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt +vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz +TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +NetLock Arany (Class Gold) Főtanúsítvány +======================================== +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G +A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 +dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB +cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx +MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO +ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv +biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 +c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu +0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw +/HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk +H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw +fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 +neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW +qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta +YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna +NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu +dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +SecureSign RootCA11 +=================== +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi +SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS +b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw +KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 +cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL +TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO +wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq +g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP +O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA +bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX +t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh +OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r +bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ +Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 +y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 +lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +Microsec e-Szigno Root CA 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER +MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv +c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE +BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt +U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA +fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG +0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA +pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm +1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC +AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf +QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE +FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o +lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX +I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 +yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi +LXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +GlobalSign Root CA - R3 +======================= +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv +YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh +bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT +aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln +bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt +iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ +0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 +rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl +OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 +xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 +lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 +EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E +bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 +YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r +kpeDMdmztcpHWD9f +-----END CERTIFICATE----- + +Izenpe.com +========== +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG +EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz +MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu +QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ +03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK +ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU ++zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC +PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT +OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK +F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK +0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ +0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB +leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID +AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ +SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG +NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l +Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga +kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q +hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs +g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 +aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 +nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC +ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo +Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z +WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- + +Go Daddy Root Certificate Authority - G2 +======================================== +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu +MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G +A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq +9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD ++qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd +fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl +NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 +BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac +vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r +5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV +N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 +-----END CERTIFICATE----- + +Starfield Root Certificate Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw +DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg +VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB +dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv +W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs +bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk +N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf +ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU +JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol +TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx +4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw +F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ +c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +Starfield Services Root Certificate Authority - G2 +================================================== +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT +B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s +b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl +IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT +dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 +h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa +hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP +LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB +rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG +SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP +E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy +xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza +YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 +-----END CERTIFICATE----- + +AffirmTrust Commercial +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw +MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb +DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV +C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 +BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww +MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV +HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG +hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi +qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv +0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh +sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +AffirmTrust Networking +====================== +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw +MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly +bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE +Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI +dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 +/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb +h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV +HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu +UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 +12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 +WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 +/ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +AffirmTrust Premium +=================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS +BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy +OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy +dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn +BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV +5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs ++7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd +GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R +p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI +S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 +6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 +/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo ++Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv +MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC +6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S +L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK ++4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV +BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg +IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 +g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb +zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== +-----END CERTIFICATE----- + +AffirmTrust Premium ECC +======================= +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV +BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx +MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U +cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ +N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW +BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK +BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X +57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM +eQ== +-----END CERTIFICATE----- + +Certum Trusted Network CA +========================= +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK +ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy +MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU +ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC +l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J +J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 +fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 +cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB +Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw +DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj +jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 +mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj +Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +TWCA Root Certification Authority +================================= +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ +VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG +EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB +IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx +QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC +oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP +4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r +y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG +9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC +mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW +QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY +T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny +Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +Security Communication RootCA2 +============================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh +dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC +SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy +aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ ++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R +3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV +spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K +EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 +QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB +CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj +u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk +3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q +tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 +mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +Actalis Authentication Root CA +============================== +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM +BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE +AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky +MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz +IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ +wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa +by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 +zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f +YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 +oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l +EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 +hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 +EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 +jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY +iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI +WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 +JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx +K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ +Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC +4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo +2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz +lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem +OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 +vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +Buypass Class 2 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X +DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 +g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn +9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b +/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU +CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff +awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI +zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn +Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX +Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs +M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI +osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S +aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd +DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD +LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 +oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC +wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS +CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN +rJgWVqA= +-----END CERTIFICATE----- + +Buypass Class 3 Root CA +======================= +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU +QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X +DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 +eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH +sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR +5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh +7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ +ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH +2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV +/afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ +RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA +Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq +j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF +AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G +uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG +Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 +ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 +KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz +6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug +UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe +eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi +Cp/HuZc= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 3 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx +MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK +9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU +NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF +iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W +0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr +AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb +fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT +ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h +P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- + +TeliaSonera Root CA v1 +====================== +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE +CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 +MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW +VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ +6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA +3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k +B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn +Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH +oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 +F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ +oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 +gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc +TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB +AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW +DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm +zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW +pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV +G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc +c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT +JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 +qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 +Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems +WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +T-TeleSec GlobalRoot Class 2 +============================ +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM +IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU +cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx +MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz +dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD +ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ +SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F +vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 +2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV +WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy +YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 +r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf +vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR +3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== +-----END CERTIFICATE----- + +Atos TrustedRoot 2011 +===================== +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU +cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 +MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG +A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV +hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr +54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ +DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 +HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR +z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R +l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ +bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h +k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh +TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 +61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G +3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +QuoVadis Root CA 1 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE +PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm +PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 +Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN +ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l +g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV +7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX +9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f +iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg +t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI +hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 +GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct +Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP ++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh +3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa +wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 +O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 +FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV +hMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +QuoVadis Root CA 2 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh +ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY +NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t +oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o +MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l +V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo +L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ +sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD +6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh +lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI +hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K +pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 +x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz +dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X +U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw +mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD +zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN +JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr +O3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +QuoVadis Root CA 3 G3 +===================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG +A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv +b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN +MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg +RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 +IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL +Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe +6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 +I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U +VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 +5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi +Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM +dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt +rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI +hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS +t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ +TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du +DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib +Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD +hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX +0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW +dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 +PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +DigiCert Assured ID Root G2 +=========================== +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw +IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw +MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL +ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH +35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq +bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw +VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP +YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn +lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO +w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv +0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz +d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW +hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M +jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +DigiCert Assured ID Root G3 +=========================== +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD +VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb +RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs +KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF +UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy +YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy +1vUhZscv6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +DigiCert Global Root G2 +======================= +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw +HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx +MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 +dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ +kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO +3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV +BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM +UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu +5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr +F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U +WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH +QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ +iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +DigiCert Global Root G3 +======================= +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD +VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw +MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k +aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C +AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O +YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp +Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y +3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 +VOKa5Vt8sycX +-----END CERTIFICATE----- + +DigiCert Trusted Root G4 +======================== +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw +HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 +MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp +pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o +k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa +vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY +QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 +MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm +mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 +f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH +dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 +oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY +ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr +yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy +7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah +ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN +5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb +/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa +5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK +G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP +82Z+ +-----END CERTIFICATE----- + +COMODO RSA Certification Authority +================================== +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn +dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ +FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ +5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG +x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX +2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL +OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 +sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C +GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 +WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt +rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ +nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg +tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW +sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp +pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA +zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq +ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 +7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE----- + +USERTrust RSA Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE +BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK +ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz +0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j +Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn +RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O ++T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq +/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE +Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM +lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 +yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ +eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW +FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ +7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ +Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM +8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi +FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi +yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c +J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw +sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx +Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +USERTrust ECC Certification Authority +===================================== +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC +VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 +0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez +nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV +HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB +HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu +9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R5 +=========================== +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb +R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD +EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 +SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS +h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx +uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 +yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +IdenTrust Commercial Root CA 1 +============================== +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS +b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES +MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB +IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld +hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ +mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi +1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C +XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl +3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy +NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV +WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg +xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix +uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI +hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg +ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt +ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV +YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX +feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro +kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe +2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz +Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R +cGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +IdenTrust Public Sector Root CA 1 +================================= +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG +EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv +ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV +UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS +b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy +P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 +Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI +rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf +qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS +mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn +ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh +LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v +iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL +4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B +Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw +DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A +mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt +GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt +m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx +NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 +Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI +ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC +ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ +3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G2 +========================================= +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV +BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy +bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug +b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw +HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT +DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx +OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP +/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz +HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU +s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y +TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx +AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 +0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z +iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi +nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ +vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO +e4pIb4tF9g== +-----END CERTIFICATE----- + +Entrust Root Certification Authority - EC1 +========================================== +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx +FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn +YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw +FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs +LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg +dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt +IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy +AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef +9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE +FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h +vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 +kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +CFCA EV ROOT +============ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE +CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB +IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw +MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD +DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV +BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD +7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN +uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW +ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 +xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f +py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K +gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol +hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ +tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf +BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q +ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua +4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG +E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX +BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn +aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy +PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX +kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C +ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GB CA +=============================== +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG +EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw +MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds +b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX +scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP +rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk +9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o +Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg +GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI +hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD +dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0 +VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui +HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +SZAFIR ROOT CA2 +=============== +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG +A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV +BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ +BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD +VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q +qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK +DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE +2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ +ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi +ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC +AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5 +O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67 +oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul +4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6 ++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +Certum Trusted Network CA 2 +=========================== +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE +BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1 +bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y +ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ +TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB +IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9 +7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o +CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b +Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p +uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130 +GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ +9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB +Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye +hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM +BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI +hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW +Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA +L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo +clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM +pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb +w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo +J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm +ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX +is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7 +zAYspsbiDrW5viSP +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions RootCA 2015 +======================================================= +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT +BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0 +aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx +MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg +QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV +BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw +MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv +bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh +iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+ +6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd +FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr +i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F +GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2 +fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu +iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI +hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+ +D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM +d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y +d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn +82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb +davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F +Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt +J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa +JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q +p/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +Hellenic Academic and Research Institutions ECC RootCA 2015 +=========================================================== +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0 +aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw +MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj +IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD +VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290 +Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP +dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK +Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA +GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn +dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +ISRG Root X1 +============ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE +BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD +EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG +EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT +DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r +Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1 +3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K +b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN +Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ +4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf +1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu +hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH +usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r +OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G +A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY +9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV +0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt +hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw +TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx +e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA +JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD +YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n +JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ +m+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM +================ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT +AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw +MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD +TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf +qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr +btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL +j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou +08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw +WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT +tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ +47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC +ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa +i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o +dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s +D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ +j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT +Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW ++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7 +Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d +8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm +5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG +rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +Amazon Root CA 1 +================ +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1 +MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH +FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ +gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t +dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce +VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3 +DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM +CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy +8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa +2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2 +xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +Amazon Root CA 2 +================ +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD +VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1 +MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv +bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4 +kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp +N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9 +AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd +fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx +kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS +btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0 +Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN +c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+ +3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw +DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA +A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE +YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW +xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ +gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW +aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV +Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3 +KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi +JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw= +-----END CERTIFICATE----- + +Amazon Root CA 3 +================ +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB +f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr +Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43 +rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc +eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +Amazon Root CA 4 +================ +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG +EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy +NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ +MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN +/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri +83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA +MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1 +AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 +============================================= +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIxGDAWBgNVBAcT +D0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxpbXNlbCB2ZSBUZWtub2xvamlr +IEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0wKwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24g +TWVya2V6aSAtIEthbXUgU00xNjA0BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRp +ZmlrYXNpIC0gU3VydW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYD +VQQGEwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXllIEJpbGlt +c2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklUQUsxLTArBgNVBAsTJEth +bXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBTTTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11 +IFNNIFNTTCBLb2sgU2VydGlmaWthc2kgLSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAr3UwM6q7a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y8 +6Ij5iySrLqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INrN3wc +wv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2XYacQuFWQfw4tJzh0 +3+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/iSIzL+aFCr2lqBs23tPcLG07xxO9 +WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4fAJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQU +ZT/HiobGPN08VFw1+DrtUgxHV8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQELBQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPfIPP54+M638yc +lNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4lzwDGrpDxpa5RXI4s6ehlj2R +e37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0j +q5Rm+K37DwhuJi1/FwcJsoz7UMCflo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +GDCA TrustAUTH R5 ROOT +====================== +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCQ04xMjAw +BgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8wHQYDVQQD +DBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVow +YjELMAkGA1UEBhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJjDp6L3TQs +AlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBjTnnEt1u9ol2x8kECK62p +OqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+uKU49tm7srsHwJ5uu4/Ts765/94Y9cnrr +pftZTqfrlYwiOXnhLQiPzLyRuEH3FMEjqcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ +9Cy5WmYqsBebnh52nUpmMUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQ +xXABZG12ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloPzgsM +R6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3GkL30SgLdTMEZeS1SZ +D2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeCjGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4 +oR24qoAATILnsn8JuLwwoC8N9VKejveSswoAHQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx +9hoh49pwBiFYFIeFd3mqgnkCAwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlR +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZmDRd9FBUb1Ov9 +H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5COmSdI31R9KrO9b7eGZONn35 +6ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ryL3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd ++PwyvzeG5LuOmCd+uh8W4XAR8gPfJWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQ +HtZa37dG/OaG+svgIHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBD +F8Io2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV09tL7ECQ +8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQXR4EzzffHqhmsYzmIGrv +/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrqT8p+ck0LcIymSLumoRT2+1hEmRSuqguT +aaApJUqlyyvdimYHFngVV3Eb7PVHhPOeMTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +SSL.com Root Certification Authority RSA +======================================== +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxDjAM +BgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24x +MTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYw +MjEyMTczOTM5WhcNNDEwMjEyMTczOTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NM +LmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2RxFdHaxh3a3by/ZPkPQ/C +Fp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aXqhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8 +P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcCC52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/ge +oeOy3ZExqysdBP+lSgQ36YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkp +k8zruFvh/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrFYD3Z +fBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93EJNyAKoFBbZQ+yODJ +gUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVcUS4cK38acijnALXRdMbX5J+tB5O2 +UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi8 +1xtZPCvM8hnIk2snYxnP/Okm+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4s +bE6x/c+cCbqiM+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGVcpNxJK1ok1iOMq8bs3AD/CUr +dIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBcHadm47GUBwwyOabqG7B52B2ccETjit3E+ZUf +ijhDPwGFpUenPUayvOUiaPd7nNgsPgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAsl +u1OJD7OAUN5F7kR/q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjq +erQ0cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jra6x+3uxj +MxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90IH37hVZkLId6Tngr75qNJ +vTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/YK9f1JmzJBjSWFupwWRoyeXkLtoh/D1JI +Pb9s2KJELtFOt3JY04kTlf5Eq/jXixtunLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406y +wKBjYZC6VWg3dGq2ktufoYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NI +WuuA8ShYIc2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +SSL.com Root Certification Authority ECC +======================================== +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xMTAv +BgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEy +MTgxNDAzWhcNNDEwMjEyMTgxNDAzWjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO +BgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI7Z4INcgn64mMU1jrYor+ +8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPgCemB+vNH06NjMGEwHQYDVR0OBBYEFILR +hXMw5zUE044CkvvlpNHEIejNMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTT +jgKS++Wk0cQh6M0wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCW +e+0F+S8Tkdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+gA0z +5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority RSA R2 +============================================== +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMQ4w +DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9u +MTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MB4XDTE3MDUzMTE4MTQzN1oXDTQyMDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI +DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYD +VQQDDC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvqM0fNTPl9fb69LT3w23jh +hqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssufOePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7w +cXHswxzpY6IXFJ3vG2fThVUCAtZJycxa4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTO +Zw+oz12WGQvE43LrrdF9HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+ +B6KjBSYRaZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcAb9Zh +CBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQGp8hLH94t2S42Oim +9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQVPWKchjgGAGYS5Fl2WlPAApiiECto +RHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMOpgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+Slm +JuwgUHfbSguPvuUCYHBBXtSuUDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48 ++qvWBkofZ6aYMBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa49QaAJadz20Zp +qJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBWs47LCp1Jjr+kxJG7ZhcFUZh1 +++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nx +Y/hoLVUE0fKNsKTPvDxeH3jnpaAgcLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2G +guDKBAdRUNf/ktUM79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDz +OFSz/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXtll9ldDz7 +CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEmKf7GUmG6sXP/wwyc5Wxq +lD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKKQbNmC1r7fSOl8hqw/96bg5Qu0T/fkreR +rwU7ZcegbLHNYhLDkBvjJc40vG93drEQw/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1 +hlMYegouCRw2n5H9gooiS9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX +9hwJ1C07mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +SSL.com EV Root Certification Authority ECC +=========================================== +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9TU0wgQ29ycG9yYXRpb24xNDAy +BgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYw +MjEyMTgxNTIzWhcNNDEwMjEyMTgxNTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx +EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NM +LmNvbSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMAVIbc/R/fALhBYlzccBYy +3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1KthkuWnBaBu2+8KGwytAJKaNjMGEwHQYDVR0O +BBYEFFvKXuXe0oGqzagtZFG22XKbl+ZPMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe +5d7SgarNqC1kUbbZcpuX5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJ +N+vp1RPZytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZgh5Mm +m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +GlobalSign Root CA - R6 +======================= +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEgMB4GA1UECxMX +R2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQxMjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9i +YWxTaWduIFJvb3QgQ0EgLSBSNjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFs +U2lnbjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQss +grRIxutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1kZguSgMpE +3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxDaNc9PIrFsmbVkJq3MQbF +vuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJwLnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqM +PKq0pPbzlUoSB239jLKJz9CgYXfIWHSw1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+ +azayOeSsJDa38O+2HBNXk7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05O +WgtH8wY2SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/hbguy +CLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4nWUx2OVvq+aWh2IMP +0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpYrZxCRXluDocZXFSxZba/jJvcE+kN +b7gu3GduyYsRtYQUigAZcIN5kZeR1BonvzceMgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQE +AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNV +HSMEGDAWgBSubAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGtIxg93eFyRJa0 +lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr6155wsTLxDKZmOMNOsIeDjHfrY +BzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLjvUYAGm0CuiVdjaExUd1URhxN25mW7xocBFym +Fe944Hn+Xds+qkxV/ZoVqW/hpvvfcDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr +3TsTjxKM4kEaSHpzoHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB1 +0jZpnOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfspA9MRf/T +uTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+vJJUEeKgDu+6B5dpffItK +oZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+t +JDfLRVpOoERIyNiwmcUVhAn21klJwGW45hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +OISTE WISeKey Global Root GC CA +=============================== +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQswCQYDVQQGEwJD +SDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEo +MCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRa +Fw00MjA1MDkwOTU4MzNaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQL +ExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4nieUqjFqdr +VCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4Wp2OQ0jnUsYd4XxiWD1Ab +NTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd +BgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7TrYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0E +AwMDaAAwZQIwJsdpW9zV57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtk +AjEA2zQgMgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +UCA Global G2 Root +================== +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBHbG9iYWwgRzIgUm9vdDAeFw0x +NjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0xCzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlU +cnVzdDEbMBkGA1UEAwwSVUNBIEdsb2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxeYrb3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmT +oni9kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzmVHqUwCoV +8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/RVogvGjqNO7uCEeBHANBS +h6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDcC/Vkw85DvG1xudLeJ1uK6NjGruFZfc8o +LTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIjtm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/ +R+zvWr9LesGtOxdQXGLYD0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBe +KW4bHAyvj5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6DlNaBa +4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6iIis7nCs+dwp4wwc +OxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznPO6Q0ibd5Ei9Hxeepl2n8pndntd97 +8XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFIHEjMz15DD/pQwIX4wVZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo +5sOASD0Ee/ojL3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl1qnN3e92mI0A +Ds0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oUb3n09tDh05S60FdRvScFDcH9 +yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LVPtateJLbXDzz2K36uGt/xDYotgIVilQsnLAX +c47QN6MUPJiVAAwpBVueSUmxX8fjy88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHo +jhJi6IjMtX9Gl8CbEGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZk +bxqgDMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI+Vg7RE+x +ygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGyYiGqhkCyLmTTX8jjfhFn +RR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bXUB+K+wb1whnw0A== +-----END CERTIFICATE----- + +UCA Extended Validation Root +============================ +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBHMQswCQYDVQQG +EwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9u +IFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMxMDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8G +A1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrs +iWogD4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvSsPGP2KxF +Rv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aopO2z6+I9tTcg1367r3CTu +eUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dksHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR +59mzLC52LqGj3n5qiAno8geK+LLNEOfic0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH +0mK1lTnj8/FtDw5lhIpjVMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KR +el7sFsLzKuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/TuDv +B0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41Gsx2VYVdWf6/wFlth +WG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs1+lvK9JKBZP8nm9rZ/+I8U6laUpS +NwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQDfwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS +3H5aBZ8eNJr34RQwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEL +BQADggIBADaNl8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQVBcZEhrxH9cM +aVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5c6sq1WnIeJEmMX3ixzDx/BR4 +dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb ++7lsq+KePRXBOy5nAliRn+/4Qh8st2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOW +F3sGPjLtx7dCvHaj2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwi +GpWOvpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2CxR9GUeOc +GMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmxcmtpzyKEC2IPrNkZAJSi +djzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbMfjKaiJUINlK73nZfdklJrX+9ZSCyycEr +dhh2n1ax +-----END CERTIFICATE----- + +Certigna Root CA +================ +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UE +BhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAwMiA0ODE0NjMwODEwMDAzNjEZ +MBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0xMzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjda +MFoxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYz +MDgxMDAwMzYxGTAXBgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sOty3tRQgX +stmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9MCiBtnyN6tMbaLOQdLNyz +KNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPuI9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8 +JXrJhFwLrN1CTivngqIkicuQstDuI7pmTLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16 +XdG+RCYyKfHx9WzMfgIhC59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq +4NYKpkDfePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3YzIoej +wpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWTCo/1VTp2lc5ZmIoJ +lXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1kJWumIWmbat10TWuXekG9qxf5kBdI +jzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp/ +/TBt2dzhauH8XwIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczovL3d3d3cuY2Vy +dGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilodHRwOi8vY3JsLmNlcnRpZ25h +LmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYraHR0cDovL2NybC5kaGlteW90aXMuY29tL2Nl +cnRpZ25hcm9vdGNhLmNybDANBgkqhkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOIt +OoldaDgvUSILSo3L6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxP +TGRGHVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH60BGM+RFq +7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncBlA2c5uk5jR+mUYyZDDl3 +4bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdio2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd +8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS +6Cvu5zHbugRqh5jnxV/vfaci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaY +tlu3zM63Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayhjWZS +aX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw3kAP+HwV96LOPNde +E4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +emSign Root CA - G1 +=================== +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYDVQQGEwJJTjET +MBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRl +ZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBHMTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgx +ODMwMDBaMGcxCzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk +aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQzf2N4aLTN +LnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO8oG0x5ZOrRkVUkr+PHB1 +cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aqd7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHW +DV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhMtTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ +6DqS0hdW5TUaQBw+jSztOd9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrH +hQIDAQABo0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQDAgEG +MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31xPaOfG1vR2vjTnGs2 +vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjMwiI/aTvFthUvozXGaCocV685743Q +NcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6dGNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q ++Mri/Tm3R7nrft8EI6/6nAYH6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeih +U80Bv2noWgbyRQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +emSign ECC Root CA - G3 +======================= +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQGEwJJTjETMBEG +A1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEg +MB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4 +MTgzMDAwWjBrMQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11 +ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0WXTsuwYc +58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xySfvalY8L1X44uT6EYGQIr +MgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuBzhccLikenEhjQjAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+D +CBeQyh+KTOgNG3qxrdWBCUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7 +jHvrZQnD+JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +emSign Root CA - C1 +=================== +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMx +EzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNp +Z24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQD +ExNlbVNpZ24gUm9vdCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+up +ufGZBczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZHdPIWoU/ +Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH3DspVpNqs8FqOp099cGX +OFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvHGPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4V +I5b2P/AgNBbeCsbEBEV5f6f9vtKppa+cxSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleooms +lMuoaJuvimUnzYnu3Yy1aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+ +XJGFehiqTbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQAD +ggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87/kOXSTKZEhVb3xEp +/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4kqNPEjE2NuLe/gDEo2APJ62gsIq1 +NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrGYQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9 +wC68AivTxEDkigcxHpvOJpkT+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQ +BmIMMMAVSKeoWXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +emSign ECC Root CA - C3 +======================= +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQGEwJVUzETMBEG +A1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMxIDAeBgNVBAMTF2VtU2lnbiBF +Q0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAwMFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UE +BhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQD +ExdlbVNpZ24gRUNDIFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd +6bciMK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4OjavtisIGJAnB9 +SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0OBBYEFPtaSNCAIEDyqOkA +B2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gA +MGUCMQC02C8Cif22TGK6Q04ThHK1rt0c3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwU +ZOR8loMRnLDRWmFLpg9J0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +Hongkong Post Root CA 3 +======================= +-----BEGIN CERTIFICATE----- +MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQELBQAwbzELMAkG +A1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJSG9uZyBLb25nMRYwFAYDVQQK +Ew1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25na29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2 +MDMwMjI5NDZaFw00MjA2MDMwMjI5NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtv +bmcxEjAQBgNVBAcTCUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMX +SG9uZ2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz +iNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFOdem1p+/l6TWZ5Mwc50tf +jTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mIVoBc+L0sPOFMV4i707mV78vH9toxdCim +5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOe +sL4jpNrcyCse2m5FHomY2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj +0mRiikKYvLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+TtbNe/ +JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZbx39ri1UbSsUgYT2u +y1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+l2oBlKN8W4UdKjk60FSh0Tlxnf0h ++bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YKTE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsG +xVd7GYYKecsAyVKvQv83j+GjHno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwID +AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e +i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEwDQYJKoZIhvcN +AQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG7BJ8dNVI0lkUmcDrudHr9Egw +W62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCkMpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWld +y8joRTnU+kLBEUx3XZL7av9YROXrgZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov ++BS5gLNdTaqX4fnkGMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDc +eqFS3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJmOzj/2ZQw +9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+l6mc1X5VTMbeRRAc6uk7 +nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6cJfTzPV4e0hz5sy229zdcxsshTrD3mUcY +hcErulWuBurQB7Lcq9CClnXO0lD+mefPL5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB +60PZ2Pierc+xYw5F9KBaLJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fq +dBb9HxEGmpv0 +-----END CERTIFICATE----- + +Entrust Root Certification Authority - G4 +========================================= +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAwgb4xCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3Qu +bmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1 +dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eSAtIEc0MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYT +AlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhv +cml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3D +umSXbcr3DbVZwbPLqGgZ2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV +3imz/f3ET+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j5pds +8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAMC1rlLAHGVK/XqsEQ +e9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73TDtTUXm6Hnmo9RR3RXRv06QqsYJn7 +ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNXwbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5X +xNMhIWNlUpEbsZmOeX7m640A2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV +7rtNOzK+mndmnqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwlN4y6mACXi0mW +Hv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNjc0kCAwEAAaNCMEAwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9n +MA0GCSqGSIb3DQEBCwUAA4ICAQAS5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4Q +jbRaZIxowLByQzTSGwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht +7LGrhFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/B7NTeLUK +YvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uIAeV8KEsD+UmDfLJ/fOPt +jqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbwH5Lk6rWS02FREAutp9lfx1/cH6NcjKF+ +m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKW +RGhXxNUzzxkvFMSUHHuk2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjA +JOgc47OlIQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk5F6G ++TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuYn/PIjhs4ViFqUZPT +kcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +Microsoft ECC Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQgRUND +IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4 +MjMxNjA0WjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQ +BgcqhkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZRogPZnZH6 +thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYbhGBKia/teQ87zvH2RPUB +eMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIy5lycFIM ++Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlf +Xu5gKcs68tvWMoQZP3zVL8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaR +eNtUjGUBiudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +Microsoft RSA Root Certificate Authority 2017 +============================================= +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNyb3NvZnQg +UlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIw +NzE4MjMwMDIzWjBlMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u +MTYwNAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZNt9GkMml +7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0ZdDMbRnMlfl7rEqUrQ7e +S0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw7 +1VdyvD/IybLeS2v4I2wDwAW9lcfNcztmgGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+ +dkC0zVJhUXAoP8XFWvLJjEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49F +yGcohJUcaDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaGYaRS +MLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6W6IYZVcSn2i51BVr +lMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4KUGsTuqwPN1q3ErWQgR5WrlcihtnJ +0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJ +ClTUFLkqqNfs+avNJVgyeY+QW5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZCLgLNFgVZJ8og +6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OCgMNPOsduET/m4xaRhPtthH80 +dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk ++ONVFT24bcMKpBLBaYVu32TxU5nhSnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex +/2kskZGT4d9Mozd2TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDy +AmH3pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGRxpl/j8nW +ZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiAppGWSZI1b7rCoucL5mxAyE +7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKT +c0QWbej09+CVgI+WXTik9KveCjCHk9hNAHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D +5KbvtwEwXlGjefVwaaZBRA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +e-Szigno Root CA 2017 +===================== +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNVBAYTAkhVMREw +DwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUt +MjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJvb3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZa +Fw00MjA4MjIxMjA3MDZaMHExCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UE +CgwNTWljcm9zZWMgTHRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3pp +Z25vIFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtvxie+RJCx +s1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+HWyx7xf58etqjYzBhMA8G +A1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSHERUI0arBeAyxr87GyZDv +vzAEwDAfBgNVHSMEGDAWgBSHERUI0arBeAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEA +tVfd14pVCzbhhkT61NlojbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxO +svxyqltZ+efcMQ== +-----END CERTIFICATE----- + +certSIGN Root CA G2 +=================== +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNVBAYTAlJPMRQw +EgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjAeFw0xNzAy +MDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJBgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lH +TiBTQTEcMBoGA1UECxMTY2VydFNJR04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMDFdRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05 +N0IwvlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZuIt4Imfk +abBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhpn+Sc8CnTXPnGFiWeI8Mg +wT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKscpc/I1mbySKEwQdPzH/iV8oScLumZfNp +dWO9lfsbl83kqK/20U6o2YpxJM02PbyWxPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91Qqh +ngLjYl/rNUssuHLoPj1PrCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732 +jcZZroiFDsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fxDTvf +95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgyLcsUDFDYg2WD7rlc +z8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6CeWRgKRM+o/1Pcmqr4tTluCRVLERL +iohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBSCIS1mxteg4BXrzkwJd8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOB +ywaK8SJJ6ejqkX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQlqiCA2ClV9+BB +/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0OJD7uNGzcgbJceaBxXntC6Z5 +8hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+cNywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5 +BiKDUyUM/FHE5r7iOZULJK2v0ZXkltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklW +atKcsWMy5WHgUyIOpwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tU +Sxfj03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZkPuXaTH4M +NMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE1LlSVHJ7liXMvGnjSG4N +0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MXQRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +Trustwave Global Certification Authority +======================================== +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTAeFw0xNzA4MjMxOTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJV +UzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2 +ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALldUShLPDeS0YLOvR29 +zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0XznswuvCAAJWX/NKSqIk4cXGIDtiLK0thAf +LdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4Bq +stTnoApTAbqOl5F2brz81Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9o +WN0EACyW80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotPJqX+ +OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1lRtzuzWniTY+HKE40 +Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfwhI0Vcnyh78zyiGG69Gm7DIwLdVcE +uE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm ++9jaJXLE9gCxInm943xZYkqcBW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqj +ifLJS3tBEW1ntwiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1UdDwEB/wQEAwIB +BjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W0OhUKDtkLSGm+J1WE2pIPU/H +PinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfeuyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0H +ZJDmHvUqoai7PF35owgLEQzxPy0QlG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla +4gt5kNdXElE1GYhBaCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5R +vbbEsLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPTMaCm/zjd +zyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qequ5AvzSxnI9O4fKSTx+O +856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxhVicGaeVyQYHTtgGJoC86cnn+OjC/QezH +Yj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu +3R3y4G5OBVixwJAWKqQ9EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP +29FpHOTKyeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +Trustwave Global ECC P256 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDI1 +NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABH77bOYj +43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoNFWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqm +P62jQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt +0UrrdaVKEJmzsaGLSvcwCgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjz +RM4q3wghDDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +Trustwave Global ECC P384 Certification Authority +================================================= +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYDVQQGEwJVUzER +MA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRy +dXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBFQ0MgUDM4 +NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuBBAAiA2IABGvaDXU1CDFH +Ba5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJj9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr +/TklZvFe/oyujUF5nQlgziip04pt89ZF1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNV +HQ8BAf8EBQMDBwYAMB0GA1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNn +ADBkAjA3AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsCMGcl +CrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVuSw== +-----END CERTIFICATE----- + +NAVER Global Root Certification Authority +========================================= +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEMBQAwaTELMAkG +A1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRGT1JNIENvcnAuMTIwMAYDVQQD +DClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4 +NDJaFw0zNzA4MTgyMzU5NTlaMGkxCzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVT +UyBQTEFURk9STSBDb3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVAiQqrDZBb +UGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH38dq6SZeWYp34+hInDEW ++j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lEHoSTGEq0n+USZGnQJoViAbbJAh2+g1G7 +XNr4rRVqmfeSVPc0W+m/6imBEtRTkZazkVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2 +aacp+yPOiNgSnABIqKYPszuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4 +Yb8ObtoqvC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHfnZ3z +VHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaGYQ5fG8Ir4ozVu53B +A0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo0es+nPxdGoMuK8u180SdOqcXYZai +cdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3aCJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejy +YhbLgGvtPe31HzClrkvJE+2KAQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNV +HQ4EFgQU0p+I36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoNqo0hV4/GPnrK +21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatjcu3cvuzHV+YwIHHW1xDBE1UB +jCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bx +hYTeodoS76TiEJd6eN4MUZeoIUCLhr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTg +E34h5prCy8VCZLQelHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTH +D8z7p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8piKCk5XQ +A76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLRLBT/DShycpWbXgnbiUSY +qqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oG +I/hGoiLtk/bdmuYqh7GYVPEi92tF4+KOdh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmg +kpzNNIaRkPpkUZ3+/uul9XXeifdy +-----END CERTIFICATE----- + +AC RAIZ FNMT-RCM SERVIDORES SEGUROS +=================================== +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQswCQYDVQQGEwJF +UzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgwFgYDVQRhDA9WQVRFUy1RMjgy +NjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1SQ00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4 +MTIyMDA5MzczM1oXDTQzMTIyMDA5MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQt +UkNNMQ4wDAYDVQQLDAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNB +QyBSQUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuBBAAiA2IA +BPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LHsbI6GA60XYyzZl2hNPk2 +LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oKUm8BA06Oi6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqG +SM49BAMDA2kAMGYCMQCuSuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoD +zBOQn5ICMQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJyv+c= +-----END CERTIFICATE----- + +GlobalSign Root R46 +=================== +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUAMEYxCzAJBgNV +BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJv +b3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAX +BgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08Es +CVeJOaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQGvGIFAha/ +r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud316HCkD7rRlr+/fKYIje +2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo0q3v84RLHIf8E6M6cqJaESvWJ3En7YEt +bWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSEy132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvj +K8Cd+RTyG/FWaha/LIWFzXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD4 +12lPFzYE+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCNI/on +ccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzsx2sZy/N78CsHpdls +eVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqaByFrgY/bxFn63iLABJzjqls2k+g9 +vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEM +BQADggIBAHx47PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti2kM3S+LGteWy +gxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIkpnnpHs6i58FZFZ8d4kuaPp92 +CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRFFRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZm +OUdkLG5NrmJ7v2B0GbhWrJKsFjLtrWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qq +JZ4d16GLuc1CLgSkZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwye +qiv5u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP4vkYxboz +nxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6N3ec592kD3ZDZopD8p/7 +DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3vouXsXgxT7PntgMTzlSdriVZzH81Xwj3 +QEUxeCp6 +-----END CERTIFICATE----- + +GlobalSign Root E46 +=================== +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYxCzAJBgNVBAYT +AkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQDExNHbG9iYWxTaWduIFJvb3Qg +RTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNV +BAoTEEdsb2JhbFNpZ24gbnYtc2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkB +jtjqR+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGddyXqBPCCj +QjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQxCpCPtsad0kRL +gLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZk +vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ +CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +GLOBALTRUST 2020 +================ +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx +IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT +VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh +BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy +MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi +D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO +VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM +CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm +fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA +A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR +JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG +DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU +clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ +mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud +IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw +4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 +iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS +8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 +HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS +vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 +oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF +YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl +gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +ANF Secure Server Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 +NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv +bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg +Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw +MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw +EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz +BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv +T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv +B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse +zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM +VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j +7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z +JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe +8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO +Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ +UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx +j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt +dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM +5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb +5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 +EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H +hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy +g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 +r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- + +Certum EC-384 CA +================ +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ +TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 +MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh +dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq +vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn +iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo +ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 +QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +Certum Trusted Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG +EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew +HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY +QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p +fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 +HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 +fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt +g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 +NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk +fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ +P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY +njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK +HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL +LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s +ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K +h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 +CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA +4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo +WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj +6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT +OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck +bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + +TunTrust Root CA +================ +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQELBQAwYTELMAkG +A1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUgQ2VydGlmaWNhdGlvbiBFbGVj +dHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJvb3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQw +NDI2MDg1NzU2WjBhMQswCQYDVQQGEwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBD +ZXJ0aWZpY2F0aW9uIEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZn56eY+hz +2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd2JQDoOw05TDENX37Jk0b +bjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgFVwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7 +NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZGoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAd +gjH8KcwAWJeRTIAAHDOFli/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViW +VSHbhlnUr8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2eY8f +Tpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIbMlEsPvLfe/ZdeikZ +juXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISgjwBUFfyRbVinljvrS5YnzWuioYas +DXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwS +VXAkPcvCFDVDXSdOvsC9qnyW5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI +04Y+oXNZtPdEITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+zxiD2BkewhpMl +0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYuQEkHDVneixCwSQXi/5E/S7fd +Ao74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRY +YdZ2vyJ/0Adqp2RT8JeNnYA/u8EH22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJp +adbGNjHh/PqAulxPxOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65x +xBzndFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5Xc0yGYuP +jCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7bnV2UqL1g52KAdoGDDIzM +MEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQCvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9z +ZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZHu/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3r +AZ3r2OvEhJn7wAzMMujjd9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +HARICA TLS RSA Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQG +EwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u +cyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0EgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUz +OFoXDTQ1MDIxMzEwNTUzN1owbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRl +bWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNB +IFJvb3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569lmwVnlskN +JLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE4VGC/6zStGndLuwRo0Xu +a2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uva9of08WRiFukiZLRgeaMOVig1mlDqa2Y +Ulhu2wr7a89o+uOkXjpFc5gH6l8Cct4MpbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K +5FrZx40d/JiZ+yykgmvwKh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEv +dmn8kN3bLW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcYAuUR +0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqBAGMUuTNe3QvboEUH +GjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYqE613TBoYm5EPWNgGVMWX+Ko/IIqm +haZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHrW2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQ +CPxrvrNQKlr9qEgYRtaQQJKQCoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAUX15QvWiWkKQU +EapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3f5Z2EMVGpdAgS1D0NTsY9FVq +QRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxajaH6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxD +QpSbIPDRzbLrLFPCU3hKTwSUQZqPJzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcR +j88YxeMn/ibvBZ3PzzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5 +vZStjBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0/L5H9MG0 +qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pTBGIBnfHAT+7hOtSLIBD6 +Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79aPib8qXPMThcFarmlwDB31qlpzmq6YR/ +PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YWxw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnn +kf3/W9b3raYvAwtt41dU63ZTGI0RmLo= +-----END CERTIFICATE----- + +HARICA TLS ECC Root CA 2021 +=========================== +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQswCQYDVQQGEwJH +UjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBD +QTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9vdCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoX +DTQ1MDIxMzExMDEwOVowbDELMAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWlj +IGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJv +b3QgQ0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7KKrxcm1l +AEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9YSTHMmE5gEYd103KUkE+b +ECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW +0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAi +rcJRQO9gcS3ujwLEXQNwSaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/Qw +CZ61IygNnxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- + +Autoridad de Certificacion Firmaprofesional CIF A62634068 +========================================================= +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCRVMxQjBA +BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 +MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIw +QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB +NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD +Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P +B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY +7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH +ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI +plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX +MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX +LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK +bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU +vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1Ud +DgQWBBRlzeurNR4APn7VdMActHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4w +gZswgZgGBFUdIAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABCAG8AbgBhAG4A +bwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAwADEANzAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9miWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL +4QjbEwj4KKE1soCzC1HA01aajTNFSa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDb +LIpgD7dvlAceHabJhfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1il +I45PVf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZEEAEeiGaP +cjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV1aUsIC+nmCjuRfzxuIgA +LI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2tCsvMo2ebKHTEm9caPARYpoKdrcd7b/+A +lun4jWq9GJAd/0kakFI3ky88Al2CdgtR5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH +9IBk9W6VULgRfhVwOEqwf9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpf +NIbnYrX9ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNKGbqE +ZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- + +vTrus ECC Root CA +================= +-----BEGIN CERTIFICATE----- +MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMwRzELMAkGA1UE +BhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBS +b290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDczMTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAa +BgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+c +ToL0v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUde4BdS49n +TPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIwV53dVvHH4+m4SVBrm2nDb+zDfSXkV5UT +QJtS0zvzQBm8JsctBp61ezaf9SXUY2sAAjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQL +YgmRWAD5Tfs0aNoJrSEGGJTO +-----END CERTIFICATE----- + +vTrus Root CA +============= +-----BEGIN CERTIFICATE----- +MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQELBQAwQzELMAkG +A1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xFjAUBgNVBAMTDXZUcnVzIFJv +b3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMxMDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoG +A1UEChMTaVRydXNDaGluYSBDby4sTHRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZots +SKYcIrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykUAyyNJJrI +ZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+GrPSbcKvdmaVayqwlHeF +XgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z98Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KA +YPxMvDVTAWqXcoKv8R1w6Jz1717CbMdHflqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70 +kLJrxLT5ZOrpGgrIDajtJ8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2 +AXPKBlim0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZNpGvu +/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQUqqzApVg+QxMaPnu +1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHWOXSuTEGC2/KmSNGzm/MzqvOmwMVO +9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMBAAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYg +scasGrz2iTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOC +AgEAKbqSSaet8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd +nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1jbhd47F18iMjr +jld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvMKar5CKXiNxTKsbhm7xqC5PD4 +8acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIivTDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJn +xDHO2zTlJQNgJXtxmOTAGytfdELSS8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554Wg +icEFOwE30z9J4nfrI8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4 +sEb9b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNBUvupLnKW +nyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1PTi07NEPhmg4NpGaXutIc +SkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929vensBxXVsFy6K2ir40zSbofitzmdHxghm+H +l3s= +-----END CERTIFICATE----- + +ISRG Root X2 +============ +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQswCQYDVQQGEwJV +UzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElT +UkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVT +MSkwJwYDVQQKEyBJbnRlcm5ldCBTZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNS +RyBSb290IFgyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0H +ttwW+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9ItgKbppb +d9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZIzj0EAwMDaAAwZQIwe3lORlCEwkSHRhtF +cP9Ymd70/aTSVaYgLXTWNLxBo1BfASdWtL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5 +U6VR5CmD1/iQMVtCnwr1/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- + +HiPKI Root CA - G1 +================== +-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQG +EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xGzAZBgNVBAMMEkhpUEtJ +IFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRaFw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYT +AlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kg +Um9vdCBDQSAtIEcxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0 +o9QwqNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twvVcg3Px+k +wJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6lZgRZq2XNdZ1AYDgr/SE +YYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnzQs7ZngyzsHeXZJzA9KMuH5UHsBffMNsA +GJZMoYFL3QRtU6M9/Aes1MU3guvklQgZKILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfd +hSi8MEyr48KxRURHH+CKFgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj +1jOXTyFjHluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDry+K4 +9a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ/W3c1pzAtH2lsN0/ +Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgMa/aOEmem8rJY5AIJEzypuxC00jBF +8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQD +AgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqcSE5XCV0vrPSl +tJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6FzaZsT0pPBWGTMpWmWSBUdGSquE +wx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9TcXzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07Q +JNBAsNB1CI69aO4I1258EHBGG3zgiLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv +5wiZqAxeJoBF1PhoL5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+Gpz +jLrFNe85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wrkkVbbiVg +hUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+vhV4nYWBSipX3tUZQ9rb +yltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQUYDksswBVLuT1sw5XxJFBAJw/6KXf6vb/ +yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== +-----END CERTIFICATE----- + +GlobalSign ECC Root CA - R4 +=========================== +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYDVQQLExtHbG9i +YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgwMTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9i +YWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkds +b2JhbFNpZ24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkW +ymOxuYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/+wpu+74zyTyjhNUwCgYI +KoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147bmF0774BxL4YSFlhgjICICadVGNA3jdg +UM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE----- + +GTS Root R1 +=========== +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7wCl7raKb0 +xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjwTcLCeoiKu7rPWRnWr4+w +B7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0PfyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXW +nOunVmSPlk9orj2XwoSPwLxAwAtcvfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk +9+aCEI3oncKKiPo4Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zq +kUspzBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92wO1A +K/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70paDPvOmbsB4om3xPX +V2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDW +cfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQAD +ggIBAJ+qQibbC5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuyh6f88/qBVRRi +ClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM47HLwEXWdyzRSjeZ2axfG34ar +J45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8JZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYci +NuaCp+0KueIHoI17eko8cdLiA6EfMgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5me +LMFrUKTX5hgUvYU/Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJF +fbdT6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ0E6yove+ +7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm2tIMPNuzjsmhDYAPexZ3 +FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bbbP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3 +gm3c +-----END CERTIFICATE----- + +GTS Root R2 +=========== +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQswCQYDVQQGEwJV +UzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3Qg +UjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UE +ChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY6Dlo7JUl +e3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAuMC6C/Pq8tBcKSOWIm8Wb +a96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS ++LFjKBC4swm4VndAoiaYecb+3yXuPuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7M +kogwTZq9TwtImoS1mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJG +r61K8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RWIr9q +S34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKaG73VululycslaVNV +J1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCqgc7dGtxRcw1PcOnlthYhGXmy5okL +dWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQAD +ggIBAB/Kzt3HvqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyCB19m3H0Q/gxh +swWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2uNmSRXbBoGOqKYcl3qJfEycel +/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMgyALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVn +jWQye+mew4K6Ki3pHrTgSAai/GevHyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y5 +9PYjJbigapordwj6xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M +7YNRTOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924SgJPFI/2R8 +0L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV7LXTWtiBmelDGDfrs7vR +WGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjW +HYbL +-----END CERTIFICATE----- + +GTS Root R3 +=========== +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi +MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMw +HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ +R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjO +PQIBBgUrgQQAIgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL24CejQjBA +MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTB8Sa6oC2uhYHP0/Eq +Er24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azT +L818+FsuVbu/3ZL3pAzcMeGiAjEA/JdmZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV +11RZt+cRLInUue4X +-----END CERTIFICATE----- + +GTS Root R4 +=========== +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYDVQQGEwJVUzEi +MCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQw +HhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZ +R29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjO +PQIBBgUrgQQAIgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvRHYqjQjBA +MA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSATNbrdP9JNqPV2Py1 +PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C +r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh +4rsUecrNIdSUtUlD +-----END CERTIFICATE----- + +Telia Root CA v2 +================ +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT +AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2 +MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK +DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7 +6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q +9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn +pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl +tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW +5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr +RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E +BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4 +M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau +BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W +xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5 +tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H +eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C +y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC +QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15 +h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70 +sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9 +xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ +raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc= +-----END CERTIFICATE----- + +D-TRUST BR Root CA 1 2020 +========================= +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE +RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy +MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV +BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7 +dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu +QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t +MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu +bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP +PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD +AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom +AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE----- + +D-TRUST EV Root CA 1 2020 +========================= +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE +RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy +MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV +BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8 +ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ +raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL +MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu +bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP +PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD +AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR +AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE----- + +DigiCert TLS ECC P384 Root G5 +============================= +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4 +NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx +FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg +Um9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd +lHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj +n4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB +/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds +Jk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx +AJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- + +DigiCert TLS RSA4096 Root G5 +============================ +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG +EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0 +MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV +UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2 +IFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8 +7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU +AT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces +tyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa +zOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV +DdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q +TXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy +z6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/ +MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk +wcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E +FgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN +lnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN +MBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/ +u4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G +OUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh +47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU +FvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ +yqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP +bEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- + +Certainly Root R1 +================= +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE +BhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN +MjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy +dGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O +5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl +8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl +DbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI +XsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN +KPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ +AjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb +rlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1 +VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS +p6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz +HQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v +MMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB +GsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+ +gjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH +JBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7 +fpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw +x06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S +X3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8= +-----END CERTIFICATE----- + +Certainly Root E1 +================= +-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV +UzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0 +MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu +bHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4 +fxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9 +YBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E +AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8 +rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE----- + +Security Communication RootCA3 +============================== +-----BEGIN CERTIFICATE----- +MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNVBAYTAkpQMSUw +IwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScwJQYDVQQDEx5TZWN1cml0eSBD +b21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQsw +CQYDVQQGEwJKUDElMCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UE +AxMeU2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4rCmDvu20r +hvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzAlrenfna84xtSGc4RHwsE +NPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MGTfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2 +/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF79+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGm +npjKIG58u4iFW/vAEGK78vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtY +XLVqAvO4g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3weGVPK +p7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst+3A7caoreyYn8xrC +3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M0V9hvqG8OmpI6iZVIhZdXw3/JzOf +GAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQT9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0Vcw +CBEF/VfR2ccCAwEAAaNCMEAwHQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS +YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PAFNr0Y/Dq9HHu +Tofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd9XbXv8S2gVj/yP9kaWJ5rW4O +H3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQIUYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASx +YfQAW0q3nHE3GYV5v4GwxxMOdnE+OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZ +XSEIx2C/pHF7uNkegr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml ++LLfiAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUVnuiZIesn +KwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD2NCcnWXL0CsnMQMeNuE9 +dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI//1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm +6Vwdp6POXiUyK+OVrCoHzrQoeIY8LaadTdJ0MN1kURXbg4NR16/9M51NZg== +-----END CERTIFICATE----- + +Security Communication ECC RootCA1 +================================== +-----BEGIN CERTIFICATE----- +MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYTAkpQMSUwIwYD +VQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYDVQQDEyJTZWN1cml0eSBDb21t +dW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYxNjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTEL +MAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNV +BAMTIlNlY3VyaXR5IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+CnnfdldB9sELLo +5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpKULGjQjBAMB0GA1UdDgQW +BBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAK +BggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3L +snNdo4gIxwwCMQDAqy0Obe0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70e +N9k= +-----END CERTIFICATE----- + +BJCA Global Root CA1 +==================== +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQG +EwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJK +Q0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAzMTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkG +A1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQD +DBRCSkNBIEdsb2JhbCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFm +CL3ZxRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZspDyRhyS +sTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O558dnJCNPYwpj9mZ9S1Wn +P3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgRat7GGPZHOiJBhyL8xIkoVNiMpTAK+BcW +yqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRj +eulumijWML3mG90Vr4TqnMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNn +MoH1V6XKV0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/pj+b +OT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZOz2nxbkRs1CTqjSSh +GL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXnjSXWgXSHRtQpdaJCbPdzied9v3pK +H9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMB +AAGjQjBAMB0GA1UdDgQWBBTF7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 +YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3KliawLwQ8hOnThJ +dMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u+2D2/VnGKhs/I0qUJDAnyIm8 +60Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuh +TaRjAv04l5U/BXCga99igUOLtFkNSoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW +4AB+dAb/OMRyHdOoP2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmp +GQrI+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRzznfSxqxx +4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9eVzYH6Eze9mCUAyTF6ps +3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4S +SPfSKcOYKMryMguTjClPPGAyzQWWYezyr/6zcCwupvI= +-----END CERTIFICATE----- + +BJCA Global Root CA2 +==================== +-----BEGIN CERTIFICATE----- +MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQswCQYDVQQGEwJD +TjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJVFkxHTAbBgNVBAMMFEJKQ0Eg +R2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgyMVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UE +BhMCQ04xJjAkBgNVBAoMHUJFSUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRC +SkNBIEdsb2JhbCBSb290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jl +SR9BIgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK++kpRuDCK +/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJKsVF/BvDRgh9Obl+rg/xI +1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8 +W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8g +UXOQwKhbYdDFUDn9hf7B43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== +-----END CERTIFICATE----- + +Sectigo Public Server Authentication Root E46 +============================================= +-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQswCQYDVQQGEwJH +QjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBTZXJ2 +ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5 +WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0 +aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUr +gQQAIgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccCWvkEN/U0 +NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+6xnOQ6OjQjBAMB0GA1Ud +DgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAKBggqhkjOPQQDAwNnADBkAjAn7qRaqCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RH +lAFWovgzJQxC36oCMB3q4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21U +SAGKcw== +-----END CERTIFICATE----- + +Sectigo Public Server Authentication Root R46 +============================================= +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBfMQswCQYDVQQG +EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1 +OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDaef0rty2k +1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnzSDBh+oF8HqcIStw+Kxwf +GExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xfiOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMP +FF1bFOdLvt30yNoDN9HWOaEhUTCDsG3XME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vu +ZDCQOc2TZYEhMbUjUDM3IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5Qaz +Yw6A3OASVYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgESJ/A +wSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu+Zd4KKTIRJLpfSYF +plhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt8uaZFURww3y8nDnAtOFr94MlI1fZ +EoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+LHaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW +6aWWrL3DkJiy4Pmi1KZHQ3xtzwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWI +IUkwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQYKlJfp/imTYp +E0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52gDY9hAaLMyZlbcp+nv4fjFg4 +exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZAFv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M +0ejf5lG5Nkc/kLnHvALcWxxPDkjBJYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI +84HxZmduTILA7rpXDhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9m +pFuiTdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5dHn5Hrwd +Vw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65LvKRRFHQV80MNNVIIb/b +E/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmm +J1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAYQqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE----- + +SSL.com TLS RSA Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQG +EwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBSU0Eg +Um9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloXDTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMC +VVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u +9nTPL3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OYt6/wNr/y +7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0insS657Lb85/bRi3pZ7Qcac +oOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3PnxEX4MN8/HdIGkWCVDi1FW24IBydm5M +R7d1VVm0U3TZlMZBrViKMWYPHqIbKUBOL9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDG +D6C1vBdOSHtRwvzpXGk3R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEW +TO6Af77wdr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS+YCk +8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYSd66UNHsef8JmAOSq +g+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoGAtUjHBPW6dvbxrB6y3snm/vg1UYk +7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2fgTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsu +N+7jhHonLs0ZNbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsMQtfhWsSWTVTN +j8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvfR4iyrT7gJ4eLSYwfqUdYe5by +iB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJDPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjU +o3KUQyxi4U5cMj29TH0ZR6LDSeeWP4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqo +ENjwuSfr98t67wVylrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7Egkaib +MOlqbLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2wAgDHbICi +vRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3qr5nsLFR+jM4uElZI7xc7 +P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sjiMho6/4UIyYOf8kpIEFR3N+2ivEC+5BB0 +9+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- + +SSL.com TLS ECC Root CA 2022 +============================ +-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV +UzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxTU0wuY29tIFRMUyBFQ0MgUm9v +dCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMx +GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWy +JGYmacCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFNSeR7T5v1 +5wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSJjy+j6CugFFR7 +81a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NWuCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGG +MAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w +7deedWo1dlJF4AIxAMeNb0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5 +Zn6g6g== +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA ECC TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4wLAYDVQQDDCVB +dG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQswCQYD +VQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3Mg +VHJ1c3RlZFJvb3QgUm9vdCBDQSBFQ0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYT +AkRFMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6K +DP/XtXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4AjJn8ZQS +b+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2KCXWfeBmmnoJsmo7jjPX +NtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIwW5kp85wxtolrbNa9d+F851F+ +uDrNozZffPc8dz7kUK2o59JZDCaOMDtuCCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGY +a3cpetskz2VAv9LcjBHo9H1/IISpQuQo +-----END CERTIFICATE----- + +Atos TrustedRoot Root CA RSA TLS 2021 +===================================== +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBMMS4wLAYDVQQD +DCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIxMQ0wCwYDVQQKDARBdG9zMQsw +CQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0 +b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNV +BAYTAkRFMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BB +l01Z4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYvYe+W/CBG +vevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZkmGbzSoXfduP9LVq6hdK +ZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDsGY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt +0xU6kGpn8bRrZtkh68rZYnxGEFzedUlnnkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVK +PNe0OwANwI8f4UDErmwh3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMY +sluMWuPD0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzygeBY +Br3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8ANSbhqRAvNncTFd+ +rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezBc6eUWsuSZIKmAMFwoW4sKeFYV+xa +fJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lIpw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUdEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0G +CSqGSIb3DQEBDAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPso0UvFJ/1TCpl +Q3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJqM7F78PRreBrAwA0JrRUITWX +AdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuywxfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9G +slA9hGCZcbUztVdF5kJHdWoOsAgMrr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2Vkt +afcxBPTy+av5EzH4AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9q +TFsR0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuYo7Ey7Nmj +1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5dDTedk+SKlOxJTnbPP/l +PqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcEoji2jbDwN/zIIX8/syQbPYtuzE2wFg2W +HYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE----- + +TrustAsia Global Root CA G3 +=========================== +-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEMBQAwWjELMAkG +A1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMM +G1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAeFw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEw +MTlaMFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMu +MSQwIgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNST1QY4Sxz +lZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqKAtCWHwDNBSHvBm3dIZwZ +Q0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/V +P68czH5GX6zfZBCK70bwkPAPLfSIC7Epqq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1Ag +dB4SQXMeJNnKziyhWTXAyB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm +9WAPzJMshH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gXzhqc +D0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAvkV34PmVACxmZySYg +WmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msTf9FkPz2ccEblooV7WIQn3MSAPmea +mseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jAuPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCF +TIcQcf+eQxuulXUtgQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj +7zjKsK5Xf/IhMBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4wM8zAQLpw6o1 +D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2XFNFV1pF1AWZLy4jVe5jaN/T +G3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNj +duMNhXJEIlU/HHzp/LgV6FL6qj6jITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstl +cHboCoWASzY9M/eVVHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys ++TIxxHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1onAX1daBli +2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d7XB4tmBZrOFdRWOPyN9y +aFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2NtjjgKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsAS +ZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFR +JQJ6+N1rZdVtTTDIZbpoFGWsJwt0ivKH +-----END CERTIFICATE----- + +TrustAsia Global Root CA G4 +=========================== +-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMwWjELMAkGA1UE +BhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMsIEluYy4xJDAiBgNVBAMMG1Ry +dXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0yMTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJa +MFoxCzAJBgNVBAYTAkNOMSUwIwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQw +IgYDVQQDDBtUcnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATxs8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbwLxYI+hW8 +m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJijYzBhMA8GA1UdEwEB/wQF +MAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mDpm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/ +pDHel4NZg6ZvccveMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AA +bbd+NvBNEU/zy4k6LHiRUKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xk +dUfFVZDj/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNaFw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLx +eP0CflfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJEhRGnSjot +6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggqhkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2 +Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liW +pDVfG2XqYZpwI7UNo5uSUm9poIyNStDuiw7LR47QjRE= +-----END CERTIFICATE----- + +CommScope Public Trust ECC Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMwTjELMAkGA1UE +BhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBUcnVz +dCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRaFw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYT +AlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3Qg +RUNDIFJvb3QtMDIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/M +MDALj2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmUv4RDsNuE +SgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggqhkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9 +Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/nich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs7 +3u1Z/GtMMH9ZzkXpc2AVmkzw5l4lIhVtwodZ0LKOag== +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-01 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45Ft +nYSkYZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslhsuitQDy6 +uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0alDrJLpA6lfO741GIDuZNq +ihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3OjWiE260f6GBfZumbCk6SP/F2krfxQapWs +vCQz0b2If4b19bJzKo98rwjyGpg/qYFlP8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/c +Zip8UlF1y5mO6D1cv547KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTif +BSeolz7pUcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/kQO9 +lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JOHg9O5j9ZpSPcPYeo +KFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkBEa801M/XrmLTBQe0MXXgDW1XT2mH ++VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6UCBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm4 +5P3luG0wDQYJKoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 +NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQnmhUQo8mUuJM +3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+QgvfKNmwrZggvkN80V4aCRck +jXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2vtrV0KnahP/t1MJ+UXjulYPPLXAziDslg+Mkf +Foom3ecnf+slpoq9uC02EJqxWE2aaE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/W +NyVntHKLr4W96ioDj8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+ +o/E4Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0wlREQKC6/ +oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHnYfkUyq+Dj7+vsQpZXdxc +1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVocicCMb3SgazNNtQEo/a2tiRc7ppqEvOuM +6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw +-----END CERTIFICATE----- + +CommScope Public Trust RSA Root-02 +================================== +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQELBQAwTjELMAkG +A1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29tbVNjb3BlIFB1YmxpYyBU +cnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNV +BAYTAlVTMRIwEAYDVQQKDAlDb21tU2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1 +c3QgUlNBIFJvb3QtMDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3V +rCLENQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0kyI9p+Kx +7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1CrWDaSWqVcN3SAOLMV2MC +e5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxzhkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2W +Wy09X6GDRl224yW4fKcZgBzqZUPckXk2LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rp +M9kzXzehxfCrPfp4sOcsn/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIf +hs1w/tkuFT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5kQMr +eyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3wNemKfrb3vOTlycE +VS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6vwQcQeKwRoi9C8DfF8rhW3Q5iLc4t +Vn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7Gx +cJXvYXowDQYJKoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB +KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3+VGXu6TwYofF +1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbymeAPnCKfWxkxlSaRosTKCL4BWa +MS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3NyqpgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xd +gSGn2rtO/+YHqP65DSdsu3BaVXoT6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2O +HG1QAk8mGEPej1WFsQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+Nm +YWvtPjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2dlklyALKr +dVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670v64fG9PiO/yzcnMcmyiQ +iRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17Org3bhzjlP1v9mxnhMUF6cKojawHhRUzN +lM47ni3niAIi9G7oyOzWPPO5std3eqx7 +-----END CERTIFICATE----- + +Telekom Security TLS ECC Root 2020 +================================== +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQswCQYDVQQGEwJE +RTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJUZWxl +a29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIwMB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIz +NTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkg +R21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqG +SM49AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/OtdKPD/M1 +2kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDPf8iAC8GXs7s1J8nCG6NC +MEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6fMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P +AQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZ +Mo7k+5Dck2TOrbRBR2Diz6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdU +ga/sf+Rn27iQ7t0l +-----END CERTIFICATE----- + +Telekom Security TLS RSA Root 2023 +================================== +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQG +EwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBHbWJIMSswKQYDVQQDDCJU +ZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAyMDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMy +NzIzNTk1OVowYzELMAkGA1UEBhMCREUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJp +dHkgR21iSDErMCkGA1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9cUD/h3VC +KSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHVcp6R+SPWcHu79ZvB7JPP +GeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMAU6DksquDOFczJZSfvkgdmOGjup5czQRx +UX11eKvzWarE4GC+j4NSuHUaQTXtvPM6Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWo +l8hHD/BeEIvnHRz+sTugBTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9 +FIS3R/qy8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73Jco4v +zLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg8qKrBC7m8kwOFjQg +rIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8rFEz0ciD0cmfHdRHNCk+y7AO+oML +KFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7S +WWO/gLCMk3PLNaaZlSJhZQNg+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUtqeXgj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQpGv7qHBFfLp+ +sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm9S3ul0A8Yute1hTWjOKWi0Fp +kzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErwM807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy +/SKE8YXJN3nptT+/XOR0so8RYgDdGGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4 +mZqTuXNnQkYRIer+CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtz +aL1txKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+w6jv/naa +oqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aKL4x35bcF7DvB7L6Gs4a8 +wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+ljX273CXE2whJdV/LItM3z7gLfEdxquVeE +HVlNjM7IDiPCtyaaEBRx/pOyiriA8A4QntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0 +o82bNSQ3+pCTE4FCxpgmdTdmQRCsu/WU48IxK63nI1bMNSWSs1A= +-----END CERTIFICATE----- diff --git a/vendor/composer/ca-bundle/src/CaBundle.php b/vendor/composer/ca-bundle/src/CaBundle.php new file mode 100644 index 0000000..f6f2afe --- /dev/null +++ b/vendor/composer/ca-bundle/src/CaBundle.php @@ -0,0 +1,325 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Composer\CaBundle; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Process\PhpProcess; + +/** + * @author Chris Smith + * @author Jordi Boggiano + */ +class CaBundle +{ + /** @var string|null */ + private static $caPath; + /** @var array */ + private static $caFileValidity = array(); + + /** + * Returns the system CA bundle path, or a path to the bundled one + * + * This method was adapted from Sslurp. + * https://github.com/EvanDotPro/Sslurp + * + * (c) Evan Coury + * + * For the full copyright and license information, please see below: + * + * Copyright (c) 2013, Evan Coury + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * @param LoggerInterface $logger optional logger for information about which CA files were loaded + * @return string path to a CA bundle file or directory + */ + public static function getSystemCaRootBundlePath(?LoggerInterface $logger = null) + { + if (self::$caPath !== null) { + return self::$caPath; + } + $caBundlePaths = array(); + + // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $caBundlePaths[] = self::getEnvVariable('SSL_CERT_FILE'); + + // If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $caBundlePaths[] = self::getEnvVariable('SSL_CERT_DIR'); + + $caBundlePaths[] = ini_get('openssl.cafile'); + $caBundlePaths[] = ini_get('openssl.capath'); + + $otherLocations = array( + '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) + '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package) + '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package) + '/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package) + '/usr/ssl/certs/ca-bundle.crt', // Cygwin + '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package + '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option) + '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat? + '/etc/ssl/cert.pem', // OpenBSD + '/usr/local/etc/ssl/cert.pem', // FreeBSD 10.x + '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package + '/usr/local/etc/openssl@1.1/cert.pem', // OS X homebrew, openssl@1.1 package + '/opt/homebrew/etc/openssl@3/cert.pem', // macOS silicon homebrew, openssl@3 package + '/opt/homebrew/etc/openssl@1.1/cert.pem', // macOS silicon homebrew, openssl@1.1 package + ); + + foreach($otherLocations as $location) { + $otherLocations[] = dirname($location); + } + + $caBundlePaths = array_merge($caBundlePaths, $otherLocations); + + foreach ($caBundlePaths as $caBundle) { + if ($caBundle && self::caFileUsable($caBundle, $logger)) { + return self::$caPath = $caBundle; + } + + if ($caBundle && self::caDirUsable($caBundle, $logger)) { + return self::$caPath = $caBundle; + } + } + + return self::$caPath = static::getBundledCaBundlePath(); // Bundled CA file, last resort + } + + /** + * Returns the path to the bundled CA file + * + * In case you don't want to trust the user or the system, you can use this directly + * + * @return string path to a CA bundle file + */ + public static function getBundledCaBundlePath() + { + $caBundleFile = __DIR__.'/../res/cacert.pem'; + + // cURL does not understand 'phar://' paths + // see https://github.com/composer/ca-bundle/issues/10 + if (0 === strpos($caBundleFile, 'phar://')) { + $tempCaBundleFile = tempnam(sys_get_temp_dir(), 'openssl-ca-bundle-'); + if (false === $tempCaBundleFile) { + throw new \RuntimeException('Could not create a temporary file to store the bundled CA file'); + } + + file_put_contents( + $tempCaBundleFile, + file_get_contents($caBundleFile) + ); + + register_shutdown_function(function() use ($tempCaBundleFile) { + @unlink($tempCaBundleFile); + }); + + $caBundleFile = $tempCaBundleFile; + } + + return $caBundleFile; + } + + /** + * Validates a CA file using opensl_x509_parse only if it is safe to use + * + * @param string $filename + * @param LoggerInterface $logger optional logger for information about which CA files were loaded + * + * @return bool + */ + public static function validateCaFile($filename, ?LoggerInterface $logger = null) + { + static $warned = false; + + if (isset(self::$caFileValidity[$filename])) { + return self::$caFileValidity[$filename]; + } + + $contents = file_get_contents($filename); + + if (is_string($contents) && strlen($contents) > 0) { + $contents = preg_replace("/^(\\-+(?:BEGIN|END))\\s+TRUSTED\\s+(CERTIFICATE\\-+)\$/m", '$1 $2', $contents); + if (null === $contents) { + // regex extraction failed + $isValid = false; + } else { + $isValid = (bool) openssl_x509_parse($contents); + } + } else { + $isValid = false; + } + + if ($logger) { + $logger->debug('Checked CA file '.realpath($filename).': '.($isValid ? 'valid' : 'invalid')); + } + + return self::$caFileValidity[$filename] = $isValid; + } + + /** + * Test if it is safe to use the PHP function openssl_x509_parse(). + * + * This checks if OpenSSL extensions is vulnerable to remote code execution + * via the exploit documented as CVE-2013-6420. + * + * @return bool + */ + public static function isOpensslParseSafe() + { + return true; + } + + /** + * Resets the static caches + * @return void + */ + public static function reset() + { + self::$caFileValidity = array(); + self::$caPath = null; + } + + /** + * @param string $name + * @return string|false + */ + private static function getEnvVariable($name) + { + if (isset($_SERVER[$name])) { + return (string) $_SERVER[$name]; + } + + if (PHP_SAPI === 'cli' && ($value = getenv($name)) !== false && $value !== null) { + return (string) $value; + } + + return false; + } + + /** + * @param string|false $certFile + * @param LoggerInterface|null $logger + * @return bool + */ + private static function caFileUsable($certFile, ?LoggerInterface $logger = null) + { + return $certFile + && self::isFile($certFile, $logger) + && self::isReadable($certFile, $logger) + && self::validateCaFile($certFile, $logger); + } + + /** + * @param string|false $certDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function caDirUsable($certDir, ?LoggerInterface $logger = null) + { + return $certDir + && self::isDir($certDir, $logger) + && self::isReadable($certDir, $logger) + && self::glob($certDir . '/*', $logger); + } + + /** + * @param string $certFile + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isFile($certFile, ?LoggerInterface $logger = null) + { + $isFile = @is_file($certFile); + if (!$isFile && $logger) { + $logger->debug(sprintf('Checked CA file %s does not exist or it is not a file.', $certFile)); + } + + return $isFile; + } + + /** + * @param string $certDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isDir($certDir, ?LoggerInterface $logger = null) + { + $isDir = @is_dir($certDir); + if (!$isDir && $logger) { + $logger->debug(sprintf('Checked directory %s does not exist or it is not a directory.', $certDir)); + } + + return $isDir; + } + + /** + * @param string $certFileOrDir + * @param LoggerInterface|null $logger + * @return bool + */ + private static function isReadable($certFileOrDir, ?LoggerInterface $logger = null) + { + $isReadable = @is_readable($certFileOrDir); + if (!$isReadable && $logger) { + $logger->debug(sprintf('Checked file or directory %s is not readable.', $certFileOrDir)); + } + + return $isReadable; + } + + /** + * @param string $pattern + * @param LoggerInterface|null $logger + * @return bool + */ + private static function glob($pattern, ?LoggerInterface $logger = null) + { + $certs = glob($pattern); + if ($certs === false) { + if ($logger) { + $logger->debug(sprintf("An error occurred while trying to find certificates for pattern: %s", $pattern)); + } + return false; + } + + if (count($certs) === 0) { + if ($logger) { + $logger->debug(sprintf("No CA files found for pattern: %s", $pattern)); + } + return false; + } + + return true; + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000..a7ae664 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,3870 @@ +{ + "packages": [ + { + "name": "adbario/php-dot-notation", + "version": "2.5.0", + "version_normalized": "2.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/adbario/php-dot-notation.git", + "reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae", + "reference": "081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^5.5 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7|^6.6|^7.5|^8.5|^9.5", + "squizlabs/php_codesniffer": "^3.6" + }, + "time": "2022-10-14T20:31:46+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Adbar\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Riku Särkinen", + "email": "riku@adbar.io" + } + ], + "description": "PHP dot notation access to arrays", + "homepage": "https://github.com/adbario/php-dot-notation", + "keywords": [ + "ArrayAccess", + "dotnotation" + ], + "support": { + "issues": "https://github.com/adbario/php-dot-notation/issues", + "source": "https://github.com/adbario/php-dot-notation/tree/2.5.0" + }, + "install-path": "../adbario/php-dot-notation" + }, + { + "name": "alibabacloud/client", + "version": "1.5.32", + "version_normalized": "1.5.32.0", + "source": { + "type": "git", + "url": "https://github.com/aliyun/openapi-sdk-php-client.git", + "reference": "5bc6f6d660797dcee2c3aef29700ab41ee764f4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aliyun/openapi-sdk-php-client/zipball/5bc6f6d660797dcee2c3aef29700ab41ee764f4d", + "reference": "5bc6f6d660797dcee2c3aef29700ab41ee764f4d", + "shasum": "" + }, + "require": { + "adbario/php-dot-notation": "^2.4.1", + "clagiordano/weblibs-configmanager": "^1.0", + "ext-curl": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-simplexml": "*", + "ext-xmlwriter": "*", + "guzzlehttp/guzzle": "^6.3|^7.0", + "mtdowling/jmespath.php": "^2.5", + "php": ">=5.5" + }, + "require-dev": { + "composer/composer": "^1.8", + "drupal/coder": "^8.3", + "ext-dom": "*", + "ext-pcre": "*", + "ext-sockets": "*", + "ext-spl": "*", + "league/climate": "^3.2.4", + "mikey179/vfsstream": "^1.6", + "monolog/monolog": "^1.24", + "phpunit/phpunit": "^5.7|^6.6|^7.5|^8.5|^9.5", + "psr/cache": "^1.0", + "symfony/dotenv": "^3.4", + "symfony/var-dumper": "^3.4" + }, + "suggest": { + "ext-sockets": "To use client-side monitoring" + }, + "time": "2022-12-09T04:05:55+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "AlibabaCloud\\Client\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Alibaba Cloud SDK", + "email": "sdk-team@alibabacloud.com", + "homepage": "http://www.alibabacloud.com" + } + ], + "description": "Alibaba Cloud Client for PHP - Use Alibaba Cloud in your PHP project", + "homepage": "https://www.alibabacloud.com/", + "keywords": [ + "alibaba", + "alibabacloud", + "aliyun", + "client", + "cloud", + "library", + "sdk", + "tool" + ], + "support": { + "issues": "https://github.com/aliyun/openapi-sdk-php-client/issues", + "source": "https://github.com/aliyun/openapi-sdk-php-client" + }, + "install-path": "../alibabacloud/client" + }, + { + "name": "carbonphp/carbon-doctrine-types", + "version": "2.1.0", + "version_normalized": "2.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git", + "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", + "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "doctrine/dbal": "<3.7.0 || >=4.0.0" + }, + "require-dev": { + "doctrine/dbal": "^3.7.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "time": "2023-12-11T17:09:12+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "install-path": "../carbonphp/carbon-doctrine-types" + }, + { + "name": "clagiordano/weblibs-configmanager", + "version": "v1.2.0", + "version_normalized": "1.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/clagiordano/weblibs-configmanager.git", + "reference": "5c8ebcc62782313b1278afe802b120d18c07a059" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clagiordano/weblibs-configmanager/zipball/5c8ebcc62782313b1278afe802b120d18c07a059", + "reference": "5c8ebcc62782313b1278afe802b120d18c07a059", + "shasum": "" + }, + "require": { + "php": ">=5.4" + }, + "require-dev": { + "clagiordano/phpunit-result-printer": "^1", + "phpunit/phpunit": "^4.8" + }, + "time": "2021-05-18T17:55:57+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "clagiordano\\weblibs\\configmanager\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Claudio Giordano", + "email": "claudio.giordano@autistici.org", + "role": "Developer" + } + ], + "description": "weblibs-configmanager is a tool library for easily read and access to php config array file and direct read/write configuration file / object", + "keywords": [ + "clagiordano", + "configuration", + "manager", + "tool", + "weblibs" + ], + "support": { + "issues": "https://github.com/clagiordano/weblibs-configmanager/issues", + "source": "https://github.com/clagiordano/weblibs-configmanager/tree/v1.2.0" + }, + "install-path": "../clagiordano/weblibs-configmanager" + }, + { + "name": "composer/ca-bundle", + "version": "1.5.0", + "version_normalized": "1.5.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", + "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "time": "2024-03-15T14:00:32+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.5.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "install-path": "./ca-bundle" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.17.0", + "version_normalized": "4.17.0.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/bbc513d79acf6691fa9cf10f192c90dd2957f18c", + "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "time": "2023-11-17T15:01:25+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.17.0" + }, + "install-path": "../ezyang/htmlpurifier" + }, + { + "name": "firebase/php-jwt", + "version": "v6.10.0", + "version_normalized": "6.10.0.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "a49db6f0a5033aef5143295342f1c95521b075ff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/a49db6f0a5033aef5143295342f1c95521b075ff", + "reference": "a49db6f0a5033aef5143295342f1c95521b075ff", + "shasum": "" + }, + "require": { + "php": "^7.4||^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^6.5||^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^1.0||^2.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "time": "2023-12-01T16:26:39+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.10.0" + }, + "install-path": "../firebase/php-jwt" + }, + { + "name": "geoip2/geoip2", + "version": "v2.13.0", + "version_normalized": "2.13.0.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/GeoIP2-php.git", + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/6a41d8fbd6b90052bc34dff3b4252d0f88067b23", + "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23", + "shasum": "" + }, + "require": { + "ext-json": "*", + "maxmind-db/reader": "~1.8", + "maxmind/web-service-common": "~0.8", + "php": ">=7.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^8.0 || ^9.0", + "squizlabs/php_codesniffer": "3.*" + }, + "time": "2022-08-05T20:32:58+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "GeoIp2\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "description": "MaxMind GeoIP2 PHP API", + "homepage": "https://github.com/maxmind/GeoIP2-php", + "keywords": [ + "IP", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], + "support": { + "issues": "https://github.com/maxmind/GeoIP2-php/issues", + "source": "https://github.com/maxmind/GeoIP2-php/tree/v2.13.0" + }, + "install-path": "../geoip2/geoip2" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.8.1", + "version_normalized": "7.8.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104", + "reference": "41042bc7ab002487b876a0683fc8dce04ddce104", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.1", + "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "time": "2023-12-03T20:35:24+00:00", + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.8.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/guzzle" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.2", + "version_normalized": "2.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223", + "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" + }, + "time": "2023-12-03T20:19:20+00:00", + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/promises" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.6.2", + "version_normalized": "2.6.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221", + "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.36 || ^9.6.15" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "time": "2023-12-03T20:05:35+00:00", + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.6.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "install-path": "../guzzlehttp/psr7" + }, + { + "name": "itinysun/tp-model-helper", + "version": "v1.0.2", + "version_normalized": "1.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/Itinysun/tp-model-helper.git", + "reference": "ab280d3ad6321ef4c3951690153520d34497323f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Itinysun/tp-model-helper/zipball/ab280d3ad6321ef4c3951690153520d34497323f", + "reference": "ab280d3ad6321ef4c3951690153520d34497323f", + "shasum": "" + }, + "require": { + "phpdocumentor/reflection-docblock": "^3.1", + "symfony/class-loader": "^2.3|^3.0", + "topthink/framework": "^6.0", + "topthink/think-helper": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.6" + }, + "time": "2021-11-03T13:21:13+00:00", + "type": "library", + "extra": { + "think": { + "services": [ + "itinysun\\model\\helper\\Service" + ], + "config": { + "model_help": "config/config.php" + } + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "itinysun\\model\\helper\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Itinysun", + "email": "860760361@qq.com" + } + ], + "description": "a vendor for thinkphp6.*,help generate phpdocs for model class", + "support": { + "issues": "https://github.com/Itinysun/tp-model-helper/issues", + "source": "https://github.com/Itinysun/tp-model-helper/tree/v1.0.2" + }, + "install-path": "../itinysun/tp-model-helper" + }, + { + "name": "lcobucci/clock", + "version": "2.0.0", + "version_normalized": "2.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/clock.git", + "reference": "353d83fe2e6ae95745b16b3d911813df6a05bfb3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/353d83fe2e6ae95745b16b3d911813df6a05bfb3", + "reference": "353d83fe2e6ae95745b16b3d911813df6a05bfb3", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "infection/infection": "^0.17", + "lcobucci/coding-standard": "^6.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/php-code-coverage": "9.1.4", + "phpunit/phpunit": "9.3.7" + }, + "time": "2020-08-27T18:56:02+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Lcobucci\\Clock\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com" + } + ], + "description": "Yet another clock abstraction", + "support": { + "issues": "https://github.com/lcobucci/clock/issues", + "source": "https://github.com/lcobucci/clock/tree/2.0.x" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "install-path": "../lcobucci/clock" + }, + { + "name": "lcobucci/jwt", + "version": "4.0.4", + "version_normalized": "4.0.4.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "55564265fddf810504110bd68ca311932324b0e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/55564265fddf810504110bd68ca311932324b0e9", + "reference": "55564265fddf810504110bd68ca311932324b0e9", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-openssl": "*", + "lcobucci/clock": "^2.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "infection/infection": "^0.20", + "lcobucci/coding-standard": "^6.0", + "mikey179/vfsstream": "^1.6", + "phpbench/phpbench": "^0.17", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-deprecation-rules": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/php-invoker": "^3.1", + "phpunit/phpunit": "^9.4" + }, + "time": "2021-09-28T19:18:28+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "install-path": "../lcobucci/jwt" + }, + { + "name": "league/flysystem", + "version": "1.1.10", + "version_normalized": "1.1.10.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "time": "2022-10-04T09:16:37+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.1.10" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "install-path": "../league/flysystem" + }, + { + "name": "league/flysystem-cached-adapter", + "version": "1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-cached-adapter.git", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-cached-adapter/zipball/d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "reference": "d1925efb2207ac4be3ad0c40b8277175f99ffaff", + "shasum": "" + }, + "require": { + "league/flysystem": "~1.0", + "psr/cache": "^1.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9", + "phpspec/phpspec": "^3.4", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0", + "tedivm/stash": "~0.12" + }, + "suggest": { + "ext-phpredis": "Pure C implemented extension for PHP" + }, + "time": "2020-07-25T15:56:04+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Flysystem\\Cached\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "frankdejonge", + "email": "info@frenky.net" + } + ], + "description": "An adapter decorator to enable meta-data caching.", + "support": { + "issues": "https://github.com/thephpleague/flysystem-cached-adapter/issues", + "source": "https://github.com/thephpleague/flysystem-cached-adapter/tree/master" + }, + "install-path": "../league/flysystem-cached-adapter" + }, + { + "name": "league/mime-type-detection", + "version": "1.15.0", + "version_normalized": "1.15.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301", + "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "time": "2024-01-28T23:22:08+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "install-path": "../league/mime-type-detection" + }, + { + "name": "maennchen/zipstream-php", + "version": "2.2.6", + "version_normalized": "2.2.6.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "30ad6f93cf3efe4192bc7a4c9cad11ff8f4f237f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/30ad6f93cf3efe4192bc7a4c9cad11ff8f4f237f", + "reference": "30ad6f93cf3efe4192bc7a4c9cad11ff8f4f237f", + "shasum": "" + }, + "require": { + "myclabs/php-enum": "^1.5", + "php": "^7.4 || ^8.0", + "psr/http-message": "^1.0", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.9", + "guzzlehttp/guzzle": "^6.5.3 || ^7.2.0", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.4", + "phpunit/phpunit": "^8.5.8 || ^9.4.2", + "vimeo/psalm": "^4.1" + }, + "time": "2022-11-25T18:57:19+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/2.2.6" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + }, + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], + "install-path": "../maennchen/zipstream-php" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "version_normalized": "3.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "time": "2022-12-06T16:21:08+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "install-path": "../markbaker/complex" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "version_normalized": "3.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "time": "2022-12-02T22:17:43+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "install-path": "../markbaker/matrix" + }, + { + "name": "maxmind-db/reader", + "version": "v1.11.1", + "version_normalized": "1.11.1.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", + "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/1e66f73ffcf25e17c7a910a1317e9720a95497c7", + "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "conflict": { + "ext-maxminddb": "<1.11.1,>=2.0.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "php-coveralls/php-coveralls": "^2.1", + "phpstan/phpstan": "*", + "phpunit/phpcov": ">=6.0.0", + "phpunit/phpunit": ">=8.0.0,<10.0.0", + "squizlabs/php_codesniffer": "3.*" + }, + "suggest": { + "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", + "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" + }, + "time": "2023-12-02T00:09:23+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "MaxMind\\Db\\": "src/MaxMind/Db" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory J. Oschwald", + "email": "goschwald@maxmind.com", + "homepage": "https://www.maxmind.com/" + } + ], + "description": "MaxMind DB Reader API", + "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php", + "keywords": [ + "database", + "geoip", + "geoip2", + "geolocation", + "maxmind" + ], + "support": { + "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", + "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.11.1" + }, + "install-path": "../maxmind-db/reader" + }, + { + "name": "maxmind/web-service-common", + "version": "v0.9.0", + "version_normalized": "0.9.0.0", + "source": { + "type": "git", + "url": "https://github.com/maxmind/web-service-common-php.git", + "reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/4dc5a3e8df38aea4ca3b1096cee3a038094e9b53", + "reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0.3", + "ext-curl": "*", + "ext-json": "*", + "php": ">=7.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "3.*", + "phpstan/phpstan": "*", + "phpunit/phpunit": "^8.0 || ^9.0", + "squizlabs/php_codesniffer": "3.*" + }, + "time": "2022-03-28T17:43:20+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "MaxMind\\Exception\\": "src/Exception", + "MaxMind\\WebService\\": "src/WebService" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Gregory Oschwald", + "email": "goschwald@maxmind.com" + } + ], + "description": "Internal MaxMind Web Service API", + "homepage": "https://github.com/maxmind/web-service-common-php", + "support": { + "issues": "https://github.com/maxmind/web-service-common-php/issues", + "source": "https://github.com/maxmind/web-service-common-php/tree/v0.9.0" + }, + "install-path": "../maxmind/web-service-common" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.7.0", + "version_normalized": "2.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/bbb69a935c2cbb0c03d7f481a238027430f6440b", + "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "time": "2023-08-25T10:54:48+00:00", + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.7.0" + }, + "install-path": "../mtdowling/jmespath.php" + }, + { + "name": "myclabs/php-enum", + "version": "1.8.4", + "version_normalized": "1.8.4.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/php-enum.git", + "reference": "a867478eae49c9f59ece437ae7f9506bfaa27483" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/a867478eae49c9f59ece437ae7f9506bfaa27483", + "reference": "a867478eae49c9f59ece437ae7f9506bfaa27483", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "1.*", + "vimeo/psalm": "^4.6.2" + }, + "time": "2022-08-04T09:53:51+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "MyCLabs\\Enum\\": "src/" + }, + "classmap": [ + "stubs/Stringable.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP Enum contributors", + "homepage": "https://github.com/myclabs/php-enum/graphs/contributors" + } + ], + "description": "PHP Enum implementation", + "homepage": "http://github.com/myclabs/php-enum", + "keywords": [ + "enum" + ], + "support": { + "issues": "https://github.com/myclabs/php-enum/issues", + "source": "https://github.com/myclabs/php-enum/tree/1.8.4" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "install-path": "../myclabs/php-enum" + }, + { + "name": "nesbot/carbon", + "version": "2.72.3", + "version_normalized": "2.72.3.0", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/0c6fd108360c562f6e4fd1dedb8233b423e91c83", + "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "*", + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "psr/clock": "^1.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "doctrine/dbal": "^2.0 || ^3.1.4 || ^4.0", + "doctrine/orm": "^2.7 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.0", + "kylekatarnls/multi-tester": "^2.0", + "ondrejmirtes/better-reflection": "*", + "phpmd/phpmd": "^2.9", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.99 || ^1.7.14", + "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", + "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", + "squizlabs/php_codesniffer": "^3.4" + }, + "time": "2024-01-25T10:35:09+00:00", + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-3.x": "3.x-dev", + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/briannesbitt/Carbon/issues", + "source": "https://github.com/briannesbitt/Carbon" + }, + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "install-path": "../nesbot/carbon" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "time": "2017-09-11T18:02:19+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master" + }, + "install-path": "../phpdocumentor/reflection-common" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.3.2", + "version_normalized": "3.3.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bf329f6c1aadea3299f08ee804682b7c45b326a2", + "reference": "bf329f6c1aadea3299f08ee804682b7c45b326a2", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "phpdocumentor/reflection-common": "^1.0.0", + "phpdocumentor/type-resolver": "^0.4.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "time": "2017-11-10T14:09:06+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/3.x" + }, + "install-path": "../phpdocumentor/reflection-docblock" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.4.0", + "version_normalized": "0.4.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", + "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "time": "2017-07-14T14:27:02+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/master" + }, + "install-path": "../phpdocumentor/type-resolver" + }, + { + "name": "phpmailer/phpmailer", + "version": "v6.8.0", + "version_normalized": "6.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "df16b615e371d81fb79e506277faea67a1be18f1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/df16b615e371d81fb79e506277faea67a1be18f1", + "reference": "df16b615e371d81fb79e506277faea67a1be18f1", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2", + "doctrine/annotations": "^1.2.6 || ^1.13.3", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^9.3.5", + "roave/security-advisories": "dev-latest", + "squizlabs/php_codesniffer": "^3.7.1", + "yoast/phpunit-polyfills": "^1.0.4" + }, + "suggest": { + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "ext-openssl": "Needed for secure SMTP sending and DKIM signing", + "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", + "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" + }, + "time": "2023-03-06T14:43:22+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.8.0" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "install-path": "../phpmailer/phpmailer" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.29.0", + "version_normalized": "1.29.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fde2ccf55eaef7e86021ff1acce26479160a0fa0", + "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.15", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": "^7.4 || ^8.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^1.0 || ^2.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.3", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5 || ^9.0 || ^10.0", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "time": "2023-06-14T22:48:31+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.0" + }, + "install-path": "../phpoffice/phpspreadsheet" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2016-08-06T20:24:11+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "install-path": "../psr/cache" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "time": "2022-11-25T14:36:26+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "install-path": "../psr/clock" + }, + { + "name": "psr/container", + "version": "1.1.2", + "version_normalized": "1.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "time": "2021-11-05T16:50:12+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.2" + }, + "install-path": "../psr/container" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "version_normalized": "1.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "time": "2023-09-23T14:17:50+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "install-path": "../psr/http-client" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "time": "2024-04-15T12:06:14+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "install-path": "../psr/http-factory" + }, + { + "name": "psr/http-message", + "version": "1.1", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "time": "2023-04-04T09:50:52+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "install-path": "../psr/http-message" + }, + { + "name": "psr/log", + "version": "1.1.4", + "version_normalized": "1.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2021-05-03T11:20:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "install-path": "../psr/log" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "time": "2017-10-23T01:57:42+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "install-path": "../psr/simple-cache" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "version_normalized": "3.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "time": "2019-03-08T08:55:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "install-path": "../ralouphie/getallheaders" + }, + { + "name": "symfony/class-loader", + "version": "v3.4.47", + "version_normalized": "3.4.47.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/class-loader.git", + "reference": "a22265a9f3511c0212bf79f54910ca5a77c0e92c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/class-loader/zipball/a22265a9f3511c0212bf79f54910ca5a77c0e92c", + "reference": "a22265a9f3511c0212bf79f54910ca5a77c0e92c", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "require-dev": { + "symfony/finder": "~2.8|~3.0|~4.0", + "symfony/polyfill-apcu": "~1.1" + }, + "suggest": { + "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM" + }, + "time": "2020-10-24T10:57:07+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\ClassLoader\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony ClassLoader Component", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/class-loader/tree/v3.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": true, + "install-path": "../symfony/class-loader" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.3", + "version_normalized": "2.5.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "80d075412b557d41002320b96a096ca65aa2c98d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d", + "reference": "80d075412b557d41002320b96a096ca65aa2c98d", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2023-01-24T14:02:46+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/deprecation-contracts" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.29.0", + "version_normalized": "1.29.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "time": "2024-01-29T20:11:03+00:00", + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-mbstring" + }, + { + "name": "symfony/polyfill-php72", + "version": "v1.29.0", + "version_normalized": "1.29.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25", + "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2024-01-29T20:11:03+00:00", + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php72" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.29.0", + "version_normalized": "1.29.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2024-01-29T20:11:03+00:00", + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php80" + }, + { + "name": "symfony/process", + "version": "v5.4.39", + "version_normalized": "5.4.39.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "85a554acd7c28522241faf2e97b9541247a0d3d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/85a554acd7c28522241faf2e97b9541247a0d3d5", + "reference": "85a554acd7c28522241faf2e97b9541247a0d3d5", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "time": "2024-04-18T08:26:06+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.4.39" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/process" + }, + { + "name": "symfony/translation", + "version": "v5.4.39", + "version_normalized": "5.4.39.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "0fabede35e3985c4f96089edeeefe8313e15ca3a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/0fabede35e3985c4f96089edeeefe8313e15ca3a", + "reference": "0fabede35e3985c4f96089edeeefe8313e15ca3a", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation-contracts": "^2.3" + }, + "conflict": { + "symfony/config": "<4.4", + "symfony/console": "<5.3", + "symfony/dependency-injection": "<5.0", + "symfony/http-kernel": "<5.0", + "symfony/twig-bundle": "<5.0", + "symfony/yaml": "<4.4" + }, + "provide": { + "symfony/translation-implementation": "2.3" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/http-client-contracts": "^1.1|^2.0|^3.0", + "symfony/http-kernel": "^5.0|^6.0", + "symfony/intl": "^4.4|^5.0|^6.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/service-contracts": "^1.1.2|^2|^3", + "symfony/yaml": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "time": "2024-04-18T08:26:06+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v5.4.39" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/translation" + }, + { + "name": "symfony/translation-contracts", + "version": "v2.5.3", + "version_normalized": "2.5.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "b0073a77ac0b7ea55131020e87b1e3af540f4664" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b0073a77ac0b7ea55131020e87b1e3af540f4664", + "reference": "b0073a77ac0b7ea55131020e87b1e3af540f4664", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "time": "2024-01-23T13:51:25+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v2.5.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/translation-contracts" + }, + { + "name": "symfony/var-dumper", + "version": "v4.4.47", + "version_normalized": "4.4.47.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "time": "2022-10-03T15:15:11+00:00", + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/var-dumper" + }, + { + "name": "topthink/framework", + "version": "v6.1.3", + "version_normalized": "6.1.3.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/framework.git", + "reference": "7c324e7011246f0064b055b62ab9c3921cf0a041" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/framework/zipball/7c324e7011246f0064b055b62ab9c3921cf0a041", + "reference": "7c324e7011246f0064b055b62ab9c3921cf0a041", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=7.2.5", + "psr/container": "~1.0", + "psr/http-message": "^1.0", + "psr/log": "~1.0", + "psr/simple-cache": "^1.0", + "topthink/think-helper": "^3.1.1", + "topthink/think-orm": "^2.0|^3.0" + }, + "require-dev": { + "guzzlehttp/psr7": "^2.1.0", + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.0" + }, + "time": "2023-05-22T03:02:08+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [], + "psr-4": { + "think\\": "src/think/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + }, + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP Framework.", + "homepage": "http://thinkphp.cn/", + "keywords": [ + "framework", + "orm", + "thinkphp" + ], + "support": { + "issues": "https://github.com/top-think/framework/issues", + "source": "https://github.com/top-think/framework/tree/v6.1.3" + }, + "install-path": "../topthink/framework" + }, + { + "name": "topthink/think-filesystem", + "version": "v1.0.3", + "version_normalized": "1.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-filesystem.git", + "reference": "29f19f140a9267c717fecd7ccb22c84c2d72382e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-filesystem/zipball/29f19f140a9267c717fecd7ccb22c84c2d72382e", + "reference": "29f19f140a9267c717fecd7ccb22c84c2d72382e", + "shasum": "" + }, + "require": { + "league/flysystem": "^1.1.4", + "league/flysystem-cached-adapter": "^1.0", + "php": ">=7.2.5", + "topthink/framework": "^6.1|^8.0" + }, + "require-dev": { + "mikey179/vfsstream": "^1.6", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^8.0" + }, + "time": "2023-02-08T01:25:15+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6.1 Filesystem Package", + "support": { + "issues": "https://github.com/top-think/think-filesystem/issues", + "source": "https://github.com/top-think/think-filesystem/tree/v1.0.3" + }, + "install-path": "../topthink/think-filesystem" + }, + { + "name": "topthink/think-helper", + "version": "v3.1.6", + "version_normalized": "3.1.6.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-helper.git", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/769acbe50a4274327162f9c68ec2e89a38eb2aff", + "reference": "769acbe50a4274327162f9c68ec2e89a38eb2aff", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "time": "2021-12-15T04:27:55+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/helper.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Helper Package", + "support": { + "issues": "https://github.com/top-think/think-helper/issues", + "source": "https://github.com/top-think/think-helper/tree/v3.1.6" + }, + "install-path": "../topthink/think-helper" + }, + { + "name": "topthink/think-multi-app", + "version": "v1.0.17", + "version_normalized": "1.0.17.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-multi-app.git", + "reference": "4055a6187296ac16c0bc7bbab4ed5d92f82f791c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-multi-app/zipball/4055a6187296ac16c0bc7bbab4ed5d92f82f791c", + "reference": "4055a6187296ac16c0bc7bbab4ed5d92f82f791c", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0|^8.0" + }, + "time": "2023-03-29T02:04:29+00:00", + "type": "library", + "extra": { + "think": { + "services": [ + "think\\app\\Service" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\app\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp multi app support", + "support": { + "issues": "https://github.com/top-think/think-multi-app/issues", + "source": "https://github.com/top-think/think-multi-app/tree/v1.0.17" + }, + "install-path": "../topthink/think-multi-app" + }, + { + "name": "topthink/think-orm", + "version": "v2.0.61", + "version_normalized": "2.0.61.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-orm.git", + "reference": "10528ebf4a5106b19c3bac9c6deae7a67ff49de6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-orm/zipball/10528ebf4a5106b19c3bac9c6deae7a67ff49de6", + "reference": "10528ebf4a5106b19c3bac9c6deae7a67ff49de6", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pdo": "*", + "php": ">=7.1.0", + "psr/log": "^1.0|^2.0", + "psr/simple-cache": "^1.0|^2.0", + "topthink/think-helper": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^7|^8|^9.5" + }, + "time": "2023-04-20T14:27:51+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "stubs/load_stubs.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "think orm", + "keywords": [ + "database", + "orm" + ], + "support": { + "issues": "https://github.com/top-think/think-orm/issues", + "source": "https://github.com/top-think/think-orm/tree/v2.0.61" + }, + "install-path": "../topthink/think-orm" + }, + { + "name": "topthink/think-queue", + "version": "v3.0.9", + "version_normalized": "3.0.9.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-queue.git", + "reference": "654812b47dd7c708c4443deed27f212f8382e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-queue/zipball/654812b47dd7c708c4443deed27f212f8382e8da", + "reference": "654812b47dd7c708c4443deed27f212f8382e8da", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nesbot/carbon": "^2.16", + "symfony/process": ">=4.2", + "topthink/framework": "^6.0 || ^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^6.2", + "topthink/think-migration": "^3.0" + }, + "time": "2023-07-03T05:42:01+00:00", + "type": "library", + "extra": { + "think": { + "services": [ + "think\\queue\\Service" + ], + "config": { + "queue": "src/config.php" + } + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "src/common.php" + ], + "psr-4": { + "think\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "yunwuxin", + "email": "448901948@qq.com" + } + ], + "description": "The ThinkPHP6 Queue Package", + "support": { + "issues": "https://github.com/top-think/think-queue/issues", + "source": "https://github.com/top-think/think-queue/tree/v3.0.9" + }, + "install-path": "../topthink/think-queue" + }, + { + "name": "topthink/think-trace", + "version": "v1.6", + "version_normalized": "1.6.0.0", + "source": { + "type": "git", + "url": "https://github.com/top-think/think-trace.git", + "reference": "136cd5d97e8bdb780e4b5c1637c588ed7ca3e142" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/top-think/think-trace/zipball/136cd5d97e8bdb780e4b5c1637c588ed7ca3e142", + "reference": "136cd5d97e8bdb780e4b5c1637c588ed7ca3e142", + "shasum": "" + }, + "require": { + "php": ">=7.1.0", + "topthink/framework": "^6.0|^8.0" + }, + "time": "2023-02-07T08:36:32+00:00", + "type": "library", + "extra": { + "think": { + "services": [ + "think\\trace\\Service" + ], + "config": { + "trace": "src/config.php" + } + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "think\\trace\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "liu21st", + "email": "liu21st@gmail.com" + } + ], + "description": "thinkphp debug trace", + "support": { + "issues": "https://github.com/top-think/think-trace/issues", + "source": "https://github.com/top-think/think-trace/tree/v1.6" + }, + "install-path": "../topthink/think-trace" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "version_normalized": "1.11.0.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "time": "2022-06-03T18:03:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "install-path": "../webmozart/assert" + } + ], + "dev": true, + "dev-package-names": [ + "symfony/polyfill-php72", + "symfony/var-dumper", + "topthink/think-trace" + ] +} diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 0000000..2c99547 --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,557 @@ + array( + 'name' => 'topthink/think', + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'reference' => null, + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + 'adbario/php-dot-notation' => array( + 'pretty_version' => '2.5.0', + 'version' => '2.5.0.0', + 'reference' => '081e2cca50c84bfeeea2e3ef9b2c8d206d80ccae', + 'type' => 'library', + 'install_path' => __DIR__ . '/../adbario/php-dot-notation', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'alibabacloud/client' => array( + 'pretty_version' => '1.5.32', + 'version' => '1.5.32.0', + 'reference' => '5bc6f6d660797dcee2c3aef29700ab41ee764f4d', + 'type' => 'library', + 'install_path' => __DIR__ . '/../alibabacloud/client', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'carbonphp/carbon-doctrine-types' => array( + 'pretty_version' => '2.1.0', + 'version' => '2.1.0.0', + 'reference' => '99f76ffa36cce3b70a4a6abce41dba15ca2e84cb', + 'type' => 'library', + 'install_path' => __DIR__ . '/../carbonphp/carbon-doctrine-types', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'clagiordano/weblibs-configmanager' => array( + 'pretty_version' => 'v1.2.0', + 'version' => '1.2.0.0', + 'reference' => '5c8ebcc62782313b1278afe802b120d18c07a059', + 'type' => 'library', + 'install_path' => __DIR__ . '/../clagiordano/weblibs-configmanager', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'composer/ca-bundle' => array( + 'pretty_version' => '1.5.0', + 'version' => '1.5.0.0', + 'reference' => '0c5ccfcfea312b5c5a190a21ac5cef93f74baf99', + 'type' => 'library', + 'install_path' => __DIR__ . '/./ca-bundle', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ezyang/htmlpurifier' => array( + 'pretty_version' => 'v4.17.0', + 'version' => '4.17.0.0', + 'reference' => 'bbc513d79acf6691fa9cf10f192c90dd2957f18c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ezyang/htmlpurifier', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'firebase/php-jwt' => array( + 'pretty_version' => 'v6.10.0', + 'version' => '6.10.0.0', + 'reference' => 'a49db6f0a5033aef5143295342f1c95521b075ff', + 'type' => 'library', + 'install_path' => __DIR__ . '/../firebase/php-jwt', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'geoip2/geoip2' => array( + 'pretty_version' => 'v2.13.0', + 'version' => '2.13.0.0', + 'reference' => '6a41d8fbd6b90052bc34dff3b4252d0f88067b23', + 'type' => 'library', + 'install_path' => __DIR__ . '/../geoip2/geoip2', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/guzzle' => array( + 'pretty_version' => '7.8.1', + 'version' => '7.8.1.0', + 'reference' => '41042bc7ab002487b876a0683fc8dce04ddce104', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/guzzle', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/promises' => array( + 'pretty_version' => '2.0.2', + 'version' => '2.0.2.0', + 'reference' => 'bbff78d96034045e58e13dedd6ad91b5d1253223', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/promises', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'guzzlehttp/psr7' => array( + 'pretty_version' => '2.6.2', + 'version' => '2.6.2.0', + 'reference' => '45b30f99ac27b5ca93cb4831afe16285f57b8221', + 'type' => 'library', + 'install_path' => __DIR__ . '/../guzzlehttp/psr7', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'itinysun/tp-model-helper' => array( + 'pretty_version' => 'v1.0.2', + 'version' => '1.0.2.0', + 'reference' => 'ab280d3ad6321ef4c3951690153520d34497323f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../itinysun/tp-model-helper', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'lcobucci/clock' => array( + 'pretty_version' => '2.0.0', + 'version' => '2.0.0.0', + 'reference' => '353d83fe2e6ae95745b16b3d911813df6a05bfb3', + 'type' => 'library', + 'install_path' => __DIR__ . '/../lcobucci/clock', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'lcobucci/jwt' => array( + 'pretty_version' => '4.0.4', + 'version' => '4.0.4.0', + 'reference' => '55564265fddf810504110bd68ca311932324b0e9', + 'type' => 'library', + 'install_path' => __DIR__ . '/../lcobucci/jwt', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/flysystem' => array( + 'pretty_version' => '1.1.10', + 'version' => '1.1.10.0', + 'reference' => '3239285c825c152bcc315fe0e87d6b55f5972ed1', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/flysystem', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/flysystem-cached-adapter' => array( + 'pretty_version' => '1.1.0', + 'version' => '1.1.0.0', + 'reference' => 'd1925efb2207ac4be3ad0c40b8277175f99ffaff', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/flysystem-cached-adapter', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'league/mime-type-detection' => array( + 'pretty_version' => '1.15.0', + 'version' => '1.15.0.0', + 'reference' => 'ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301', + 'type' => 'library', + 'install_path' => __DIR__ . '/../league/mime-type-detection', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'maennchen/zipstream-php' => array( + 'pretty_version' => '2.2.6', + 'version' => '2.2.6.0', + 'reference' => '30ad6f93cf3efe4192bc7a4c9cad11ff8f4f237f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../maennchen/zipstream-php', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'markbaker/complex' => array( + 'pretty_version' => '3.0.2', + 'version' => '3.0.2.0', + 'reference' => '95c56caa1cf5c766ad6d65b6344b807c1e8405b9', + 'type' => 'library', + 'install_path' => __DIR__ . '/../markbaker/complex', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'markbaker/matrix' => array( + 'pretty_version' => '3.0.1', + 'version' => '3.0.1.0', + 'reference' => '728434227fe21be27ff6d86621a1b13107a2562c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../markbaker/matrix', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'maxmind-db/reader' => array( + 'pretty_version' => 'v1.11.1', + 'version' => '1.11.1.0', + 'reference' => '1e66f73ffcf25e17c7a910a1317e9720a95497c7', + 'type' => 'library', + 'install_path' => __DIR__ . '/../maxmind-db/reader', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'maxmind/web-service-common' => array( + 'pretty_version' => 'v0.9.0', + 'version' => '0.9.0.0', + 'reference' => '4dc5a3e8df38aea4ca3b1096cee3a038094e9b53', + 'type' => 'library', + 'install_path' => __DIR__ . '/../maxmind/web-service-common', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'mtdowling/jmespath.php' => array( + 'pretty_version' => '2.7.0', + 'version' => '2.7.0.0', + 'reference' => 'bbb69a935c2cbb0c03d7f481a238027430f6440b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../mtdowling/jmespath.php', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'myclabs/php-enum' => array( + 'pretty_version' => '1.8.4', + 'version' => '1.8.4.0', + 'reference' => 'a867478eae49c9f59ece437ae7f9506bfaa27483', + 'type' => 'library', + 'install_path' => __DIR__ . '/../myclabs/php-enum', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'nesbot/carbon' => array( + 'pretty_version' => '2.72.3', + 'version' => '2.72.3.0', + 'reference' => '0c6fd108360c562f6e4fd1dedb8233b423e91c83', + 'type' => 'library', + 'install_path' => __DIR__ . '/../nesbot/carbon', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'phpdocumentor/reflection-common' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'reference' => '21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpdocumentor/reflection-common', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'phpdocumentor/reflection-docblock' => array( + 'pretty_version' => '3.3.2', + 'version' => '3.3.2.0', + 'reference' => 'bf329f6c1aadea3299f08ee804682b7c45b326a2', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpdocumentor/reflection-docblock', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'phpdocumentor/type-resolver' => array( + 'pretty_version' => '0.4.0', + 'version' => '0.4.0.0', + 'reference' => '9c977708995954784726e25d0cd1dddf4e65b0f7', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpdocumentor/type-resolver', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'phpmailer/phpmailer' => array( + 'pretty_version' => 'v6.8.0', + 'version' => '6.8.0.0', + 'reference' => 'df16b615e371d81fb79e506277faea67a1be18f1', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpmailer/phpmailer', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'phpoffice/phpspreadsheet' => array( + 'pretty_version' => '1.29.0', + 'version' => '1.29.0.0', + 'reference' => 'fde2ccf55eaef7e86021ff1acce26479160a0fa0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/cache' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/cache', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/clock' => array( + 'pretty_version' => '1.0.0', + 'version' => '1.0.0.0', + 'reference' => 'e41a24703d4560fd0acb709162f73b8adfc3aa0d', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/clock', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/clock-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/container' => array( + 'pretty_version' => '1.1.2', + 'version' => '1.1.2.0', + 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/container', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-client' => array( + 'pretty_version' => '1.0.3', + 'version' => '1.0.3.0', + 'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-client', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-client-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/http-factory' => array( + 'pretty_version' => '1.1.0', + 'version' => '1.1.0.0', + 'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-factory', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-factory-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/http-message' => array( + 'pretty_version' => '1.1', + 'version' => '1.1.0.0', + 'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-message', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-message-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), + 'psr/log' => array( + 'pretty_version' => '1.1.4', + 'version' => '1.1.4.0', + 'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/simple-cache' => array( + 'pretty_version' => '1.0.1', + 'version' => '1.0.1.0', + 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/simple-cache', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ralouphie/getallheaders' => array( + 'pretty_version' => '3.0.3', + 'version' => '3.0.3.0', + 'reference' => '120b605dfeb996808c31b6477290a714d356e822', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ralouphie/getallheaders', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/class-loader' => array( + 'pretty_version' => 'v3.4.47', + 'version' => '3.4.47.0', + 'reference' => 'a22265a9f3511c0212bf79f54910ca5a77c0e92c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/class-loader', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/deprecation-contracts' => array( + 'pretty_version' => 'v2.5.3', + 'version' => '2.5.3.0', + 'reference' => '80d075412b557d41002320b96a096ca65aa2c98d', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-mbstring' => array( + 'pretty_version' => 'v1.29.0', + 'version' => '1.29.0.0', + 'reference' => '9773676c8a1bb1f8d4340a62efe641cf76eda7ec', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php72' => array( + 'pretty_version' => 'v1.29.0', + 'version' => '1.29.0.0', + 'reference' => '861391a8da9a04cbad2d232ddd9e4893220d6e25', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php72', + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'symfony/polyfill-php80' => array( + 'pretty_version' => 'v1.29.0', + 'version' => '1.29.0.0', + 'reference' => '87b68208d5c1188808dd7839ee1e6c8ec3b02f1b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php80', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/process' => array( + 'pretty_version' => 'v5.4.39', + 'version' => '5.4.39.0', + 'reference' => '85a554acd7c28522241faf2e97b9541247a0d3d5', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/process', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/translation' => array( + 'pretty_version' => 'v5.4.39', + 'version' => '5.4.39.0', + 'reference' => '0fabede35e3985c4f96089edeeefe8313e15ca3a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/translation', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/translation-contracts' => array( + 'pretty_version' => 'v2.5.3', + 'version' => '2.5.3.0', + 'reference' => 'b0073a77ac0b7ea55131020e87b1e3af540f4664', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/translation-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/translation-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '2.3', + ), + ), + 'symfony/var-dumper' => array( + 'pretty_version' => 'v4.4.47', + 'version' => '4.4.47.0', + 'reference' => '1069c7a3fca74578022fab6f81643248d02f8e63', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/var-dumper', + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'topthink/framework' => array( + 'pretty_version' => 'v6.1.3', + 'version' => '6.1.3.0', + 'reference' => '7c324e7011246f0064b055b62ab9c3921cf0a041', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/framework', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'topthink/think' => array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'reference' => null, + 'type' => 'project', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'topthink/think-filesystem' => array( + 'pretty_version' => 'v1.0.3', + 'version' => '1.0.3.0', + 'reference' => '29f19f140a9267c717fecd7ccb22c84c2d72382e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-filesystem', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'topthink/think-helper' => array( + 'pretty_version' => 'v3.1.6', + 'version' => '3.1.6.0', + 'reference' => '769acbe50a4274327162f9c68ec2e89a38eb2aff', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-helper', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'topthink/think-multi-app' => array( + 'pretty_version' => 'v1.0.17', + 'version' => '1.0.17.0', + 'reference' => '4055a6187296ac16c0bc7bbab4ed5d92f82f791c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-multi-app', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'topthink/think-orm' => array( + 'pretty_version' => 'v2.0.61', + 'version' => '2.0.61.0', + 'reference' => '10528ebf4a5106b19c3bac9c6deae7a67ff49de6', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-orm', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'topthink/think-queue' => array( + 'pretty_version' => 'v3.0.9', + 'version' => '3.0.9.0', + 'reference' => '654812b47dd7c708c4443deed27f212f8382e8da', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-queue', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'topthink/think-trace' => array( + 'pretty_version' => 'v1.6', + 'version' => '1.6.0.0', + 'reference' => '136cd5d97e8bdb780e4b5c1637c588ed7ca3e142', + 'type' => 'library', + 'install_path' => __DIR__ . '/../topthink/think-trace', + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'webmozart/assert' => array( + 'pretty_version' => '1.11.0', + 'version' => '1.11.0.0', + 'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991', + 'type' => 'library', + 'install_path' => __DIR__ . '/../webmozart/assert', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php new file mode 100644 index 0000000..580fa96 --- /dev/null +++ b/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70400)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/vendor/ezyang/htmlpurifier/CREDITS b/vendor/ezyang/htmlpurifier/CREDITS new file mode 100644 index 0000000..7921b45 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/CREDITS @@ -0,0 +1,9 @@ + +CREDITS + +Almost everything written by Edward Z. Yang (Ambush Commander). Lots of thanks +to the DevNetwork Community for their help (see docs/ref-devnetwork.html for +more details), Feyd especially (namely IPv6 and optimization). Thanks to RSnake +for letting me package his fantastic XSS cheatsheet for a smoketest. + + vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/LICENSE b/vendor/ezyang/htmlpurifier/LICENSE new file mode 100644 index 0000000..8c88a20 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/README.md b/vendor/ezyang/htmlpurifier/README.md new file mode 100644 index 0000000..e6b7199 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/README.md @@ -0,0 +1,29 @@ +HTML Purifier [![Build Status](https://github.com/ezyang/htmlpurifier/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/ezyang/htmlpurifier/actions/workflows/ci.yml) +============= + +HTML Purifier is an HTML filtering solution that uses a unique combination +of robust whitelists and aggressive parsing to ensure that not only are +XSS attacks thwarted, but the resulting HTML is standards compliant. + +HTML Purifier is oriented towards richly formatted documents from +untrusted sources that require CSS and a full tag-set. This library can +be configured to accept a more restrictive set of tags, but it won't be +as efficient as more bare-bones parsers. It will, however, do the job +right, which may be more important. + +Places to go: + +* See INSTALL for a quick installation guide +* See docs/ for developer-oriented documentation, code examples and + an in-depth installation guide. +* See WYSIWYG for information on editors like TinyMCE and FCKeditor + +HTML Purifier can be found on the web at: [http://htmlpurifier.org/](http://htmlpurifier.org/) + +## Installation + +Package available on [Composer](https://packagist.org/packages/ezyang/htmlpurifier). + +If you're using Composer to manage dependencies, you can use + + $ composer require ezyang/htmlpurifier diff --git a/vendor/ezyang/htmlpurifier/VERSION b/vendor/ezyang/htmlpurifier/VERSION new file mode 100644 index 0000000..8643e72 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/VERSION @@ -0,0 +1 @@ +4.17.0 \ No newline at end of file diff --git a/vendor/ezyang/htmlpurifier/composer.json b/vendor/ezyang/htmlpurifier/composer.json new file mode 100644 index 0000000..ed46bd5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/composer.json @@ -0,0 +1,45 @@ +{ + "name": "ezyang/htmlpurifier", + "description": "Standards compliant HTML filter written in PHP", + "type": "library", + "keywords": ["html"], + "homepage": "http://htmlpurifier.org/", + "license": "LGPL-2.1-or-later", + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "autoload": { + "psr-0": { "HTMLPurifier": "library/" }, + "files": ["library/HTMLPurifier.composer.php"], + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-tidy": "Used for pretty-printing HTML" + }, + "config": { + "sort-packages": true + }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/ezyang/simpletest.git", + "no-api": true + } + ] +} diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php new file mode 100644 index 0000000..1960c39 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php @@ -0,0 +1,11 @@ +purify($html, $config); +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php new file mode 100644 index 0000000..77ebf2d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php @@ -0,0 +1,235 @@ + $attributes) { + $allowed_elements[$element] = true; + foreach ($attributes as $attribute => $x) { + $allowed_attributes["$element.$attribute"] = true; + } + } + $config->set('HTML.AllowedElements', $allowed_elements); + $config->set('HTML.AllowedAttributes', $allowed_attributes); + if ($allowed_protocols !== null) { + $config->set('URI.AllowedSchemes', $allowed_protocols); + } + $purifier = new HTMLPurifier($config); + return $purifier->purify($string); +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php new file mode 100644 index 0000000..39b1b65 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php @@ -0,0 +1,11 @@ +config = HTMLPurifier_Config::create($config); + $this->strategy = new HTMLPurifier_Strategy_Core(); + } + + /** + * Adds a filter to process the output. First come first serve + * + * @param HTMLPurifier_Filter $filter HTMLPurifier_Filter object + */ + public function addFilter($filter) + { + trigger_error( + 'HTMLPurifier->addFilter() is deprecated, use configuration directives' . + ' in the Filter namespace or Filter.Custom', + E_USER_WARNING + ); + $this->filters[] = $filter; + } + + /** + * Filters an HTML snippet/document to be XSS-free and standards-compliant. + * + * @param string $html String of HTML to purify + * @param HTMLPurifier_Config $config Config object for this operation, + * if omitted, defaults to the config object specified during this + * object's construction. The parameter can also be any type + * that HTMLPurifier_Config::create() supports. + * + * @return string Purified HTML + */ + public function purify($html, $config = null) + { + // :TODO: make the config merge in, instead of replace + $config = $config ? HTMLPurifier_Config::create($config) : $this->config; + + // implementation is partially environment dependant, partially + // configuration dependant + $lexer = HTMLPurifier_Lexer::create($config); + + $context = new HTMLPurifier_Context(); + + // setup HTML generator + $this->generator = new HTMLPurifier_Generator($config, $context); + $context->register('Generator', $this->generator); + + // set up global context variables + if ($config->get('Core.CollectErrors')) { + // may get moved out if other facilities use it + $language_factory = HTMLPurifier_LanguageFactory::instance(); + $language = $language_factory->create($config, $context); + $context->register('Locale', $language); + + $error_collector = new HTMLPurifier_ErrorCollector($context); + $context->register('ErrorCollector', $error_collector); + } + + // setup id_accumulator context, necessary due to the fact that + // AttrValidator can be called from many places + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + + $html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context); + + // setup filters + $filter_flags = $config->getBatch('Filter'); + $custom_filters = $filter_flags['Custom']; + unset($filter_flags['Custom']); + $filters = array(); + foreach ($filter_flags as $filter => $flag) { + if (!$flag) { + continue; + } + if (strpos($filter, '.') !== false) { + continue; + } + $class = "HTMLPurifier_Filter_$filter"; + $filters[] = new $class; + } + foreach ($custom_filters as $filter) { + // maybe "HTMLPurifier_Filter_$filter", but be consistent with AutoFormat + $filters[] = $filter; + } + $filters = array_merge($filters, $this->filters); + // maybe prepare(), but later + + for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) { + $html = $filters[$i]->preFilter($html, $config, $context); + } + + // purified HTML + $html = + $this->generator->generateFromTokens( + // list of tokens + $this->strategy->execute( + // list of un-purified tokens + $lexer->tokenizeHTML( + // un-purified HTML + $html, + $config, + $context + ), + $config, + $context + ) + ); + + for ($i = $filter_size - 1; $i >= 0; $i--) { + $html = $filters[$i]->postFilter($html, $config, $context); + } + + $html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context); + $this->context =& $context; + return $html; + } + + /** + * Filters an array of HTML snippets + * + * @param string[] $array_of_html Array of html snippets + * @param HTMLPurifier_Config $config Optional config object for this operation. + * See HTMLPurifier::purify() for more details. + * + * @return string[] Array of purified HTML + */ + public function purifyArray($array_of_html, $config = null) + { + $context_array = array(); + $array = array(); + foreach($array_of_html as $key=>$value){ + if (is_array($value)) { + $array[$key] = $this->purifyArray($value, $config); + } else { + $array[$key] = $this->purify($value, $config); + } + $context_array[$key] = $this->context; + } + $this->context = $context_array; + return $array; + } + + /** + * Singleton for enforcing just one HTML Purifier in your system + * + * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype + * HTMLPurifier instance to overload singleton with, + * or HTMLPurifier_Config instance to configure the + * generated version with. + * + * @return HTMLPurifier + */ + public static function instance($prototype = null) + { + if (!self::$instance || $prototype) { + if ($prototype instanceof HTMLPurifier) { + self::$instance = $prototype; + } elseif ($prototype) { + self::$instance = new HTMLPurifier($prototype); + } else { + self::$instance = new HTMLPurifier(); + } + } + return self::$instance; + } + + /** + * Singleton for enforcing just one HTML Purifier in your system + * + * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype + * HTMLPurifier instance to overload singleton with, + * or HTMLPurifier_Config instance to configure the + * generated version with. + * + * @return HTMLPurifier + * @note Backwards compatibility, see instance() + */ + public static function getInstance($prototype = null) + { + return HTMLPurifier::instance($prototype); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php new file mode 100644 index 0000000..94543f5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php @@ -0,0 +1,229 @@ +getHTMLDefinition(); + $parent = new HTMLPurifier_Token_Start($definition->info_parent); + $stack = array($parent->toNode()); + foreach ($tokens as $token) { + $token->skip = null; // [MUT] + $token->carryover = null; // [MUT] + if ($token instanceof HTMLPurifier_Token_End) { + $token->start = null; // [MUT] + $r = array_pop($stack); + //assert($r->name === $token->name); + //assert(empty($token->attr)); + $r->endCol = $token->col; + $r->endLine = $token->line; + $r->endArmor = $token->armor; + continue; + } + $node = $token->toNode(); + $stack[count($stack)-1]->children[] = $node; + if ($token instanceof HTMLPurifier_Token_Start) { + $stack[] = $node; + } + } + //assert(count($stack) == 1); + return $stack[0]; + } + + public static function flatten($node, $config, $context) { + $level = 0; + $nodes = array($level => new HTMLPurifier_Queue(array($node))); + $closingTokens = array(); + $tokens = array(); + do { + while (!$nodes[$level]->isEmpty()) { + $node = $nodes[$level]->shift(); // FIFO + list($start, $end) = $node->toTokenPair(); + if ($level > 0) { + $tokens[] = $start; + } + if ($end !== NULL) { + $closingTokens[$level][] = $end; + } + if ($node instanceof HTMLPurifier_Node_Element) { + $level++; + $nodes[$level] = new HTMLPurifier_Queue(); + foreach ($node->children as $childNode) { + $nodes[$level]->push($childNode); + } + } + } + $level--; + if ($level && isset($closingTokens[$level])) { + while ($token = array_pop($closingTokens[$level])) { + $tokens[] = $token; + } + } + } while ($level > 0); + return $tokens; + } +} diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php new file mode 100644 index 0000000..c7b17cf --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php @@ -0,0 +1,148 @@ +doConstruct($attr_types, $modules); + } + + public function doConstruct($attr_types, $modules) + { + // load extensions from the modules + foreach ($modules as $module) { + foreach ($module->attr_collections as $coll_i => $coll) { + if (!isset($this->info[$coll_i])) { + $this->info[$coll_i] = array(); + } + foreach ($coll as $attr_i => $attr) { + if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) { + // merge in includes + $this->info[$coll_i][$attr_i] = array_merge( + $this->info[$coll_i][$attr_i], + $attr + ); + continue; + } + $this->info[$coll_i][$attr_i] = $attr; + } + } + } + // perform internal expansions and inclusions + foreach ($this->info as $name => $attr) { + // merge attribute collections that include others + $this->performInclusions($this->info[$name]); + // replace string identifiers with actual attribute objects + $this->expandIdentifiers($this->info[$name], $attr_types); + } + } + + /** + * Takes a reference to an attribute associative array and performs + * all inclusions specified by the zero index. + * @param array &$attr Reference to attribute array + */ + public function performInclusions(&$attr) + { + if (!isset($attr[0])) { + return; + } + $merge = $attr[0]; + $seen = array(); // recursion guard + // loop through all the inclusions + for ($i = 0; isset($merge[$i]); $i++) { + if (isset($seen[$merge[$i]])) { + continue; + } + $seen[$merge[$i]] = true; + // foreach attribute of the inclusion, copy it over + if (!isset($this->info[$merge[$i]])) { + continue; + } + foreach ($this->info[$merge[$i]] as $key => $value) { + if (isset($attr[$key])) { + continue; + } // also catches more inclusions + $attr[$key] = $value; + } + if (isset($this->info[$merge[$i]][0])) { + // recursion + $merge = array_merge($merge, $this->info[$merge[$i]][0]); + } + } + unset($attr[0]); + } + + /** + * Expands all string identifiers in an attribute array by replacing + * them with the appropriate values inside HTMLPurifier_AttrTypes + * @param array &$attr Reference to attribute array + * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance + */ + public function expandIdentifiers(&$attr, $attr_types) + { + // because foreach will process new elements we add, make sure we + // skip duplicates + $processed = array(); + + foreach ($attr as $def_i => $def) { + // skip inclusions + if ($def_i === 0) { + continue; + } + + if (isset($processed[$def_i])) { + continue; + } + + // determine whether or not attribute is required + if ($required = (strpos($def_i, '*') !== false)) { + // rename the definition + unset($attr[$def_i]); + $def_i = trim($def_i, '*'); + $attr[$def_i] = $def; + } + + $processed[$def_i] = true; + + // if we've already got a literal object, move on + if (is_object($def)) { + // preserve previous required + $attr[$def_i]->required = ($required || $attr[$def_i]->required); + continue; + } + + if ($def === false) { + unset($attr[$def_i]); + continue; + } + + if ($t = $attr_types->get($def)) { + $attr[$def_i] = $t; + $attr[$def_i]->required = $required; + } else { + unset($attr[$def_i]); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php new file mode 100644 index 0000000..739646f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php @@ -0,0 +1,144 @@ + by removing + * leading and trailing whitespace, ignoring line feeds, and replacing + * carriage returns and tabs with spaces. While most useful for HTML + * attributes specified as CDATA, it can also be applied to most CSS + * values. + * + * @note This method is not entirely standards compliant, as trim() removes + * more types of whitespace than specified in the spec. In practice, + * this is rarely a problem, as those extra characters usually have + * already been removed by HTMLPurifier_Encoder. + * + * @warning This processing is inconsistent with XML's whitespace handling + * as specified by section 3.3.3 and referenced XHTML 1.0 section + * 4.7. However, note that we are NOT necessarily + * parsing XML, thus, this behavior may still be correct. We + * assume that newlines have been normalized. + */ + public function parseCDATA($string) + { + $string = trim($string); + $string = str_replace(array("\n", "\t", "\r"), ' ', $string); + return $string; + } + + /** + * Factory method for creating this class from a string. + * @param string $string String construction info + * @return HTMLPurifier_AttrDef Created AttrDef object corresponding to $string + */ + public function make($string) + { + // default implementation, return a flyweight of this object. + // If $string has an effect on the returned object (i.e. you + // need to overload this method), it is best + // to clone or instantiate new copies. (Instantiation is safer.) + return $this; + } + + /** + * Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work + * properly. THIS IS A HACK! + * @param string $string a CSS colour definition + * @return string + */ + protected function mungeRgb($string) + { + $p = '\s*(\d+(\.\d+)?([%]?))\s*'; + + if (preg_match('/(rgba|hsla)\(/', $string)) { + return preg_replace('/(rgba|hsla)\('.$p.','.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8,\11)', $string); + } + + return preg_replace('/(rgb|hsl)\('.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8)', $string); + } + + /** + * Parses a possibly escaped CSS string and returns the "pure" + * version of it. + */ + protected function expandCSSEscape($string) + { + // flexibly parse it + $ret = ''; + for ($i = 0, $c = strlen($string); $i < $c; $i++) { + if ($string[$i] === '\\') { + $i++; + if ($i >= $c) { + $ret .= '\\'; + break; + } + if (ctype_xdigit($string[$i])) { + $code = $string[$i]; + for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) { + if (!ctype_xdigit($string[$i])) { + break; + } + $code .= $string[$i]; + } + // We have to be extremely careful when adding + // new characters, to make sure we're not breaking + // the encoding. + $char = HTMLPurifier_Encoder::unichr(hexdec($code)); + if (HTMLPurifier_Encoder::cleanUTF8($char) === '') { + continue; + } + $ret .= $char; + if ($i < $c && trim($string[$i]) !== '') { + $i--; + } + continue; + } + if ($string[$i] === "\n") { + continue; + } + } + $ret .= $string[$i]; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php new file mode 100644 index 0000000..ad2cb90 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php @@ -0,0 +1,136 @@ +parseCDATA($css); + + $definition = $config->getCSSDefinition(); + $allow_duplicates = $config->get("CSS.AllowDuplicates"); + + + // According to the CSS2.1 spec, the places where a + // non-delimiting semicolon can appear are in strings + // escape sequences. So here is some dumb hack to + // handle quotes. + $len = strlen($css); + $accum = ""; + $declarations = array(); + $quoted = false; + for ($i = 0; $i < $len; $i++) { + $c = strcspn($css, ";'\"", $i); + $accum .= substr($css, $i, $c); + $i += $c; + if ($i == $len) break; + $d = $css[$i]; + if ($quoted) { + $accum .= $d; + if ($d == $quoted) { + $quoted = false; + } + } else { + if ($d == ";") { + $declarations[] = $accum; + $accum = ""; + } else { + $accum .= $d; + $quoted = $d; + } + } + } + if ($accum != "") $declarations[] = $accum; + + $propvalues = array(); + $new_declarations = ''; + + /** + * Name of the current CSS property being validated. + */ + $property = false; + $context->register('CurrentCSSProperty', $property); + + foreach ($declarations as $declaration) { + if (!$declaration) { + continue; + } + if (!strpos($declaration, ':')) { + continue; + } + list($property, $value) = explode(':', $declaration, 2); + $property = trim($property); + $value = trim($value); + $ok = false; + do { + if (isset($definition->info[$property])) { + $ok = true; + break; + } + if (ctype_lower($property)) { + break; + } + $property = strtolower($property); + if (isset($definition->info[$property])) { + $ok = true; + break; + } + } while (0); + if (!$ok) { + continue; + } + // inefficient call, since the validator will do this again + if (strtolower(trim($value)) !== 'inherit') { + // inherit works for everything (but only on the base property) + $result = $definition->info[$property]->validate( + $value, + $config, + $context + ); + } else { + $result = 'inherit'; + } + if ($result === false) { + continue; + } + if ($allow_duplicates) { + $new_declarations .= "$property:$result;"; + } else { + $propvalues[$property] = $result; + } + } + + $context->destroy('CurrentCSSProperty'); + + // procedure does not write the new CSS simultaneously, so it's + // slightly inefficient, but it's the only way of getting rid of + // duplicates. Perhaps config to optimize it, but not now. + + foreach ($propvalues as $prop => $value) { + $new_declarations .= "$prop:$value;"; + } + + return $new_declarations ? $new_declarations : false; + + } + +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php new file mode 100644 index 0000000..af2b83d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php @@ -0,0 +1,34 @@ + 1.0) { + $result = '1'; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php new file mode 100644 index 0000000..28c4988 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php @@ -0,0 +1,113 @@ +getCSSDefinition(); + $this->info['background-color'] = $def->info['background-color']; + $this->info['background-image'] = $def->info['background-image']; + $this->info['background-repeat'] = $def->info['background-repeat']; + $this->info['background-attachment'] = $def->info['background-attachment']; + $this->info['background-position'] = $def->info['background-position']; + $this->info['background-size'] = $def->info['background-size']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') { + return false; + } + + // munge rgb() decl if necessary + $string = $this->mungeRgb($string); + + // assumes URI doesn't have spaces in it + $bits = explode(' ', $string); // bits to process + + $caught = array(); + $caught['color'] = false; + $caught['image'] = false; + $caught['repeat'] = false; + $caught['attachment'] = false; + $caught['position'] = false; + $caught['size'] = false; + + $i = 0; // number of catches + + foreach ($bits as $bit) { + if ($bit === '') { + continue; + } + foreach ($caught as $key => $status) { + if ($key != 'position') { + if ($status !== false) { + continue; + } + $r = $this->info['background-' . $key]->validate($bit, $config, $context); + } else { + $r = $bit; + } + if ($r === false) { + continue; + } + if ($key == 'position') { + if ($caught[$key] === false) { + $caught[$key] = ''; + } + $caught[$key] .= $r . ' '; + } else { + $caught[$key] = $r; + } + $i++; + break; + } + } + + if (!$i) { + return false; + } + if ($caught['position'] !== false) { + $caught['position'] = $this->info['background-position']-> + validate($caught['position'], $config, $context); + } + + $ret = array(); + foreach ($caught as $value) { + if ($value === false) { + continue; + } + $ret[] = $value; + } + + if (empty($ret)) { + return false; + } + return implode(' ', $ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php new file mode 100644 index 0000000..4580ef5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php @@ -0,0 +1,157 @@ + | | left | center | right + ] + [ + | | top | center | bottom + ]? + ] | + [ // this signifies that the vertical and horizontal adjectives + // can be arbitrarily ordered, however, there can only be two, + // one of each, or none at all + [ + left | center | right + ] || + [ + top | center | bottom + ] + ] + top, left = 0% + center, (none) = 50% + bottom, right = 100% +*/ + +/* QuirksMode says: + keyword + length/percentage must be ordered correctly, as per W3C + + Internet Explorer and Opera, however, support arbitrary ordering. We + should fix it up. + + Minor issue though, not strictly necessary. +*/ + +// control freaks may appreciate the ability to convert these to +// percentages or something, but it's not necessary + +/** + * Validates the value of background-position. + */ +class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef +{ + + /** + * @type HTMLPurifier_AttrDef_CSS_Length + */ + protected $length; + + /** + * @type HTMLPurifier_AttrDef_CSS_Percentage + */ + protected $percentage; + + public function __construct() + { + $this->length = new HTMLPurifier_AttrDef_CSS_Length(); + $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage(); + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + $bits = explode(' ', $string); + + $keywords = array(); + $keywords['h'] = false; // left, right + $keywords['v'] = false; // top, bottom + $keywords['ch'] = false; // center (first word) + $keywords['cv'] = false; // center (second word) + $measures = array(); + + $i = 0; + + $lookup = array( + 'top' => 'v', + 'bottom' => 'v', + 'left' => 'h', + 'right' => 'h', + 'center' => 'c' + ); + + foreach ($bits as $bit) { + if ($bit === '') { + continue; + } + + // test for keyword + $lbit = ctype_lower($bit) ? $bit : strtolower($bit); + if (isset($lookup[$lbit])) { + $status = $lookup[$lbit]; + if ($status == 'c') { + if ($i == 0) { + $status = 'ch'; + } else { + $status = 'cv'; + } + } + $keywords[$status] = $lbit; + $i++; + } + + // test for length + $r = $this->length->validate($bit, $config, $context); + if ($r !== false) { + $measures[] = $r; + $i++; + } + + // test for percentage + $r = $this->percentage->validate($bit, $config, $context); + if ($r !== false) { + $measures[] = $r; + $i++; + } + } + + if (!$i) { + return false; + } // no valid values were caught + + $ret = array(); + + // first keyword + if ($keywords['h']) { + $ret[] = $keywords['h']; + } elseif ($keywords['ch']) { + $ret[] = $keywords['ch']; + $keywords['cv'] = false; // prevent re-use: center = center center + } elseif (count($measures)) { + $ret[] = array_shift($measures); + } + + if ($keywords['v']) { + $ret[] = $keywords['v']; + } elseif ($keywords['cv']) { + $ret[] = $keywords['cv']; + } elseif (count($measures)) { + $ret[] = array_shift($measures); + } + + if (empty($ret)) { + return false; + } + return implode(' ', $ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php new file mode 100644 index 0000000..16243ba --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php @@ -0,0 +1,56 @@ +getCSSDefinition(); + $this->info['border-width'] = $def->info['border-width']; + $this->info['border-style'] = $def->info['border-style']; + $this->info['border-top-color'] = $def->info['border-top-color']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + $string = $this->mungeRgb($string); + $bits = explode(' ', $string); + $done = array(); // segments we've finished + $ret = ''; // return value + foreach ($bits as $bit) { + foreach ($this->info as $propname => $validator) { + if (isset($done[$propname])) { + continue; + } + $r = $validator->validate($bit, $config, $context); + if ($r !== false) { + $ret .= $r . ' '; + $done[$propname] = true; + break; + } + } + } + return rtrim($ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php new file mode 100644 index 0000000..d7287a0 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php @@ -0,0 +1,161 @@ +alpha = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + } + + /** + * @param string $color + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($color, $config, $context) + { + static $colors = null; + if ($colors === null) { + $colors = $config->get('Core.ColorKeywords'); + } + + $color = trim($color); + if ($color === '') { + return false; + } + + $lower = strtolower($color); + if (isset($colors[$lower])) { + return $colors[$lower]; + } + + if (preg_match('#(rgb|rgba|hsl|hsla)\(#', $color, $matches) === 1) { + $length = strlen($color); + if (strpos($color, ')') !== $length - 1) { + return false; + } + + // get used function : rgb, rgba, hsl or hsla + $function = $matches[1]; + + $parameters_size = 3; + $alpha_channel = false; + if (substr($function, -1) === 'a') { + $parameters_size = 4; + $alpha_channel = true; + } + + /* + * Allowed types for values : + * parameter_position => [type => max_value] + */ + $allowed_types = array( + 1 => array('percentage' => 100, 'integer' => 255), + 2 => array('percentage' => 100, 'integer' => 255), + 3 => array('percentage' => 100, 'integer' => 255), + ); + $allow_different_types = false; + + if (strpos($function, 'hsl') !== false) { + $allowed_types = array( + 1 => array('integer' => 360), + 2 => array('percentage' => 100), + 3 => array('percentage' => 100), + ); + $allow_different_types = true; + } + + $values = trim(str_replace($function, '', $color), ' ()'); + + $parts = explode(',', $values); + if (count($parts) !== $parameters_size) { + return false; + } + + $type = false; + $new_parts = array(); + $i = 0; + + foreach ($parts as $part) { + $i++; + $part = trim($part); + + if ($part === '') { + return false; + } + + // different check for alpha channel + if ($alpha_channel === true && $i === count($parts)) { + $result = $this->alpha->validate($part, $config, $context); + + if ($result === false) { + return false; + } + + $new_parts[] = (string)$result; + continue; + } + + if (substr($part, -1) === '%') { + $current_type = 'percentage'; + } else { + $current_type = 'integer'; + } + + if (!array_key_exists($current_type, $allowed_types[$i])) { + return false; + } + + if (!$type) { + $type = $current_type; + } + + if ($allow_different_types === false && $type != $current_type) { + return false; + } + + $max_value = $allowed_types[$i][$current_type]; + + if ($current_type == 'integer') { + // Return value between range 0 -> $max_value + $new_parts[] = (int)max(min($part, $max_value), 0); + } elseif ($current_type == 'percentage') { + $new_parts[] = (float)max(min(rtrim($part, '%'), $max_value), 0) . '%'; + } + } + + $new_values = implode(',', $new_parts); + + $color = $function . '(' . $new_values . ')'; + } else { + // hexadecimal handling + if ($color[0] === '#') { + $hex = substr($color, 1); + } else { + $hex = $color; + $color = '#' . $color; + } + $length = strlen($hex); + if ($length !== 3 && $length !== 6) { + return false; + } + if (!ctype_xdigit($hex)) { + return false; + } + } + return $color; + } + +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php new file mode 100644 index 0000000..9c17505 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php @@ -0,0 +1,48 @@ +defs = $defs; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + foreach ($this->defs as $i => $def) { + $result = $this->defs[$i]->validate($string, $config, $context); + if ($result !== false) { + return $result; + } + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php new file mode 100644 index 0000000..9d77cc9 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php @@ -0,0 +1,44 @@ +def = $def; + $this->element = $element; + } + + /** + * Checks if CurrentToken is set and equal to $this->element + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $token = $context->get('CurrentToken', true); + if ($token && $token->name == $this->element) { + return false; + } + return $this->def->validate($string, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php new file mode 100644 index 0000000..bde4c33 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php @@ -0,0 +1,77 @@ +intValidator = new HTMLPurifier_AttrDef_Integer(); + } + + /** + * @param string $value + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($value, $config, $context) + { + $value = $this->parseCDATA($value); + if ($value === 'none') { + return $value; + } + // if we looped this we could support multiple filters + $function_length = strcspn($value, '('); + $function = trim(substr($value, 0, $function_length)); + if ($function !== 'alpha' && + $function !== 'Alpha' && + $function !== 'progid:DXImageTransform.Microsoft.Alpha' + ) { + return false; + } + $cursor = $function_length + 1; + $parameters_length = strcspn($value, ')', $cursor); + $parameters = substr($value, $cursor, $parameters_length); + $params = explode(',', $parameters); + $ret_params = array(); + $lookup = array(); + foreach ($params as $param) { + list($key, $value) = explode('=', $param); + $key = trim($key); + $value = trim($value); + if (isset($lookup[$key])) { + continue; + } + if ($key !== 'opacity') { + continue; + } + $value = $this->intValidator->validate($value, $config, $context); + if ($value === false) { + continue; + } + $int = (int)$value; + if ($int > 100) { + $value = '100'; + } + if ($int < 0) { + $value = '0'; + } + $ret_params[] = "$key=$value"; + $lookup[$key] = true; + } + $ret_parameters = implode(',', $ret_params); + $ret_function = "$function($ret_parameters)"; + return $ret_function; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php new file mode 100644 index 0000000..579b97e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php @@ -0,0 +1,176 @@ +getCSSDefinition(); + $this->info['font-style'] = $def->info['font-style']; + $this->info['font-variant'] = $def->info['font-variant']; + $this->info['font-weight'] = $def->info['font-weight']; + $this->info['font-size'] = $def->info['font-size']; + $this->info['line-height'] = $def->info['line-height']; + $this->info['font-family'] = $def->info['font-family']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + static $system_fonts = array( + 'caption' => true, + 'icon' => true, + 'menu' => true, + 'message-box' => true, + 'small-caption' => true, + 'status-bar' => true + ); + + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') { + return false; + } + + // check if it's one of the keywords + $lowercase_string = strtolower($string); + if (isset($system_fonts[$lowercase_string])) { + return $lowercase_string; + } + + $bits = explode(' ', $string); // bits to process + $stage = 0; // this indicates what we're looking for + $caught = array(); // which stage 0 properties have we caught? + $stage_1 = array('font-style', 'font-variant', 'font-weight'); + $final = ''; // output + + for ($i = 0, $size = count($bits); $i < $size; $i++) { + if ($bits[$i] === '') { + continue; + } + switch ($stage) { + case 0: // attempting to catch font-style, font-variant or font-weight + foreach ($stage_1 as $validator_name) { + if (isset($caught[$validator_name])) { + continue; + } + $r = $this->info[$validator_name]->validate( + $bits[$i], + $config, + $context + ); + if ($r !== false) { + $final .= $r . ' '; + $caught[$validator_name] = true; + break; + } + } + // all three caught, continue on + if (count($caught) >= 3) { + $stage = 1; + } + if ($r !== false) { + break; + } + case 1: // attempting to catch font-size and perhaps line-height + $found_slash = false; + if (strpos($bits[$i], '/') !== false) { + list($font_size, $line_height) = + explode('/', $bits[$i]); + if ($line_height === '') { + // ooh, there's a space after the slash! + $line_height = false; + $found_slash = true; + } + } else { + $font_size = $bits[$i]; + $line_height = false; + } + $r = $this->info['font-size']->validate( + $font_size, + $config, + $context + ); + if ($r !== false) { + $final .= $r; + // attempt to catch line-height + if ($line_height === false) { + // we need to scroll forward + for ($j = $i + 1; $j < $size; $j++) { + if ($bits[$j] === '') { + continue; + } + if ($bits[$j] === '/') { + if ($found_slash) { + return false; + } else { + $found_slash = true; + continue; + } + } + $line_height = $bits[$j]; + break; + } + } else { + // slash already found + $found_slash = true; + $j = $i; + } + if ($found_slash) { + $i = $j; + $r = $this->info['line-height']->validate( + $line_height, + $config, + $context + ); + if ($r !== false) { + $final .= '/' . $r; + } + } + $final .= ' '; + $stage = 2; + break; + } + return false; + case 2: // attempting to catch font-family + $font_family = + implode(' ', array_slice($bits, $i, $size - $i)); + $r = $this->info['font-family']->validate( + $font_family, + $config, + $context + ); + if ($r !== false) { + $final .= $r . ' '; + // processing completed successfully + return rtrim($final); + } + return false; + } + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php new file mode 100644 index 0000000..f1ff116 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php @@ -0,0 +1,217 @@ +mask = array_reduce($c, function ($carry, $value) { + return $carry . $value; + }, '_- '); + + /* + PHP's internal strcspn implementation is + O(length of string * length of mask), making it inefficient + for large masks. However, it's still faster than + preg_match 8) + for (p = s1;;) { + spanp = s2; + do { + if (*spanp == c || p == s1_end) { + return p - s1; + } + } while (spanp++ < (s2_end - 1)); + c = *++p; + } + */ + // possible optimization: invert the mask. + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + static $generic_names = array( + 'serif' => true, + 'sans-serif' => true, + 'monospace' => true, + 'fantasy' => true, + 'cursive' => true + ); + $allowed_fonts = $config->get('CSS.AllowedFonts'); + + // assume that no font names contain commas in them + $fonts = explode(',', $string); + $final = ''; + foreach ($fonts as $font) { + $font = trim($font); + if ($font === '') { + continue; + } + // match a generic name + if (isset($generic_names[$font])) { + if ($allowed_fonts === null || isset($allowed_fonts[$font])) { + $final .= $font . ', '; + } + continue; + } + // match a quoted name + if ($font[0] === '"' || $font[0] === "'") { + $length = strlen($font); + if ($length <= 2) { + continue; + } + $quote = $font[0]; + if ($font[$length - 1] !== $quote) { + continue; + } + $font = substr($font, 1, $length - 2); + } + + $font = $this->expandCSSEscape($font); + + // $font is a pure representation of the font name + + if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) { + continue; + } + + if (ctype_alnum($font) && $font !== '') { + // very simple font, allow it in unharmed + $final .= $font . ', '; + continue; + } + + // bugger out on whitespace. form feed (0C) really + // shouldn't show up regardless + $font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font); + + // Here, there are various classes of characters which need + // to be treated differently: + // - Alphanumeric characters are essentially safe. We + // handled these above. + // - Spaces require quoting, though most parsers will do + // the right thing if there aren't any characters that + // can be misinterpreted + // - Dashes rarely occur, but they fairly unproblematic + // for parsing/rendering purposes. + // The above characters cover the majority of Western font + // names. + // - Arbitrary Unicode characters not in ASCII. Because + // most parsers give little thought to Unicode, treatment + // of these codepoints is basically uniform, even for + // punctuation-like codepoints. These characters can + // show up in non-Western pages and are supported by most + // major browsers, for example: "MS 明朝" is a + // legitimate font-name + // . See + // the CSS3 spec for more examples: + // + // You can see live samples of these on the Internet: + // + // However, most of these fonts have ASCII equivalents: + // for example, 'MS Mincho', and it's considered + // professional to use ASCII font names instead of + // Unicode font names. Thanks Takeshi Terada for + // providing this information. + // The following characters, to my knowledge, have not been + // used to name font names. + // - Single quote. While theoretically you might find a + // font name that has a single quote in its name (serving + // as an apostrophe, e.g. Dave's Scribble), I haven't + // been able to find any actual examples of this. + // Internet Explorer's cssText translation (which I + // believe is invoked by innerHTML) normalizes any + // quoting to single quotes, and fails to escape single + // quotes. (Note that this is not IE's behavior for all + // CSS properties, just some sort of special casing for + // font-family). So a single quote *cannot* be used + // safely in the font-family context if there will be an + // innerHTML/cssText translation. Note that Firefox 3.x + // does this too. + // - Double quote. In IE, these get normalized to + // single-quotes, no matter what the encoding. (Fun + // fact, in IE8, the 'content' CSS property gained + // support, where they special cased to preserve encoded + // double quotes, but still translate unadorned double + // quotes into single quotes.) So, because their + // fixpoint behavior is identical to single quotes, they + // cannot be allowed either. Firefox 3.x displays + // single-quote style behavior. + // - Backslashes are reduced by one (so \\ -> \) every + // iteration, so they cannot be used safely. This shows + // up in IE7, IE8 and FF3 + // - Semicolons, commas and backticks are handled properly. + // - The rest of the ASCII punctuation is handled properly. + // We haven't checked what browsers do to unadorned + // versions, but this is not important as long as the + // browser doesn't /remove/ surrounding quotes (as IE does + // for HTML). + // + // With these results in hand, we conclude that there are + // various levels of safety: + // - Paranoid: alphanumeric, spaces and dashes(?) + // - International: Paranoid + non-ASCII Unicode + // - Edgy: Everything except quotes, backslashes + // - NoJS: Standards compliance, e.g. sod IE. Note that + // with some judicious character escaping (since certain + // types of escaping doesn't work) this is theoretically + // OK as long as innerHTML/cssText is not called. + // We believe that international is a reasonable default + // (that we will implement now), and once we do more + // extensive research, we may feel comfortable with dropping + // it down to edgy. + + // Edgy: alphanumeric, spaces, dashes, underscores and Unicode. Use of + // str(c)spn assumes that the string was already well formed + // Unicode (which of course it is). + if (strspn($font, $this->mask) !== strlen($font)) { + continue; + } + + // Historical: + // In the absence of innerHTML/cssText, these ugly + // transforms don't pose a security risk (as \\ and \" + // might--these escapes are not supported by most browsers). + // We could try to be clever and use single-quote wrapping + // when there is a double quote present, but I have choosen + // not to implement that. (NOTE: you can reduce the amount + // of escapes by one depending on what quoting style you use) + // $font = str_replace('\\', '\\5C ', $font); + // $font = str_replace('"', '\\22 ', $font); + // $font = str_replace("'", '\\27 ', $font); + + // font possibly with spaces, requires quoting + $final .= "'$font', "; + } + $final = rtrim($final, ', '); + if ($final === '') { + return false; + } + return $final; + } + +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php new file mode 100644 index 0000000..973002c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php @@ -0,0 +1,32 @@ +def = $def; + $this->allow = $allow; + } + + /** + * Intercepts and removes !important if necessary + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + // test for ! and important tokens + $string = trim($string); + $is_important = false; + // :TODO: optimization: test directly for !important and ! important + if (strlen($string) >= 9 && substr($string, -9) === 'important') { + $temp = rtrim(substr($string, 0, -9)); + // use a temp, because we might want to restore important + if (strlen($temp) >= 1 && substr($temp, -1) === '!') { + $string = rtrim(substr($temp, 0, -1)); + $is_important = true; + } + } + $string = $this->def->validate($string, $config, $context); + if ($this->allow && $is_important) { + $string .= ' !important'; + } + return $string; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php new file mode 100644 index 0000000..f12453a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php @@ -0,0 +1,77 @@ +min = $min !== null ? HTMLPurifier_Length::make($min) : null; + $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + + // Optimizations + if ($string === '') { + return false; + } + if ($string === '0') { + return '0'; + } + if (strlen($string) === 1) { + return false; + } + + $length = HTMLPurifier_Length::make($string); + if (!$length->isValid()) { + return false; + } + + if ($this->min) { + $c = $length->compareTo($this->min); + if ($c === false) { + return false; + } + if ($c < 0) { + return false; + } + } + if ($this->max) { + $c = $length->compareTo($this->max); + if ($c === false) { + return false; + } + if ($c > 0) { + return false; + } + } + return $length->toString(); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php new file mode 100644 index 0000000..e74d426 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php @@ -0,0 +1,112 @@ +getCSSDefinition(); + $this->info['list-style-type'] = $def->info['list-style-type']; + $this->info['list-style-position'] = $def->info['list-style-position']; + $this->info['list-style-image'] = $def->info['list-style-image']; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + // regular pre-processing + $string = $this->parseCDATA($string); + if ($string === '') { + return false; + } + + // assumes URI doesn't have spaces in it + $bits = explode(' ', strtolower($string)); // bits to process + + $caught = array(); + $caught['type'] = false; + $caught['position'] = false; + $caught['image'] = false; + + $i = 0; // number of catches + $none = false; + + foreach ($bits as $bit) { + if ($i >= 3) { + return; + } // optimization bit + if ($bit === '') { + continue; + } + foreach ($caught as $key => $status) { + if ($status !== false) { + continue; + } + $r = $this->info['list-style-' . $key]->validate($bit, $config, $context); + if ($r === false) { + continue; + } + if ($r === 'none') { + if ($none) { + continue; + } else { + $none = true; + } + if ($key == 'image') { + continue; + } + } + $caught[$key] = $r; + $i++; + break; + } + } + + if (!$i) { + return false; + } + + $ret = array(); + + // construct type + if ($caught['type']) { + $ret[] = $caught['type']; + } + + // construct image + if ($caught['image']) { + $ret[] = $caught['image']; + } + + // construct position + if ($caught['position']) { + $ret[] = $caught['position']; + } + + if (empty($ret)) { + return false; + } + return implode(' ', $ret); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php new file mode 100644 index 0000000..e707f87 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php @@ -0,0 +1,71 @@ +single = $single; + $this->max = $max; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->mungeRgb($this->parseCDATA($string)); + if ($string === '') { + return false; + } + $parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n + $length = count($parts); + $final = ''; + for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) { + if (ctype_space($parts[$i])) { + continue; + } + $result = $this->single->validate($parts[$i], $config, $context); + if ($result !== false) { + $final .= $result . ' '; + $num++; + } + } + if ($final === '') { + return false; + } + return rtrim($final); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php new file mode 100644 index 0000000..ef49d20 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php @@ -0,0 +1,90 @@ +non_negative = $non_negative; + } + + /** + * @param string $number + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string|bool + * @warning Some contexts do not pass $config, $context. These + * variables should not be used without checking HTMLPurifier_Length + */ + public function validate($number, $config, $context) + { + $number = $this->parseCDATA($number); + + if ($number === '') { + return false; + } + if ($number === '0') { + return '0'; + } + + $sign = ''; + switch ($number[0]) { + case '-': + if ($this->non_negative) { + return false; + } + $sign = '-'; + case '+': + $number = substr($number, 1); + } + + if (ctype_digit($number)) { + $number = ltrim($number, '0'); + return $number ? $sign . $number : '0'; + } + + // Period is the only non-numeric character allowed + if (strpos($number, '.') === false) { + return false; + } + + list($left, $right) = explode('.', $number, 2); + + if ($left === '' && $right === '') { + return false; + } + if ($left !== '' && !ctype_digit($left)) { + return false; + } + + // Remove leading zeros until positive number or a zero stays left + if (ltrim($left, '0') != '') { + $left = ltrim($left, '0'); + } else { + $left = '0'; + } + + $right = rtrim($right, '0'); + + if ($right === '') { + return $left ? $sign . $left : '0'; + } elseif (!ctype_digit($right)) { + return false; + } + return $sign . $left . '.' . $right; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php new file mode 100644 index 0000000..f0f25c5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php @@ -0,0 +1,54 @@ +number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative); + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = $this->parseCDATA($string); + + if ($string === '') { + return false; + } + $length = strlen($string); + if ($length === 1) { + return false; + } + if ($string[$length - 1] !== '%') { + return false; + } + + $number = substr($string, 0, $length - 1); + $number = $this->number_def->validate($number, $config, $context); + + if ($number === false) { + return false; + } + return "$number%"; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php new file mode 100644 index 0000000..5fd4b7f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php @@ -0,0 +1,46 @@ + true, + 'overline' => true, + 'underline' => true, + ); + + $string = strtolower($this->parseCDATA($string)); + + if ($string === 'none') { + return $string; + } + + $parts = explode(' ', $string); + $final = ''; + foreach ($parts as $part) { + if (isset($allowed_values[$part])) { + $final .= $part . ' '; + } + } + $final = rtrim($final); + if ($final === '') { + return false; + } + return $final; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php new file mode 100644 index 0000000..6617aca --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php @@ -0,0 +1,77 @@ +parseCDATA($uri_string); + if (strpos($uri_string, 'url(') !== 0) { + return false; + } + $uri_string = substr($uri_string, 4); + if (strlen($uri_string) == 0) { + return false; + } + $new_length = strlen($uri_string) - 1; + if ($uri_string[$new_length] != ')') { + return false; + } + $uri = trim(substr($uri_string, 0, $new_length)); + + if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) { + $quote = $uri[0]; + $new_length = strlen($uri) - 1; + if ($uri[$new_length] !== $quote) { + return false; + } + $uri = substr($uri, 1, $new_length - 1); + } + + $uri = $this->expandCSSEscape($uri); + + $result = parent::validate($uri, $config, $context); + + if ($result === false) { + return false; + } + + // extra sanity check; should have been done by URI + $result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result); + + // suspicious characters are ()'; we're going to percent encode + // them for safety. + $result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result); + + // there's an extra bug where ampersands lose their escaping on + // an innerHTML cycle, so a very unlucky query parameter could + // then change the meaning of the URL. Unfortunately, there's + // not much we can do about that... + return "url(\"$result\")"; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php new file mode 100644 index 0000000..6698a00 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php @@ -0,0 +1,44 @@ +clone = $clone; + } + + /** + * @param string $v + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($v, $config, $context) + { + return $this->clone->validate($v, $config, $context); + } + + /** + * @param string $string + * @return HTMLPurifier_AttrDef + */ + public function make($string) + { + return clone $this->clone; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php new file mode 100644 index 0000000..8abda7f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php @@ -0,0 +1,73 @@ +valid_values = array_flip($valid_values); + $this->case_sensitive = $case_sensitive; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = trim($string); + if (!$this->case_sensitive) { + // we may want to do full case-insensitive libraries + $string = ctype_lower($string) ? $string : strtolower($string); + } + $result = isset($this->valid_values[$string]); + + return $result ? $string : false; + } + + /** + * @param string $string In form of comma-delimited list of case-insensitive + * valid values. Example: "foo,bar,baz". Prepend "s:" to make + * case sensitive + * @return HTMLPurifier_AttrDef_Enum + */ + public function make($string) + { + if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') { + $string = substr($string, 2); + $sensitive = true; + } else { + $sensitive = false; + } + $values = explode(',', $string); + return new HTMLPurifier_AttrDef_Enum($values, $sensitive); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php new file mode 100644 index 0000000..be3bbc8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php @@ -0,0 +1,48 @@ +name = $name; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + return $this->name; + } + + /** + * @param string $string Name of attribute + * @return HTMLPurifier_AttrDef_HTML_Bool + */ + public function make($string) + { + return new HTMLPurifier_AttrDef_HTML_Bool($string); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php new file mode 100644 index 0000000..d501348 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php @@ -0,0 +1,48 @@ +getDefinition('HTML')->doctype->name; + if ($name == "XHTML 1.1" || $name == "XHTML 2.0") { + return parent::split($string, $config, $context); + } else { + return preg_split('/\s+/', $string); + } + } + + /** + * @param array $tokens + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + protected function filter($tokens, $config, $context) + { + $allowed = $config->get('Attr.AllowedClasses'); + $forbidden = $config->get('Attr.ForbiddenClasses'); + $ret = array(); + foreach ($tokens as $token) { + if (($allowed === null || isset($allowed[$token])) && + !isset($forbidden[$token]) && + // We need this O(n) check because of PHP's array + // implementation that casts -0 to 0. + !in_array($token, $ret, true) + ) { + $ret[] = $token; + } + } + return $ret; + } +} diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php new file mode 100644 index 0000000..946ebb7 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php @@ -0,0 +1,51 @@ +get('Core.ColorKeywords'); + } + + $string = trim($string); + + if (empty($string)) { + return false; + } + $lower = strtolower($string); + if (isset($colors[$lower])) { + return $colors[$lower]; + } + if ($string[0] === '#') { + $hex = substr($string, 1); + } else { + $hex = $string; + } + + $length = strlen($hex); + if ($length !== 3 && $length !== 6) { + return false; + } + if (!ctype_xdigit($hex)) { + return false; + } + if ($length === 3) { + $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; + } + return "#$hex"; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ContentEditable.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ContentEditable.php new file mode 100644 index 0000000..5b03d3e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ContentEditable.php @@ -0,0 +1,16 @@ +get('HTML.Trusted')) { + $allowed = array('', 'true', 'false'); + } + + $enum = new HTMLPurifier_AttrDef_Enum($allowed); + + return $enum->validate($string, $config, $context); + } +} diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php new file mode 100644 index 0000000..d79ba12 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php @@ -0,0 +1,38 @@ +valid_values === false) { + $this->valid_values = $config->get('Attr.AllowedFrameTargets'); + } + return parent::validate($string, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php new file mode 100644 index 0000000..4ba4561 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php @@ -0,0 +1,113 @@ +selector = $selector; + } + + /** + * @param string $id + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($id, $config, $context) + { + if (!$this->selector && !$config->get('Attr.EnableID')) { + return false; + } + + $id = trim($id); // trim it first + + if ($id === '') { + return false; + } + + $prefix = $config->get('Attr.IDPrefix'); + if ($prefix !== '') { + $prefix .= $config->get('Attr.IDPrefixLocal'); + // prevent re-appending the prefix + if (strpos($id, $prefix) !== 0) { + $id = $prefix . $id; + } + } elseif ($config->get('Attr.IDPrefixLocal') !== '') { + trigger_error( + '%Attr.IDPrefixLocal cannot be used unless ' . + '%Attr.IDPrefix is set', + E_USER_WARNING + ); + } + + if (!$this->selector) { + $id_accumulator =& $context->get('IDAccumulator'); + if (isset($id_accumulator->ids[$id])) { + return false; + } + } + + // we purposely avoid using regex, hopefully this is faster + + if ($config->get('Attr.ID.HTML5') === true) { + if (preg_match('/[\t\n\x0b\x0c ]/', $id)) { + return false; + } + } else { + if (ctype_alpha($id)) { + // OK + } else { + if (!ctype_alpha(@$id[0])) { + return false; + } + // primitive style of regexps, I suppose + $trim = trim( + $id, + 'A..Za..z0..9:-._' + ); + if ($trim !== '') { + return false; + } + } + } + + $regexp = $config->get('Attr.IDBlacklistRegexp'); + if ($regexp && preg_match($regexp, $id)) { + return false; + } + + if (!$this->selector) { + $id_accumulator->add($id); + } + + // if no change was made to the ID, return the result + // else, return the new id if stripping whitespace made it + // valid, or return false. + return $id; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php new file mode 100644 index 0000000..1c4006f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php @@ -0,0 +1,56 @@ + 100) { + return '100%'; + } + return ((string)$points) . '%'; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php new file mode 100644 index 0000000..63fa04c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php @@ -0,0 +1,72 @@ + 'AllowedRel', + 'rev' => 'AllowedRev' + ); + if (!isset($configLookup[$name])) { + trigger_error( + 'Unrecognized attribute name for link ' . + 'relationship.', + E_USER_ERROR + ); + return; + } + $this->name = $configLookup[$name]; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $allowed = $config->get('Attr.' . $this->name); + if (empty($allowed)) { + return false; + } + + $string = $this->parseCDATA($string); + $parts = explode(' ', $string); + + // lookup to prevent duplicates + $ret_lookup = array(); + foreach ($parts as $part) { + $part = strtolower(trim($part)); + if (!isset($allowed[$part])) { + continue; + } + $ret_lookup[$part] = true; + } + + if (empty($ret_lookup)) { + return false; + } + $string = implode(' ', array_keys($ret_lookup)); + return $string; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php new file mode 100644 index 0000000..bbb20f2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php @@ -0,0 +1,60 @@ +split($string, $config, $context); + $tokens = $this->filter($tokens, $config, $context); + if (empty($tokens)) { + return false; + } + return implode(' ', $tokens); + } + + /** + * Splits a space separated list of tokens into its constituent parts. + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + protected function split($string, $config, $context) + { + // OPTIMIZABLE! + // do the preg_match, capture all subpatterns for reformulation + + // we don't support U+00A1 and up codepoints or + // escaping because I don't know how to do that with regexps + // and plus it would complicate optimization efforts (you never + // see that anyway). + $pattern = '/(?:(?<=\s)|\A)' . // look behind for space or string start + '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)' . + '(?:(?=\s)|\z)/'; // look ahead for space or string end + preg_match_all($pattern, $string, $matches); + return $matches[1]; + } + + /** + * Template method for removing certain tokens based on arbitrary criteria. + * @note If we wanted to be really functional, we'd do an array_filter + * with a callback. But... we're not. + * @param array $tokens + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + protected function filter($tokens, $config, $context) + { + return $tokens; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php new file mode 100644 index 0000000..a1d019e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php @@ -0,0 +1,76 @@ +max = $max; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $string = trim($string); + if ($string === '0') { + return $string; + } + if ($string === '') { + return false; + } + $length = strlen($string); + if (substr($string, $length - 2) == 'px') { + $string = substr($string, 0, $length - 2); + } + if (!is_numeric($string)) { + return false; + } + $int = (int)$string; + + if ($int < 0) { + return '0'; + } + + // upper-bound value, extremely high values can + // crash operating systems, see + // WARNING, above link WILL crash you if you're using Windows + + if ($this->max !== null && $int > $this->max) { + return (string)$this->max; + } + return (string)$int; + } + + /** + * @param string $string + * @return HTMLPurifier_AttrDef + */ + public function make($string) + { + if ($string === '') { + $max = null; + } else { + $max = (int)$string; + } + $class = get_class($this); + return new $class($max); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php new file mode 100644 index 0000000..400e707 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php @@ -0,0 +1,91 @@ +negative = $negative; + $this->zero = $zero; + $this->positive = $positive; + } + + /** + * @param string $integer + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($integer, $config, $context) + { + $integer = $this->parseCDATA($integer); + if ($integer === '') { + return false; + } + + // we could possibly simply typecast it to integer, but there are + // certain fringe cases that must not return an integer. + + // clip leading sign + if ($this->negative && $integer[0] === '-') { + $digits = substr($integer, 1); + if ($digits === '0') { + $integer = '0'; + } // rm minus sign for zero + } elseif ($this->positive && $integer[0] === '+') { + $digits = $integer = substr($integer, 1); // rm unnecessary plus + } else { + $digits = $integer; + } + + // test if it's numeric + if (!ctype_digit($digits)) { + return false; + } + + // perform scope tests + if (!$this->zero && $integer == 0) { + return false; + } + if (!$this->positive && $integer > 0) { + return false; + } + if (!$this->negative && $integer < 0) { + return false; + } + + return $integer; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php new file mode 100644 index 0000000..2a55cea --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php @@ -0,0 +1,86 @@ + 8 || !ctype_alnum($subtags[1])) { + return $new_string; + } + if (!ctype_lower($subtags[1])) { + $subtags[1] = strtolower($subtags[1]); + } + + $new_string .= '-' . $subtags[1]; + if ($num_subtags == 2) { + return $new_string; + } + + // process all other subtags, index 2 and up + for ($i = 2; $i < $num_subtags; $i++) { + $length = strlen($subtags[$i]); + if ($length == 0 || $length > 8 || !ctype_alnum($subtags[$i])) { + return $new_string; + } + if (!ctype_lower($subtags[$i])) { + $subtags[$i] = strtolower($subtags[$i]); + } + $new_string .= '-' . $subtags[$i]; + } + return $new_string; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php new file mode 100644 index 0000000..c7eb319 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php @@ -0,0 +1,53 @@ +tag = $tag; + $this->withTag = $with_tag; + $this->withoutTag = $without_tag; + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $token = $context->get('CurrentToken', true); + if (!$token || $token->name !== $this->tag) { + return $this->withoutTag->validate($string, $config, $context); + } else { + return $this->withTag->validate($string, $config, $context); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php new file mode 100644 index 0000000..4553a4e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php @@ -0,0 +1,21 @@ +parseCDATA($string); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php new file mode 100644 index 0000000..c1cd897 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php @@ -0,0 +1,111 @@ +parser = new HTMLPurifier_URIParser(); + $this->embedsResource = (bool)$embeds_resource; + } + + /** + * @param string $string + * @return HTMLPurifier_AttrDef_URI + */ + public function make($string) + { + $embeds = ($string === 'embedded'); + return new HTMLPurifier_AttrDef_URI($embeds); + } + + /** + * @param string $uri + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($uri, $config, $context) + { + if ($config->get('URI.Disable')) { + return false; + } + + $uri = $this->parseCDATA($uri); + + // parse the URI + $uri = $this->parser->parse($uri); + if ($uri === false) { + return false; + } + + // add embedded flag to context for validators + $context->register('EmbeddedURI', $this->embedsResource); + + $ok = false; + do { + + // generic validation + $result = $uri->validate($config, $context); + if (!$result) { + break; + } + + // chained filtering + $uri_def = $config->getDefinition('URI'); + $result = $uri_def->filter($uri, $config, $context); + if (!$result) { + break; + } + + // scheme-specific validation + $scheme_obj = $uri->getSchemeObj($config, $context); + if (!$scheme_obj) { + break; + } + if ($this->embedsResource && !$scheme_obj->browsable) { + break; + } + $result = $scheme_obj->validate($uri, $config, $context); + if (!$result) { + break; + } + + // Post chained filtering + $result = $uri_def->postFilter($uri, $config, $context); + if (!$result) { + break; + } + + // survived gauntlet + $ok = true; + + } while (false); + + $context->destroy('EmbeddedURI'); + if (!$ok) { + return false; + } + // back to string + return $uri->toString(); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php new file mode 100644 index 0000000..daf32b7 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php @@ -0,0 +1,20 @@ +" + // that needs more percent encoding to be done + if ($string == '') { + return false; + } + $string = trim($string); + $result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string); + return $result ? $string : false; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php new file mode 100644 index 0000000..ddc5dfb --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php @@ -0,0 +1,142 @@ +ipv4 = new HTMLPurifier_AttrDef_URI_IPv4(); + $this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6(); + } + + /** + * @param string $string + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool|string + */ + public function validate($string, $config, $context) + { + $length = strlen($string); + // empty hostname is OK; it's usually semantically equivalent: + // the default host as defined by a URI scheme is used: + // + // If the URI scheme defines a default for host, then that + // default applies when the host subcomponent is undefined + // or when the registered name is empty (zero length). + if ($string === '') { + return ''; + } + if ($length > 1 && $string[0] === '[' && $string[$length - 1] === ']') { + //IPv6 + $ip = substr($string, 1, $length - 2); + $valid = $this->ipv6->validate($ip, $config, $context); + if ($valid === false) { + return false; + } + return '[' . $valid . ']'; + } + + // need to do checks on unusual encodings too + $ipv4 = $this->ipv4->validate($string, $config, $context); + if ($ipv4 !== false) { + return $ipv4; + } + + // A regular domain name. + + // This doesn't match I18N domain names, but we don't have proper IRI support, + // so force users to insert Punycode. + + // There is not a good sense in which underscores should be + // allowed, since it's technically not! (And if you go as + // far to allow everything as specified by the DNS spec... + // well, that's literally everything, modulo some space limits + // for the components and the overall name (which, by the way, + // we are NOT checking!). So we (arbitrarily) decide this: + // let's allow underscores wherever we would have allowed + // hyphens, if they are enabled. This is a pretty good match + // for browser behavior, for example, a large number of browsers + // cannot handle foo_.example.com, but foo_bar.example.com is + // fairly well supported. + $underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : ''; + + // Based off of RFC 1738, but amended so that + // as per RFC 3696, the top label need only not be all numeric. + // The productions describing this are: + $a = '[a-z]'; // alpha + $an = '[a-z0-9]'; // alphanum + $and = "[a-z0-9-$underscore]"; // alphanum | "-" + // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum + $domainlabel = "$an(?:$and*$an)?"; + // AMENDED as per RFC 3696 + // toplabel = alphanum | alphanum *( alphanum | "-" ) alphanum + // side condition: not all numeric + $toplabel = "$an(?:$and*$an)?"; + // hostname = *( domainlabel "." ) toplabel [ "." ] + if (preg_match("/^(?:$domainlabel\.)*($toplabel)\.?$/i", $string, $matches)) { + if (!ctype_digit($matches[1])) { + return $string; + } + } + + // PHP 5.3 and later support this functionality natively + if (function_exists('idn_to_ascii')) { + if (defined('IDNA_NONTRANSITIONAL_TO_ASCII') && defined('INTL_IDNA_VARIANT_UTS46')) { + $string = idn_to_ascii($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); + } else { + $string = idn_to_ascii($string); + } + + // If we have Net_IDNA2 support, we can support IRIs by + // punycoding them. (This is the most portable thing to do, + // since otherwise we have to assume browsers support + } elseif ($config->get('Core.EnableIDNA') && class_exists('Net_IDNA2')) { + $idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true)); + // we need to encode each period separately + $parts = explode('.', $string); + try { + $new_parts = array(); + foreach ($parts as $part) { + $encodable = false; + for ($i = 0, $c = strlen($part); $i < $c; $i++) { + if (ord($part[$i]) > 0x7a) { + $encodable = true; + break; + } + } + if (!$encodable) { + $new_parts[] = $part; + } else { + $new_parts[] = $idna->encode($part); + } + } + $string = implode('.', $new_parts); + } catch (Exception $e) { + // XXX error reporting + } + } + // Try again + if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) { + return $string; + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php new file mode 100644 index 0000000..30ac16c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php @@ -0,0 +1,45 @@ +ip4) { + $this->_loadRegex(); + } + + if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) { + return $aIP; + } + return false; + } + + /** + * Lazy load function to prevent regex from being stuffed in + * cache. + */ + protected function _loadRegex() + { + $oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255 + $this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})"; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php new file mode 100644 index 0000000..f243793 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php @@ -0,0 +1,89 @@ +ip4) { + $this->_loadRegex(); + } + + $original = $aIP; + + $hex = '[0-9a-fA-F]'; + $blk = '(?:' . $hex . '{1,4})'; + $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128 + + // prefix check + if (strpos($aIP, '/') !== false) { + if (preg_match('#' . $pre . '$#s', $aIP, $find)) { + $aIP = substr($aIP, 0, 0 - strlen($find[0])); + unset($find); + } else { + return false; + } + } + + // IPv4-compatiblity check + if (preg_match('#(?<=:' . ')' . $this->ip4 . '$#s', $aIP, $find)) { + $aIP = substr($aIP, 0, 0 - strlen($find[0])); + $ip = explode('.', $find[0]); + $ip = array_map('dechex', $ip); + $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3]; + unset($find, $ip); + } + + // compression check + $aIP = explode('::', $aIP); + $c = count($aIP); + if ($c > 2) { + return false; + } elseif ($c == 2) { + list($first, $second) = $aIP; + $first = explode(':', $first); + $second = explode(':', $second); + + if (count($first) + count($second) > 8) { + return false; + } + + while (count($first) < 8) { + array_push($first, '0'); + } + + array_splice($first, 8 - count($second), 8, $second); + $aIP = $first; + unset($first, $second); + } else { + $aIP = explode(':', $aIP[0]); + } + $c = count($aIP); + + if ($c != 8) { + return false; + } + + // All the pieces should be 16-bit hex strings. Are they? + foreach ($aIP as $piece) { + if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) { + return false; + } + } + return $original; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php new file mode 100644 index 0000000..b428331 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php @@ -0,0 +1,60 @@ +confiscateAttr($attr, 'background'); + // some validation should happen here + + $this->prependCSS($attr, "background-image:url($background);"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php new file mode 100644 index 0000000..d66c04a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php @@ -0,0 +1,27 @@ +get('Attr.DefaultTextDir'); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php new file mode 100644 index 0000000..0f51fd2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php @@ -0,0 +1,28 @@ +confiscateAttr($attr, 'bgcolor'); + // some validation should happen here + + $this->prependCSS($attr, "background-color:$bgcolor;"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php new file mode 100644 index 0000000..f25cd01 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php @@ -0,0 +1,47 @@ +attr = $attr; + $this->css = $css; + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->attr])) { + return $attr; + } + unset($attr[$this->attr]); + $this->prependCSS($attr, $this->css); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php new file mode 100644 index 0000000..057dc01 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php @@ -0,0 +1,26 @@ +confiscateAttr($attr, 'border'); + // some validation should happen here + $this->prependCSS($attr, "border:{$border_width}px solid;"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php new file mode 100644 index 0000000..7ccd0e3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php @@ -0,0 +1,68 @@ +attr = $attr; + $this->enumToCSS = $enum_to_css; + $this->caseSensitive = (bool)$case_sensitive; + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->attr])) { + return $attr; + } + + $value = trim($attr[$this->attr]); + unset($attr[$this->attr]); + + if (!$this->caseSensitive) { + $value = strtolower($value); + } + + if (!isset($this->enumToCSS[$value])) { + return $attr; + } + $this->prependCSS($attr, $this->enumToCSS[$value]); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php new file mode 100644 index 0000000..235ebb3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php @@ -0,0 +1,47 @@ +get('Core.RemoveInvalidImg')) { + return $attr; + } + $attr['src'] = $config->get('Attr.DefaultInvalidImage'); + $src = false; + } + + if (!isset($attr['alt'])) { + if ($src) { + $alt = $config->get('Attr.DefaultImageAlt'); + if ($alt === null) { + $attr['alt'] = basename($attr['src']); + } else { + $attr['alt'] = $alt; + } + } else { + $attr['alt'] = $config->get('Attr.DefaultInvalidImageAlt'); + } + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php new file mode 100644 index 0000000..350b335 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php @@ -0,0 +1,61 @@ + array('left', 'right'), + 'vspace' => array('top', 'bottom') + ); + + /** + * @param string $attr + */ + public function __construct($attr) + { + $this->attr = $attr; + if (!isset($this->css[$attr])) { + trigger_error(htmlspecialchars($attr) . ' is not valid space attribute'); + } + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->attr])) { + return $attr; + } + + $width = $this->confiscateAttr($attr, $this->attr); + // some validation could happen here + + if (!isset($this->css[$this->attr])) { + return $attr; + } + + $style = ''; + foreach ($this->css[$this->attr] as $suffix) { + $property = "margin-$suffix"; + $style .= "$property:{$width}px;"; + } + $this->prependCSS($attr, $style); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php new file mode 100644 index 0000000..3ab47ed --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php @@ -0,0 +1,56 @@ +pixels = new HTMLPurifier_AttrDef_HTML_Pixels(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['type'])) { + $t = 'text'; + } else { + $t = strtolower($attr['type']); + } + if (isset($attr['checked']) && $t !== 'radio' && $t !== 'checkbox') { + unset($attr['checked']); + } + if (isset($attr['maxlength']) && $t !== 'text' && $t !== 'password') { + unset($attr['maxlength']); + } + if (isset($attr['size']) && $t !== 'text' && $t !== 'password') { + $result = $this->pixels->validate($attr['size'], $config, $context); + if ($result === false) { + unset($attr['size']); + } else { + $attr['size'] = $result; + } + } + if (isset($attr['src']) && $t !== 'image') { + unset($attr['src']); + } + if (!isset($attr['value']) && ($t === 'radio' || $t === 'checkbox')) { + $attr['value'] = ''; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php new file mode 100644 index 0000000..5b0aff0 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php @@ -0,0 +1,31 @@ +name = $name; + $this->cssName = $css_name ? $css_name : $name; + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr[$this->name])) { + return $attr; + } + $length = $this->confiscateAttr($attr, $this->name); + if (ctype_digit($length)) { + $length .= 'px'; + } + $this->prependCSS($attr, $this->cssName . ":$length;"); + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php new file mode 100644 index 0000000..63cce68 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php @@ -0,0 +1,33 @@ +get('HTML.Attr.Name.UseCDATA')) { + return $attr; + } + if (!isset($attr['name'])) { + return $attr; + } + $id = $this->confiscateAttr($attr, 'name'); + if (isset($attr['id'])) { + return $attr; + } + $attr['id'] = $id; + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php new file mode 100644 index 0000000..5a1fdbb --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php @@ -0,0 +1,46 @@ +idDef = new HTMLPurifier_AttrDef_HTML_ID(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['name'])) { + return $attr; + } + $name = $attr['name']; + if (isset($attr['id']) && $attr['id'] === $name) { + return $attr; + } + $result = $this->idDef->validate($name, $config, $context); + if ($result === false) { + unset($attr['name']); + } else { + $attr['name'] = $result; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php new file mode 100644 index 0000000..1057ebe --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php @@ -0,0 +1,52 @@ +parser = new HTMLPurifier_URIParser(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['href'])) { + return $attr; + } + + // XXX Kind of inefficient + $url = $this->parser->parse($attr['href']); + $scheme = $url->getSchemeObj($config, $context); + + if ($scheme->browsable && !$url->isLocal($config, $context)) { + if (isset($attr['rel'])) { + $rels = explode(' ', $attr['rel']); + if (!in_array('nofollow', $rels)) { + $rels[] = 'nofollow'; + } + $attr['rel'] = implode(' ', $rels); + } else { + $attr['rel'] = 'nofollow'; + } + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php new file mode 100644 index 0000000..231c81a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php @@ -0,0 +1,25 @@ +uri = new HTMLPurifier_AttrDef_URI(true); // embedded + $this->wmode = new HTMLPurifier_AttrDef_Enum(array('window', 'opaque', 'transparent')); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + // If we add support for other objects, we'll need to alter the + // transforms. + switch ($attr['name']) { + // application/x-shockwave-flash + // Keep this synchronized with Injector/SafeObject.php + case 'allowScriptAccess': + $attr['value'] = 'never'; + break; + case 'allowNetworking': + $attr['value'] = 'internal'; + break; + case 'allowFullScreen': + if ($config->get('HTML.FlashAllowFullScreen')) { + $attr['value'] = ($attr['value'] == 'true') ? 'true' : 'false'; + } else { + $attr['value'] = 'false'; + } + break; + case 'wmode': + $attr['value'] = $this->wmode->validate($attr['value'], $config, $context); + break; + case 'movie': + case 'src': + $attr['name'] = "movie"; + $attr['value'] = $this->uri->validate($attr['value'], $config, $context); + break; + case 'flashvars': + // we're going to allow arbitrary inputs to the SWF, on + // the reasoning that it could only hack the SWF, not us. + break; + // add other cases to support other param name/value pairs + default: + $attr['name'] = $attr['value'] = null; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php new file mode 100644 index 0000000..b7057bb --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php @@ -0,0 +1,23 @@ + + */ +class HTMLPurifier_AttrTransform_ScriptRequired extends HTMLPurifier_AttrTransform +{ + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['type'])) { + $attr['type'] = 'text/javascript'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php new file mode 100644 index 0000000..cc30ab8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php @@ -0,0 +1,49 @@ +parser = new HTMLPurifier_URIParser(); + } + + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + if (!isset($attr['href'])) { + return $attr; + } + + // XXX Kind of inefficient + $url = $this->parser->parse($attr['href']); + + // Ignore invalid schemes (e.g. `javascript:`) + if (!($scheme = $url->getSchemeObj($config, $context))) { + return $attr; + } + + if ($scheme->browsable && !$url->isBenign($config, $context)) { + $attr['target'] = '_blank'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetNoopener.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetNoopener.php new file mode 100644 index 0000000..1db3c6c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetNoopener.php @@ -0,0 +1,37 @@ + + */ +class HTMLPurifier_AttrTransform_Textarea extends HTMLPurifier_AttrTransform +{ + /** + * @param array $attr + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function transform($attr, $config, $context) + { + // Calculated from Firefox + if (!isset($attr['cols'])) { + $attr['cols'] = '22'; + } + if (!isset($attr['rows'])) { + $attr['rows'] = '3'; + } + return $attr; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php new file mode 100644 index 0000000..e4429e8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php @@ -0,0 +1,97 @@ +info['Enum'] = new HTMLPurifier_AttrDef_Enum(); + $this->info['Bool'] = new HTMLPurifier_AttrDef_HTML_Bool(); + + $this->info['CDATA'] = new HTMLPurifier_AttrDef_Text(); + $this->info['ID'] = new HTMLPurifier_AttrDef_HTML_ID(); + $this->info['Length'] = new HTMLPurifier_AttrDef_HTML_Length(); + $this->info['MultiLength'] = new HTMLPurifier_AttrDef_HTML_MultiLength(); + $this->info['NMTOKENS'] = new HTMLPurifier_AttrDef_HTML_Nmtokens(); + $this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels(); + $this->info['Text'] = new HTMLPurifier_AttrDef_Text(); + $this->info['URI'] = new HTMLPurifier_AttrDef_URI(); + $this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang(); + $this->info['Color'] = new HTMLPurifier_AttrDef_HTML_Color(); + $this->info['IAlign'] = self::makeEnum('top,middle,bottom,left,right'); + $this->info['LAlign'] = self::makeEnum('top,bottom,left,right'); + $this->info['FrameTarget'] = new HTMLPurifier_AttrDef_HTML_FrameTarget(); + $this->info['ContentEditable'] = new HTMLPurifier_AttrDef_HTML_ContentEditable(); + + // unimplemented aliases + $this->info['ContentType'] = new HTMLPurifier_AttrDef_Text(); + $this->info['ContentTypes'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Charsets'] = new HTMLPurifier_AttrDef_Text(); + $this->info['Character'] = new HTMLPurifier_AttrDef_Text(); + + // "proprietary" types + $this->info['Class'] = new HTMLPurifier_AttrDef_HTML_Class(); + + // number is really a positive integer (one or more digits) + // FIXME: ^^ not always, see start and value of list items + $this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true); + } + + private static function makeEnum($in) + { + return new HTMLPurifier_AttrDef_Clone(new HTMLPurifier_AttrDef_Enum(explode(',', $in))); + } + + /** + * Retrieves a type + * @param string $type String type name + * @return HTMLPurifier_AttrDef Object AttrDef for type + */ + public function get($type) + { + // determine if there is any extra info tacked on + if (strpos($type, '#') !== false) { + list($type, $string) = explode('#', $type, 2); + } else { + $string = ''; + } + + if (!isset($this->info[$type])) { + trigger_error('Cannot retrieve undefined attribute type ' . $type, E_USER_ERROR); + return; + } + return $this->info[$type]->make($string); + } + + /** + * Sets a new implementation for a type + * @param string $type String type name + * @param HTMLPurifier_AttrDef $impl Object AttrDef for type + */ + public function set($type, $impl) + { + $this->info[$type] = $impl; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php new file mode 100644 index 0000000..f97dc93 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php @@ -0,0 +1,178 @@ +getHTMLDefinition(); + $e =& $context->get('ErrorCollector', true); + + // initialize IDAccumulator if necessary + $ok =& $context->get('IDAccumulator', true); + if (!$ok) { + $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context); + $context->register('IDAccumulator', $id_accumulator); + } + + // initialize CurrentToken if necessary + $current_token =& $context->get('CurrentToken', true); + if (!$current_token) { + $context->register('CurrentToken', $token); + } + + if (!$token instanceof HTMLPurifier_Token_Start && + !$token instanceof HTMLPurifier_Token_Empty + ) { + return; + } + + // create alias to global definition array, see also $defs + // DEFINITION CALL + $d_defs = $definition->info_global_attr; + + // don't update token until the very end, to ensure an atomic update + $attr = $token->attr; + + // do global transformations (pre) + // nothing currently utilizes this + foreach ($definition->info_attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // do local transformations only applicable to this element (pre) + // ex.

to

+ foreach ($definition->info[$token->name]->attr_transform_pre as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // create alias to this element's attribute definition array, see + // also $d_defs (global attribute definition array) + // DEFINITION CALL + $defs = $definition->info[$token->name]->attr; + + $attr_key = false; + $context->register('CurrentAttr', $attr_key); + + // iterate through all the attribute keypairs + // Watch out for name collisions: $key has previously been used + foreach ($attr as $attr_key => $value) { + + // call the definition + if (isset($defs[$attr_key])) { + // there is a local definition defined + if ($defs[$attr_key] === false) { + // We've explicitly been told not to allow this element. + // This is usually when there's a global definition + // that must be overridden. + // Theoretically speaking, we could have a + // AttrDef_DenyAll, but this is faster! + $result = false; + } else { + // validate according to the element's definition + $result = $defs[$attr_key]->validate( + $value, + $config, + $context + ); + } + } elseif (isset($d_defs[$attr_key])) { + // there is a global definition defined, validate according + // to the global definition + $result = $d_defs[$attr_key]->validate( + $value, + $config, + $context + ); + } else { + // system never heard of the attribute? DELETE! + $result = false; + } + + // put the results into effect + if ($result === false || $result === null) { + // this is a generic error message that should replaced + // with more specific ones when possible + if ($e) { + $e->send(E_ERROR, 'AttrValidator: Attribute removed'); + } + + // remove the attribute + unset($attr[$attr_key]); + } elseif (is_string($result)) { + // generally, if a substitution is happening, there + // was some sort of implicit correction going on. We'll + // delegate it to the attribute classes to say exactly what. + + // simple substitution + $attr[$attr_key] = $result; + } else { + // nothing happens + } + + // we'd also want slightly more complicated substitution + // involving an array as the return value, + // although we're not sure how colliding attributes would + // resolve (certain ones would be completely overriden, + // others would prepend themselves). + } + + $context->destroy('CurrentAttr'); + + // post transforms + + // global (error reporting untested) + foreach ($definition->info_attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + // local (error reporting untested) + foreach ($definition->info[$token->name]->attr_transform_post as $transform) { + $attr = $transform->transform($o = $attr, $config, $context); + if ($e) { + if ($attr != $o) { + $e->send(E_NOTICE, 'AttrValidator: Attributes transformed', $o, $attr); + } + } + } + + $token->attr = $attr; + + // destroy CurrentToken if we made it ourselves + if (!$current_token) { + $context->destroy('CurrentToken'); + } + + } + + +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php new file mode 100644 index 0000000..bd8f998 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php @@ -0,0 +1,91 @@ + +if (!defined('PHP_EOL')) { + switch (strtoupper(substr(PHP_OS, 0, 3))) { + case 'WIN': + define('PHP_EOL', "\r\n"); + break; + case 'DAR': + define('PHP_EOL', "\r"); + break; + default: + define('PHP_EOL', "\n"); + } +} + +/** + * Bootstrap class that contains meta-functionality for HTML Purifier such as + * the autoload function. + * + * @note + * This class may be used without any other files from HTML Purifier. + */ +class HTMLPurifier_Bootstrap +{ + + /** + * Autoload function for HTML Purifier + * @param string $class Class to load + * @return bool + */ + public static function autoload($class) + { + $file = HTMLPurifier_Bootstrap::getPath($class); + if (!$file) { + return false; + } + // Technically speaking, it should be ok and more efficient to + // just do 'require', but Antonio Parraga reports that with + // Zend extensions such as Zend debugger and APC, this invariant + // may be broken. Since we have efficient alternatives, pay + // the cost here and avoid the bug. + require_once HTMLPURIFIER_PREFIX . '/' . $file; + return true; + } + + /** + * Returns the path for a specific class. + * @param string $class Class path to get + * @return string + */ + public static function getPath($class) + { + if (strncmp('HTMLPurifier', $class, 12) !== 0) { + return false; + } + // Custom implementations + if (strncmp('HTMLPurifier_Language_', $class, 22) === 0) { + $code = str_replace('_', '-', substr($class, 22)); + $file = 'HTMLPurifier/Language/classes/' . $code . '.php'; + } else { + $file = str_replace('_', '/', $class) . '.php'; + } + if (!file_exists(HTMLPURIFIER_PREFIX . '/' . $file)) { + return false; + } + return $file; + } + + /** + * "Pre-registers" our autoloader on the SPL stack. + */ + public static function registerAutoload() + { + $autoload = array('HTMLPurifier_Bootstrap', 'autoload'); + if (spl_autoload_functions() === false) { + spl_autoload_register($autoload); + } else { + // prepend flag exists, no need for shenanigans + spl_autoload_register($autoload, true, true); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php new file mode 100644 index 0000000..1bc419c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php @@ -0,0 +1,566 @@ +info['text-align'] = new HTMLPurifier_AttrDef_Enum( + ['left', 'right', 'center', 'justify'], + false + ); + + $border_style = + $this->info['border-bottom-style'] = + $this->info['border-right-style'] = + $this->info['border-left-style'] = + $this->info['border-top-style'] = new HTMLPurifier_AttrDef_Enum( + [ + 'none', + 'hidden', + 'dotted', + 'dashed', + 'solid', + 'double', + 'groove', + 'ridge', + 'inset', + 'outset' + ], + false + ); + + $this->info['border-style'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_style); + + $this->info['clear'] = new HTMLPurifier_AttrDef_Enum( + ['none', 'left', 'right', 'both'], + false + ); + $this->info['float'] = new HTMLPurifier_AttrDef_Enum( + ['none', 'left', 'right'], + false + ); + $this->info['font-style'] = new HTMLPurifier_AttrDef_Enum( + ['normal', 'italic', 'oblique'], + false + ); + $this->info['font-variant'] = new HTMLPurifier_AttrDef_Enum( + ['normal', 'small-caps'], + false + ); + + $uri_or_none = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['none']), + new HTMLPurifier_AttrDef_CSS_URI() + ] + ); + + $this->info['list-style-position'] = new HTMLPurifier_AttrDef_Enum( + ['inside', 'outside'], + false + ); + $this->info['list-style-type'] = new HTMLPurifier_AttrDef_Enum( + [ + 'disc', + 'circle', + 'square', + 'decimal', + 'lower-roman', + 'upper-roman', + 'lower-alpha', + 'upper-alpha', + 'none' + ], + false + ); + $this->info['list-style-image'] = $uri_or_none; + + $this->info['list-style'] = new HTMLPurifier_AttrDef_CSS_ListStyle($config); + + $this->info['text-transform'] = new HTMLPurifier_AttrDef_Enum( + ['capitalize', 'uppercase', 'lowercase', 'none'], + false + ); + $this->info['color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + $this->info['background-image'] = $uri_or_none; + $this->info['background-repeat'] = new HTMLPurifier_AttrDef_Enum( + ['repeat', 'repeat-x', 'repeat-y', 'no-repeat'] + ); + $this->info['background-attachment'] = new HTMLPurifier_AttrDef_Enum( + ['scroll', 'fixed'] + ); + $this->info['background-position'] = new HTMLPurifier_AttrDef_CSS_BackgroundPosition(); + + $this->info['background-size'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum( + [ + 'auto', + 'cover', + 'contain', + 'initial', + 'inherit', + ] + ), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_CSS_Length() + ] + ); + + $border_color = + $this->info['border-top-color'] = + $this->info['border-bottom-color'] = + $this->info['border-left-color'] = + $this->info['border-right-color'] = + $this->info['background-color'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['transparent']), + new HTMLPurifier_AttrDef_CSS_Color() + ] + ); + + $this->info['background'] = new HTMLPurifier_AttrDef_CSS_Background($config); + + $this->info['border-color'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_color); + + $border_width = + $this->info['border-top-width'] = + $this->info['border-bottom-width'] = + $this->info['border-left-width'] = + $this->info['border-right-width'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['thin', 'medium', 'thick']), + new HTMLPurifier_AttrDef_CSS_Length('0') //disallow negative + ] + ); + + $this->info['border-width'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_width); + + $this->info['letter-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['normal']), + new HTMLPurifier_AttrDef_CSS_Length() + ] + ); + + $this->info['word-spacing'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['normal']), + new HTMLPurifier_AttrDef_CSS_Length() + ] + ); + + $this->info['font-size'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum( + [ + 'xx-small', + 'x-small', + 'small', + 'medium', + 'large', + 'x-large', + 'xx-large', + 'larger', + 'smaller' + ] + ), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_CSS_Length() + ] + ); + + $this->info['line-height'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum(['normal']), + new HTMLPurifier_AttrDef_CSS_Number(true), // no negatives + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + ] + ); + + $margin = + $this->info['margin-top'] = + $this->info['margin-bottom'] = + $this->info['margin-left'] = + $this->info['margin-right'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(['auto']) + ] + ); + + $this->info['margin'] = new HTMLPurifier_AttrDef_CSS_Multiple($margin); + + // non-negative + $padding = + $this->info['padding-top'] = + $this->info['padding-bottom'] = + $this->info['padding-left'] = + $this->info['padding-right'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true) + ] + ); + + $this->info['padding'] = new HTMLPurifier_AttrDef_CSS_Multiple($padding); + + $this->info['text-indent'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + ] + ); + + $trusted_wh = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(['auto', 'initial', 'inherit']) + ] + ); + $trusted_min_wh = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(['initial', 'inherit']) + ] + ); + $trusted_max_wh = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0'), + new HTMLPurifier_AttrDef_CSS_Percentage(true), + new HTMLPurifier_AttrDef_Enum(['none', 'initial', 'inherit']) + ] + ); + $max = $config->get('CSS.MaxImgLength'); + + $this->info['width'] = + $this->info['height'] = + $max === null ? + $trusted_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(['auto']) + ] + ), + // For everyone else: + $trusted_wh + ); + $this->info['min-width'] = + $this->info['min-height'] = + $max === null ? + $trusted_min_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(['initial', 'inherit']) + ] + ), + // For everyone else: + $trusted_min_wh + ); + $this->info['max-width'] = + $this->info['max-height'] = + $max === null ? + $trusted_max_wh : + new HTMLPurifier_AttrDef_Switch( + 'img', + // For img tags: + new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length('0', $max), + new HTMLPurifier_AttrDef_Enum(['none', 'initial', 'inherit']) + ] + ), + // For everyone else: + $trusted_max_wh + ); + + // text-decoration and related shorthands + $this->info['text-decoration'] = new HTMLPurifier_AttrDef_CSS_TextDecoration(); + + $this->info['text-decoration-line'] = new HTMLPurifier_AttrDef_Enum( + ['none', 'underline', 'overline', 'line-through', 'initial', 'inherit'] + ); + + $this->info['text-decoration-style'] = new HTMLPurifier_AttrDef_Enum( + ['solid', 'double', 'dotted', 'dashed', 'wavy', 'initial', 'inherit'] + ); + + $this->info['text-decoration-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + $this->info['text-decoration-thickness'] = new HTMLPurifier_AttrDef_CSS_Composite([ + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(['auto', 'from-font', 'initial', 'inherit']) + ]); + + $this->info['font-family'] = new HTMLPurifier_AttrDef_CSS_FontFamily(); + + // this could use specialized code + $this->info['font-weight'] = new HTMLPurifier_AttrDef_Enum( + [ + 'normal', + 'bold', + 'bolder', + 'lighter', + '100', + '200', + '300', + '400', + '500', + '600', + '700', + '800', + '900' + ], + false + ); + + // MUST be called after other font properties, as it references + // a CSSDefinition object + $this->info['font'] = new HTMLPurifier_AttrDef_CSS_Font($config); + + // same here + $this->info['border'] = + $this->info['border-bottom'] = + $this->info['border-top'] = + $this->info['border-left'] = + $this->info['border-right'] = new HTMLPurifier_AttrDef_CSS_Border($config); + + $this->info['border-collapse'] = new HTMLPurifier_AttrDef_Enum( + ['collapse', 'separate'] + ); + + $this->info['caption-side'] = new HTMLPurifier_AttrDef_Enum( + ['top', 'bottom'] + ); + + $this->info['table-layout'] = new HTMLPurifier_AttrDef_Enum( + ['auto', 'fixed'] + ); + + $this->info['vertical-align'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Enum( + [ + 'baseline', + 'sub', + 'super', + 'top', + 'text-top', + 'middle', + 'bottom', + 'text-bottom' + ] + ), + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage() + ] + ); + + $this->info['border-spacing'] = new HTMLPurifier_AttrDef_CSS_Multiple(new HTMLPurifier_AttrDef_CSS_Length(), 2); + + // These CSS properties don't work on many browsers, but we live + // in THE FUTURE! + $this->info['white-space'] = new HTMLPurifier_AttrDef_Enum( + ['nowrap', 'normal', 'pre', 'pre-wrap', 'pre-line'] + ); + + if ($config->get('CSS.Proprietary')) { + $this->doSetupProprietary($config); + } + + if ($config->get('CSS.AllowTricky')) { + $this->doSetupTricky($config); + } + + if ($config->get('CSS.Trusted')) { + $this->doSetupTrusted($config); + } + + $allow_important = $config->get('CSS.AllowImportant'); + // wrap all attr-defs with decorator that handles !important + foreach ($this->info as $k => $v) { + $this->info[$k] = new HTMLPurifier_AttrDef_CSS_ImportantDecorator($v, $allow_important); + } + + $this->setupConfigStuff($config); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupProprietary($config) + { + // Internet Explorer only scrollbar colors + $this->info['scrollbar-arrow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-base-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-darkshadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-face-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-highlight-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + $this->info['scrollbar-shadow-color'] = new HTMLPurifier_AttrDef_CSS_Color(); + + // vendor specific prefixes of opacity + $this->info['-moz-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + $this->info['-khtml-opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + + // only opacity, for now + $this->info['filter'] = new HTMLPurifier_AttrDef_CSS_Filter(); + + // more CSS3 + $this->info['page-break-after'] = + $this->info['page-break-before'] = new HTMLPurifier_AttrDef_Enum( + [ + 'auto', + 'always', + 'avoid', + 'left', + 'right' + ] + ); + $this->info['page-break-inside'] = new HTMLPurifier_AttrDef_Enum(['auto', 'avoid']); + + $border_radius = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Percentage(true), // disallow negative + new HTMLPurifier_AttrDef_CSS_Length('0') // disallow negative + ]); + + $this->info['border-top-left-radius'] = + $this->info['border-top-right-radius'] = + $this->info['border-bottom-right-radius'] = + $this->info['border-bottom-left-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 2); + // TODO: support SLASH syntax + $this->info['border-radius'] = new HTMLPurifier_AttrDef_CSS_Multiple($border_radius, 4); + + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupTricky($config) + { + $this->info['display'] = new HTMLPurifier_AttrDef_Enum( + [ + 'inline', + 'block', + 'list-item', + 'run-in', + 'compact', + 'marker', + 'table', + 'inline-block', + 'inline-table', + 'table-row-group', + 'table-header-group', + 'table-footer-group', + 'table-row', + 'table-column-group', + 'table-column', + 'table-cell', + 'table-caption', + 'none' + ] + ); + $this->info['visibility'] = new HTMLPurifier_AttrDef_Enum( + ['visible', 'hidden', 'collapse'] + ); + $this->info['overflow'] = new HTMLPurifier_AttrDef_Enum(['visible', 'hidden', 'auto', 'scroll']); + $this->info['opacity'] = new HTMLPurifier_AttrDef_CSS_AlphaValue(); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetupTrusted($config) + { + $this->info['position'] = new HTMLPurifier_AttrDef_Enum( + ['static', 'relative', 'absolute', 'fixed'] + ); + $this->info['top'] = + $this->info['left'] = + $this->info['right'] = + $this->info['bottom'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_CSS_Length(), + new HTMLPurifier_AttrDef_CSS_Percentage(), + new HTMLPurifier_AttrDef_Enum(['auto']), + ] + ); + $this->info['z-index'] = new HTMLPurifier_AttrDef_CSS_Composite( + [ + new HTMLPurifier_AttrDef_Integer(), + new HTMLPurifier_AttrDef_Enum(['auto']), + ] + ); + } + + /** + * Performs extra config-based processing. Based off of + * HTMLPurifier_HTMLDefinition. + * @param HTMLPurifier_Config $config + * @todo Refactor duplicate elements into common class (probably using + * composition, not inheritance). + */ + protected function setupConfigStuff($config) + { + // setup allowed elements + $support = "(for information on implementing this, see the " . + "support forums) "; + $allowed_properties = $config->get('CSS.AllowedProperties'); + if ($allowed_properties !== null) { + foreach ($this->info as $name => $d) { + if (!isset($allowed_properties[$name])) { + unset($this->info[$name]); + } + unset($allowed_properties[$name]); + } + // emit errors + foreach ($allowed_properties as $name => $d) { + // :TODO: Is this htmlspecialchars() call really necessary? + $name = htmlspecialchars($name); + trigger_error("Style attribute '$name' is not supported $support", E_USER_WARNING); + } + } + + $forbidden_properties = $config->get('CSS.ForbiddenProperties'); + if ($forbidden_properties !== null) { + foreach ($this->info as $name => $d) { + if (isset($forbidden_properties[$name])) { + unset($this->info[$name]); + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php new file mode 100644 index 0000000..8eb17b8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php @@ -0,0 +1,52 @@ +elements; + } + + /** + * Validates nodes according to definition and returns modification. + * + * @param HTMLPurifier_Node[] $children Array of HTMLPurifier_Node + * @param HTMLPurifier_Config $config HTMLPurifier_Config object + * @param HTMLPurifier_Context $context HTMLPurifier_Context object + * @return bool|array true to leave nodes as is, false to remove parent node, array of replacement children + */ + abstract public function validateChildren($children, $config, $context); +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php new file mode 100644 index 0000000..7439be2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php @@ -0,0 +1,67 @@ +inline = new HTMLPurifier_ChildDef_Optional($inline); + $this->block = new HTMLPurifier_ChildDef_Optional($block); + $this->elements = $this->block->elements; + } + + /** + * @param HTMLPurifier_Node[] $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function validateChildren($children, $config, $context) + { + if ($context->get('IsInline') === false) { + return $this->block->validateChildren( + $children, + $config, + $context + ); + } else { + return $this->inline->validateChildren( + $children, + $config, + $context + ); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php new file mode 100644 index 0000000..f515888 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php @@ -0,0 +1,102 @@ +dtd_regex = $dtd_regex; + $this->_compileRegex(); + } + + /** + * Compiles the PCRE regex from a DTD regex ($dtd_regex to $_pcre_regex) + */ + protected function _compileRegex() + { + $raw = str_replace(' ', '', $this->dtd_regex); + if ($raw[0] != '(') { + $raw = "($raw)"; + } + $el = '[#a-zA-Z0-9_.-]+'; + $reg = $raw; + + // COMPLICATED! AND MIGHT BE BUGGY! I HAVE NO CLUE WHAT I'M + // DOING! Seriously: if there's problems, please report them. + + // collect all elements into the $elements array + preg_match_all("/$el/", $reg, $matches); + foreach ($matches[0] as $match) { + $this->elements[$match] = true; + } + + // setup all elements as parentheticals with leading commas + $reg = preg_replace("/$el/", '(,\\0)', $reg); + + // remove commas when they were not solicited + $reg = preg_replace("/([^,(|]\(+),/", '\\1', $reg); + + // remove all non-paranthetical commas: they are handled by first regex + $reg = preg_replace("/,\(/", '(', $reg); + + $this->_pcre_regex = $reg; + } + + /** + * @param HTMLPurifier_Node[] $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return bool + */ + public function validateChildren($children, $config, $context) + { + $list_of_children = ''; + $nesting = 0; // depth into the nest + foreach ($children as $node) { + if (!empty($node->is_whitespace)) { + continue; + } + $list_of_children .= $node->name . ','; + } + // add leading comma to deal with stray comma declarations + $list_of_children = ',' . rtrim($list_of_children, ','); + $okay = + preg_match( + '/^,?' . $this->_pcre_regex . '$/', + $list_of_children + ); + return (bool)$okay; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php new file mode 100644 index 0000000..a8a6cbd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php @@ -0,0 +1,38 @@ + true, 'ul' => true, 'ol' => true); + + public $whitespace; + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + // Flag for subclasses + $this->whitespace = false; + + // if there are no tokens, delete parent node + if (empty($children)) { + return false; + } + + // if li is not allowed, delete parent node + if (!isset($config->getHTMLDefinition()->info['li'])) { + trigger_error("Cannot allow ul/ol without allowing li", E_USER_WARNING); + return false; + } + + // the new set of children + $result = array(); + + // a little sanity check to make sure it's not ALL whitespace + $all_whitespace = true; + + $current_li = null; + + foreach ($children as $node) { + if (!empty($node->is_whitespace)) { + $result[] = $node; + continue; + } + $all_whitespace = false; // phew, we're not talking about whitespace + + if ($node->name === 'li') { + // good + $current_li = $node; + $result[] = $node; + } else { + // we want to tuck this into the previous li + // Invariant: we expect the node to be ol/ul + // ToDo: Make this more robust in the case of not ol/ul + // by distinguishing between existing li and li created + // to handle non-list elements; non-list elements should + // not be appended to an existing li; only li created + // for non-list. This distinction is not currently made. + if ($current_li === null) { + $current_li = new HTMLPurifier_Node_Element('li'); + $result[] = $current_li; + } + $current_li->children[] = $node; + $current_li->empty = false; // XXX fascinating! Check for this error elsewhere ToDo + } + } + if (empty($result)) { + return false; + } + if ($all_whitespace) { + return false; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php new file mode 100644 index 0000000..b946806 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php @@ -0,0 +1,45 @@ +whitespace) { + return $children; + } else { + return array(); + } + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php new file mode 100644 index 0000000..0d1c8f5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php @@ -0,0 +1,118 @@ + $x) { + $elements[$i] = true; + if (empty($i)) { + unset($elements[$i]); + } // remove blank + } + } + $this->elements = $elements; + } + + /** + * @type bool + */ + public $allow_empty = false; + + /** + * @type string + */ + public $type = 'required'; + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + // Flag for subclasses + $this->whitespace = false; + + // if there are no tokens, delete parent node + if (empty($children)) { + return false; + } + + // the new set of children + $result = array(); + + // whether or not parsed character data is allowed + // this controls whether or not we silently drop a tag + // or generate escaped HTML from it + $pcdata_allowed = isset($this->elements['#PCDATA']); + + // a little sanity check to make sure it's not ALL whitespace + $all_whitespace = true; + + $stack = array_reverse($children); + while (!empty($stack)) { + $node = array_pop($stack); + if (!empty($node->is_whitespace)) { + $result[] = $node; + continue; + } + $all_whitespace = false; // phew, we're not talking about whitespace + + if (!isset($this->elements[$node->name])) { + // special case text + // XXX One of these ought to be redundant or something + if ($pcdata_allowed && $node instanceof HTMLPurifier_Node_Text) { + $result[] = $node; + continue; + } + // spill the child contents in + // ToDo: Make configurable + if ($node instanceof HTMLPurifier_Node_Element) { + for ($i = count($node->children) - 1; $i >= 0; $i--) { + $stack[] = $node->children[$i]; + } + continue; + } + continue; + } + $result[] = $node; + } + if (empty($result)) { + return false; + } + if ($all_whitespace) { + $this->whitespace = true; + return false; + } + return $result; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php new file mode 100644 index 0000000..3270a46 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php @@ -0,0 +1,110 @@ +init($config); + return $this->fake_elements; + } + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + $this->init($config); + + // trick the parent class into thinking it allows more + $this->elements = $this->fake_elements; + $result = parent::validateChildren($children, $config, $context); + $this->elements = $this->real_elements; + + if ($result === false) { + return array(); + } + if ($result === true) { + $result = $children; + } + + $def = $config->getHTMLDefinition(); + $block_wrap_name = $def->info_block_wrapper; + $block_wrap = false; + $ret = array(); + + foreach ($result as $node) { + if ($block_wrap === false) { + if (($node instanceof HTMLPurifier_Node_Text && !$node->is_whitespace) || + ($node instanceof HTMLPurifier_Node_Element && !isset($this->elements[$node->name]))) { + $block_wrap = new HTMLPurifier_Node_Element($def->info_block_wrapper); + $ret[] = $block_wrap; + } + } else { + if ($node instanceof HTMLPurifier_Node_Element && isset($this->elements[$node->name])) { + $block_wrap = false; + + } + } + if ($block_wrap) { + $block_wrap->children[] = $node; + } else { + $ret[] = $node; + } + } + return $ret; + } + + /** + * @param HTMLPurifier_Config $config + */ + private function init($config) + { + if (!$this->init) { + $def = $config->getHTMLDefinition(); + // allow all inline elements + $this->real_elements = $this->elements; + $this->fake_elements = $def->info_content_sets['Flow']; + $this->fake_elements['#PCDATA'] = true; + $this->init = true; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php new file mode 100644 index 0000000..67c7e95 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php @@ -0,0 +1,224 @@ + true, + 'tbody' => true, + 'thead' => true, + 'tfoot' => true, + 'caption' => true, + 'colgroup' => true, + 'col' => true + ); + + public function __construct() + { + } + + /** + * @param array $children + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array + */ + public function validateChildren($children, $config, $context) + { + if (empty($children)) { + return false; + } + + // only one of these elements is allowed in a table + $caption = false; + $thead = false; + $tfoot = false; + + // whitespace + $initial_ws = array(); + $after_caption_ws = array(); + $after_thead_ws = array(); + $after_tfoot_ws = array(); + + // as many of these as you want + $cols = array(); + $content = array(); + + $tbody_mode = false; // if true, then we need to wrap any stray + // s with a . + + $ws_accum =& $initial_ws; + + foreach ($children as $node) { + if ($node instanceof HTMLPurifier_Node_Comment) { + $ws_accum[] = $node; + continue; + } + switch ($node->name) { + case 'tbody': + $tbody_mode = true; + // fall through + case 'tr': + $content[] = $node; + $ws_accum =& $content; + break; + case 'caption': + // there can only be one caption! + if ($caption !== false) break; + $caption = $node; + $ws_accum =& $after_caption_ws; + break; + case 'thead': + $tbody_mode = true; + // XXX This breaks rendering properties with + // Firefox, which never floats a to + // the top. Ever. (Our scheme will float the + // first to the top.) So maybe + // s that are not first should be + // turned into ? Very tricky, indeed. + if ($thead === false) { + $thead = $node; + $ws_accum =& $after_thead_ws; + } else { + // Oops, there's a second one! What + // should we do? Current behavior is to + // transmutate the first and last entries into + // tbody tags, and then put into content. + // Maybe a better idea is to *attach + // it* to the existing thead or tfoot? + // We don't do this, because Firefox + // doesn't float an extra tfoot to the + // bottom like it does for the first one. + $node->name = 'tbody'; + $content[] = $node; + $ws_accum =& $content; + } + break; + case 'tfoot': + // see above for some aveats + $tbody_mode = true; + if ($tfoot === false) { + $tfoot = $node; + $ws_accum =& $after_tfoot_ws; + } else { + $node->name = 'tbody'; + $content[] = $node; + $ws_accum =& $content; + } + break; + case 'colgroup': + case 'col': + $cols[] = $node; + $ws_accum =& $cols; + break; + case '#PCDATA': + // How is whitespace handled? We treat is as sticky to + // the *end* of the previous element. So all of the + // nonsense we have worked on is to keep things + // together. + if (!empty($node->is_whitespace)) { + $ws_accum[] = $node; + } + break; + } + } + + if (empty($content) && $thead === false && $tfoot === false) { + return false; + } + + $ret = $initial_ws; + if ($caption !== false) { + $ret[] = $caption; + $ret = array_merge($ret, $after_caption_ws); + } + if ($cols !== false) { + $ret = array_merge($ret, $cols); + } + if ($thead !== false) { + $ret[] = $thead; + $ret = array_merge($ret, $after_thead_ws); + } + if ($tfoot !== false) { + $ret[] = $tfoot; + $ret = array_merge($ret, $after_tfoot_ws); + } + + if ($tbody_mode) { + // we have to shuffle tr into tbody + $current_tr_tbody = null; + + foreach($content as $node) { + switch ($node->name) { + case 'tbody': + $current_tr_tbody = null; + $ret[] = $node; + break; + case 'tr': + if ($current_tr_tbody === null) { + $current_tr_tbody = new HTMLPurifier_Node_Element('tbody'); + $ret[] = $current_tr_tbody; + } + $current_tr_tbody->children[] = $node; + break; + case '#PCDATA': + //assert($node->is_whitespace); + if ($current_tr_tbody === null) { + $ret[] = $node; + } else { + $current_tr_tbody->children[] = $node; + } + break; + } + } + } else { + $ret = array_merge($ret, $content); + } + + return $ret; + + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php new file mode 100644 index 0000000..f7511ca --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php @@ -0,0 +1,920 @@ +defaultPlist; + $this->plist = new HTMLPurifier_PropertyList($parent); + $this->def = $definition; // keep a copy around for checking + $this->parser = new HTMLPurifier_VarParser_Flexible(); + } + + /** + * Convenience constructor that creates a config object based on a mixed var + * @param mixed $config Variable that defines the state of the config + * object. Can be: a HTMLPurifier_Config() object, + * an array of directives based on loadArray(), + * or a string filename of an ini file. + * @param HTMLPurifier_ConfigSchema $schema Schema object + * @return HTMLPurifier_Config Configured object + */ + public static function create($config, $schema = null) + { + if ($config instanceof HTMLPurifier_Config) { + // pass-through + return $config; + } + if (!$schema) { + $ret = HTMLPurifier_Config::createDefault(); + } else { + $ret = new HTMLPurifier_Config($schema); + } + if (is_string($config)) { + $ret->loadIni($config); + } elseif (is_array($config)) $ret->loadArray($config); + return $ret; + } + + /** + * Creates a new config object that inherits from a previous one. + * @param HTMLPurifier_Config $config Configuration object to inherit from. + * @return HTMLPurifier_Config object with $config as its parent. + */ + public static function inherit(HTMLPurifier_Config $config) + { + return new HTMLPurifier_Config($config->def, $config->plist); + } + + /** + * Convenience constructor that creates a default configuration object. + * @return HTMLPurifier_Config default object. + */ + public static function createDefault() + { + $definition = HTMLPurifier_ConfigSchema::instance(); + $config = new HTMLPurifier_Config($definition); + return $config; + } + + /** + * Retrieves a value from the configuration. + * + * @param string $key String key + * @param mixed $a + * + * @return mixed + */ + public function get($key, $a = null) + { + if ($a !== null) { + $this->triggerError( + "Using deprecated API: use \$config->get('$key.$a') instead", + E_USER_WARNING + ); + $key = "$key.$a"; + } + if (!$this->finalized) { + $this->autoFinalize(); + } + if (!isset($this->def->info[$key])) { + // can't add % due to SimpleTest bug + $this->triggerError( + 'Cannot retrieve value of undefined directive ' . htmlspecialchars($key), + E_USER_WARNING + ); + return; + } + if (isset($this->def->info[$key]->isAlias)) { + $d = $this->def->info[$key]; + $this->triggerError( + 'Cannot get value from aliased directive, use real name ' . $d->key, + E_USER_ERROR + ); + return; + } + if ($this->lock) { + list($ns) = explode('.', $key); + if ($ns !== $this->lock) { + $this->triggerError( + 'Cannot get value of namespace ' . $ns . ' when lock for ' . + $this->lock . + ' is active, this probably indicates a Definition setup method ' . + 'is accessing directives that are not within its namespace', + E_USER_ERROR + ); + return; + } + } + return $this->plist->get($key); + } + + /** + * Retrieves an array of directives to values from a given namespace + * + * @param string $namespace String namespace + * + * @return array + */ + public function getBatch($namespace) + { + if (!$this->finalized) { + $this->autoFinalize(); + } + $full = $this->getAll(); + if (!isset($full[$namespace])) { + $this->triggerError( + 'Cannot retrieve undefined namespace ' . + htmlspecialchars($namespace), + E_USER_WARNING + ); + return; + } + return $full[$namespace]; + } + + /** + * Returns a SHA-1 signature of a segment of the configuration object + * that uniquely identifies that particular configuration + * + * @param string $namespace Namespace to get serial for + * + * @return string + * @note Revision is handled specially and is removed from the batch + * before processing! + */ + public function getBatchSerial($namespace) + { + if (empty($this->serials[$namespace])) { + $batch = $this->getBatch($namespace); + unset($batch['DefinitionRev']); + $this->serials[$namespace] = sha1(serialize($batch)); + } + return $this->serials[$namespace]; + } + + /** + * Returns a SHA-1 signature for the entire configuration object + * that uniquely identifies that particular configuration + * + * @return string + */ + public function getSerial() + { + if (empty($this->serial)) { + $this->serial = sha1(serialize($this->getAll())); + } + return $this->serial; + } + + /** + * Retrieves all directives, organized by namespace + * + * @warning This is a pretty inefficient function, avoid if you can + */ + public function getAll() + { + if (!$this->finalized) { + $this->autoFinalize(); + } + $ret = array(); + foreach ($this->plist->squash() as $name => $value) { + list($ns, $key) = explode('.', $name, 2); + $ret[$ns][$key] = $value; + } + return $ret; + } + + /** + * Sets a value to configuration. + * + * @param string $key key + * @param mixed $value value + * @param mixed $a + */ + public function set($key, $value, $a = null) + { + if (strpos($key, '.') === false) { + $namespace = $key; + $directive = $value; + $value = $a; + $key = "$key.$directive"; + $this->triggerError("Using deprecated API: use \$config->set('$key', ...) instead", E_USER_NOTICE); + } else { + list($namespace) = explode('.', $key); + } + if ($this->isFinalized('Cannot set directive after finalization')) { + return; + } + if (!isset($this->def->info[$key])) { + $this->triggerError( + 'Cannot set undefined directive ' . htmlspecialchars($key) . ' to value', + E_USER_WARNING + ); + return; + } + $def = $this->def->info[$key]; + + if (isset($def->isAlias)) { + if ($this->aliasMode) { + $this->triggerError( + 'Double-aliases not allowed, please fix '. + 'ConfigSchema bug with' . $key, + E_USER_ERROR + ); + return; + } + $this->aliasMode = true; + $this->set($def->key, $value); + $this->aliasMode = false; + $this->triggerError("$key is an alias, preferred directive name is {$def->key}", E_USER_NOTICE); + return; + } + + // Raw type might be negative when using the fully optimized form + // of stdClass, which indicates allow_null == true + $rtype = is_int($def) ? $def : $def->type; + if ($rtype < 0) { + $type = -$rtype; + $allow_null = true; + } else { + $type = $rtype; + $allow_null = isset($def->allow_null); + } + + try { + $value = $this->parser->parse($value, $type, $allow_null); + } catch (HTMLPurifier_VarParserException $e) { + $this->triggerError( + 'Value for ' . $key . ' is of invalid type, should be ' . + HTMLPurifier_VarParser::getTypeName($type), + E_USER_WARNING + ); + return; + } + if (is_string($value) && is_object($def)) { + // resolve value alias if defined + if (isset($def->aliases[$value])) { + $value = $def->aliases[$value]; + } + // check to see if the value is allowed + if (isset($def->allowed) && !isset($def->allowed[$value])) { + $this->triggerError( + 'Value not supported, valid values are: ' . + $this->_listify($def->allowed), + E_USER_WARNING + ); + return; + } + } + $this->plist->set($key, $value); + + // reset definitions if the directives they depend on changed + // this is a very costly process, so it's discouraged + // with finalization + if ($namespace == 'HTML' || $namespace == 'CSS' || $namespace == 'URI') { + $this->definitions[$namespace] = null; + } + + $this->serials[$namespace] = false; + } + + /** + * Convenience function for error reporting + * + * @param array $lookup + * + * @return string + */ + private function _listify($lookup) + { + $list = array(); + foreach ($lookup as $name => $b) { + $list[] = $name; + } + return implode(', ', $list); + } + + /** + * Retrieves object reference to the HTML definition. + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawHTMLDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_HTMLDefinition|null + */ + public function getHTMLDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('HTML', $raw, $optimized); + } + + /** + * Retrieves object reference to the CSS definition + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawCSSDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_CSSDefinition|null + */ + public function getCSSDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('CSS', $raw, $optimized); + } + + /** + * Retrieves object reference to the URI definition + * + * @param bool $raw Return a copy that has not been setup yet. Must be + * called before it's been setup, otherwise won't work. + * @param bool $optimized If true, this method may return null, to + * indicate that a cached version of the modified + * definition object is available and no further edits + * are necessary. Consider using + * maybeGetRawURIDefinition, which is more explicitly + * named, instead. + * + * @return HTMLPurifier_URIDefinition|null + */ + public function getURIDefinition($raw = false, $optimized = false) + { + return $this->getDefinition('URI', $raw, $optimized); + } + + /** + * Retrieves a definition + * + * @param string $type Type of definition: HTML, CSS, etc + * @param bool $raw Whether or not definition should be returned raw + * @param bool $optimized Only has an effect when $raw is true. Whether + * or not to return null if the result is already present in + * the cache. This is off by default for backwards + * compatibility reasons, but you need to do things this + * way in order to ensure that caching is done properly. + * Check out enduser-customize.html for more details. + * We probably won't ever change this default, as much as the + * maybe semantics is the "right thing to do." + * + * @throws HTMLPurifier_Exception + * @return HTMLPurifier_Definition|null + */ + public function getDefinition($type, $raw = false, $optimized = false) + { + if ($optimized && !$raw) { + throw new HTMLPurifier_Exception("Cannot set optimized = true when raw = false"); + } + if (!$this->finalized) { + $this->autoFinalize(); + } + // temporarily suspend locks, so we can handle recursive definition calls + $lock = $this->lock; + $this->lock = null; + $factory = HTMLPurifier_DefinitionCacheFactory::instance(); + $cache = $factory->create($type, $this); + $this->lock = $lock; + if (!$raw) { + // full definition + // --------------- + // check if definition is in memory + if (!empty($this->definitions[$type])) { + $def = $this->definitions[$type]; + // check if the definition is setup + if ($def->setup) { + return $def; + } else { + $def->setup($this); + if ($def->optimized) { + $cache->add($def, $this); + } + return $def; + } + } + // check if definition is in cache + $def = $cache->get($this); + if ($def) { + // definition in cache, save to memory and return it + $this->definitions[$type] = $def; + return $def; + } + // initialize it + $def = $this->initDefinition($type); + // set it up + $this->lock = $type; + $def->setup($this); + $this->lock = null; + // save in cache + $cache->add($def, $this); + // return it + return $def; + } else { + // raw definition + // -------------- + // check preconditions + $def = null; + if ($optimized) { + if (is_null($this->get($type . '.DefinitionID'))) { + // fatally error out if definition ID not set + throw new HTMLPurifier_Exception( + "Cannot retrieve raw version without specifying %$type.DefinitionID" + ); + } + } + if (!empty($this->definitions[$type])) { + $def = $this->definitions[$type]; + if ($def->setup && !$optimized) { + $extra = $this->chatty ? + " (try moving this code block earlier in your initialization)" : + ""; + throw new HTMLPurifier_Exception( + "Cannot retrieve raw definition after it has already been setup" . + $extra + ); + } + if ($def->optimized === null) { + $extra = $this->chatty ? " (try flushing your cache)" : ""; + throw new HTMLPurifier_Exception( + "Optimization status of definition is unknown" . $extra + ); + } + if ($def->optimized !== $optimized) { + $msg = $optimized ? "optimized" : "unoptimized"; + $extra = $this->chatty ? + " (this backtrace is for the first inconsistent call, which was for a $msg raw definition)" + : ""; + throw new HTMLPurifier_Exception( + "Inconsistent use of optimized and unoptimized raw definition retrievals" . $extra + ); + } + } + // check if definition was in memory + if ($def) { + if ($def->setup) { + // invariant: $optimized === true (checked above) + return null; + } else { + return $def; + } + } + // if optimized, check if definition was in cache + // (because we do the memory check first, this formulation + // is prone to cache slamming, but I think + // guaranteeing that either /all/ of the raw + // setup code or /none/ of it is run is more important.) + if ($optimized) { + // This code path only gets run once; once we put + // something in $definitions (which is guaranteed by the + // trailing code), we always short-circuit above. + $def = $cache->get($this); + if ($def) { + // save the full definition for later, but don't + // return it yet + $this->definitions[$type] = $def; + return null; + } + } + // check invariants for creation + if (!$optimized) { + if (!is_null($this->get($type . '.DefinitionID'))) { + if ($this->chatty) { + $this->triggerError( + 'Due to a documentation error in previous version of HTML Purifier, your ' . + 'definitions are not being cached. If this is OK, you can remove the ' . + '%$type.DefinitionRev and %$type.DefinitionID declaration. Otherwise, ' . + 'modify your code to use maybeGetRawDefinition, and test if the returned ' . + 'value is null before making any edits (if it is null, that means that a ' . + 'cached version is available, and no raw operations are necessary). See ' . + '' . + 'Customize for more details', + E_USER_WARNING + ); + } else { + $this->triggerError( + "Useless DefinitionID declaration", + E_USER_WARNING + ); + } + } + } + // initialize it + $def = $this->initDefinition($type); + $def->optimized = $optimized; + return $def; + } + throw new HTMLPurifier_Exception("The impossible happened!"); + } + + /** + * Initialise definition + * + * @param string $type What type of definition to create + * + * @return HTMLPurifier_CSSDefinition|HTMLPurifier_HTMLDefinition|HTMLPurifier_URIDefinition + * @throws HTMLPurifier_Exception + */ + private function initDefinition($type) + { + // quick checks failed, let's create the object + if ($type == 'HTML') { + $def = new HTMLPurifier_HTMLDefinition(); + } elseif ($type == 'CSS') { + $def = new HTMLPurifier_CSSDefinition(); + } elseif ($type == 'URI') { + $def = new HTMLPurifier_URIDefinition(); + } else { + throw new HTMLPurifier_Exception( + "Definition of $type type not supported" + ); + } + $this->definitions[$type] = $def; + return $def; + } + + public function maybeGetRawDefinition($name) + { + return $this->getDefinition($name, true, true); + } + + /** + * @return HTMLPurifier_HTMLDefinition|null + */ + public function maybeGetRawHTMLDefinition() + { + return $this->getDefinition('HTML', true, true); + } + + /** + * @return HTMLPurifier_CSSDefinition|null + */ + public function maybeGetRawCSSDefinition() + { + return $this->getDefinition('CSS', true, true); + } + + /** + * @return HTMLPurifier_URIDefinition|null + */ + public function maybeGetRawURIDefinition() + { + return $this->getDefinition('URI', true, true); + } + + /** + * Loads configuration values from an array with the following structure: + * Namespace.Directive => Value + * + * @param array $config_array Configuration associative array + */ + public function loadArray($config_array) + { + if ($this->isFinalized('Cannot load directives after finalization')) { + return; + } + foreach ($config_array as $key => $value) { + $key = str_replace('_', '.', $key); + if (strpos($key, '.') !== false) { + $this->set($key, $value); + } else { + $namespace = $key; + $namespace_values = $value; + foreach ($namespace_values as $directive => $value2) { + $this->set($namespace .'.'. $directive, $value2); + } + } + } + } + + /** + * Returns a list of array(namespace, directive) for all directives + * that are allowed in a web-form context as per an allowed + * namespaces/directives list. + * + * @param array $allowed List of allowed namespaces/directives + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return array + */ + public static function getAllowedDirectivesForForm($allowed, $schema = null) + { + if (!$schema) { + $schema = HTMLPurifier_ConfigSchema::instance(); + } + if ($allowed !== true) { + if (is_string($allowed)) { + $allowed = array($allowed); + } + $allowed_ns = array(); + $allowed_directives = array(); + $blacklisted_directives = array(); + foreach ($allowed as $ns_or_directive) { + if (strpos($ns_or_directive, '.') !== false) { + // directive + if ($ns_or_directive[0] == '-') { + $blacklisted_directives[substr($ns_or_directive, 1)] = true; + } else { + $allowed_directives[$ns_or_directive] = true; + } + } else { + // namespace + $allowed_ns[$ns_or_directive] = true; + } + } + } + $ret = array(); + foreach ($schema->info as $key => $def) { + list($ns, $directive) = explode('.', $key, 2); + if ($allowed !== true) { + if (isset($blacklisted_directives["$ns.$directive"])) { + continue; + } + if (!isset($allowed_directives["$ns.$directive"]) && !isset($allowed_ns[$ns])) { + continue; + } + } + if (isset($def->isAlias)) { + continue; + } + if ($directive == 'DefinitionID' || $directive == 'DefinitionRev') { + continue; + } + $ret[] = array($ns, $directive); + } + return $ret; + } + + /** + * Loads configuration values from $_GET/$_POST that were posted + * via ConfigForm + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return mixed + */ + public static function loadArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) + { + $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $schema); + $config = HTMLPurifier_Config::create($ret, $schema); + return $config; + } + + /** + * Merges in configuration values from $_GET/$_POST to object. NOT STATIC. + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + */ + public function mergeArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true) + { + $ret = HTMLPurifier_Config::prepareArrayFromForm($array, $index, $allowed, $mq_fix, $this->def); + $this->loadArray($ret); + } + + /** + * Prepares an array from a form into something usable for the more + * strict parts of HTMLPurifier_Config + * + * @param array $array $_GET or $_POST array to import + * @param string|bool $index Index/name that the config variables are in + * @param array|bool $allowed List of allowed namespaces/directives + * @param bool $mq_fix Boolean whether or not to enable magic quotes fix + * @param HTMLPurifier_ConfigSchema $schema Schema to use, if not global copy + * + * @return array + */ + public static function prepareArrayFromForm($array, $index = false, $allowed = true, $mq_fix = true, $schema = null) + { + if ($index !== false) { + $array = (isset($array[$index]) && is_array($array[$index])) ? $array[$index] : array(); + } + $mq = $mq_fix && version_compare(PHP_VERSION, '7.4.0', '<') && function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc(); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $schema); + $ret = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $skey = "$ns.$directive"; + if (!empty($array["Null_$skey"])) { + $ret[$ns][$directive] = null; + continue; + } + if (!isset($array[$skey])) { + continue; + } + $value = $mq ? stripslashes($array[$skey]) : $array[$skey]; + $ret[$ns][$directive] = $value; + } + return $ret; + } + + /** + * Loads configuration values from an ini file + * + * @param string $filename Name of ini file + */ + public function loadIni($filename) + { + if ($this->isFinalized('Cannot load directives after finalization')) { + return; + } + $array = parse_ini_file($filename, true); + $this->loadArray($array); + } + + /** + * Checks whether or not the configuration object is finalized. + * + * @param string|bool $error String error message, or false for no error + * + * @return bool + */ + public function isFinalized($error = false) + { + if ($this->finalized && $error) { + $this->triggerError($error, E_USER_ERROR); + } + return $this->finalized; + } + + /** + * Finalizes configuration only if auto finalize is on and not + * already finalized + */ + public function autoFinalize() + { + if ($this->autoFinalize) { + $this->finalize(); + } else { + $this->plist->squash(true); + } + } + + /** + * Finalizes a configuration object, prohibiting further change + */ + public function finalize() + { + $this->finalized = true; + $this->parser = null; + } + + /** + * Produces a nicely formatted error message by supplying the + * stack frame information OUTSIDE of HTMLPurifier_Config. + * + * @param string $msg An error message + * @param int $no An error number + */ + protected function triggerError($msg, $no) + { + // determine previous stack frame + $extra = ''; + if ($this->chatty) { + $trace = debug_backtrace(); + // zip(tail(trace), trace) -- but PHP is not Haskell har har + for ($i = 0, $c = count($trace); $i < $c - 1; $i++) { + // XXX this is not correct on some versions of HTML Purifier + if (isset($trace[$i + 1]['class']) && $trace[$i + 1]['class'] === 'HTMLPurifier_Config') { + continue; + } + $frame = $trace[$i]; + $extra = " invoked on line {$frame['line']} in file {$frame['file']}"; + break; + } + } + trigger_error($msg . $extra, $no); + } + + /** + * Returns a serialized form of the configuration object that can + * be reconstituted. + * + * @return string + */ + public function serialize() + { + $this->getDefinition('HTML'); + $this->getDefinition('CSS'); + $this->getDefinition('URI'); + return serialize($this); + } + +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php new file mode 100644 index 0000000..c3fe8cd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php @@ -0,0 +1,176 @@ + array( + * 'Directive' => new stdClass(), + * ) + * ) + * + * The stdClass may have the following properties: + * + * - If isAlias isn't set: + * - type: Integer type of directive, see HTMLPurifier_VarParser for definitions + * - allow_null: If set, this directive allows null values + * - aliases: If set, an associative array of value aliases to real values + * - allowed: If set, a lookup array of allowed (string) values + * - If isAlias is set: + * - namespace: Namespace this directive aliases to + * - name: Directive name this directive aliases to + * + * In certain degenerate cases, stdClass will actually be an integer. In + * that case, the value is equivalent to an stdClass with the type + * property set to the integer. If the integer is negative, type is + * equal to the absolute value of integer, and allow_null is true. + * + * This class is friendly with HTMLPurifier_Config. If you need introspection + * about the schema, you're better of using the ConfigSchema_Interchange, + * which uses more memory but has much richer information. + * @type array + */ + public $info = array(); + + /** + * Application-wide singleton + * @type HTMLPurifier_ConfigSchema + */ + protected static $singleton; + + public function __construct() + { + $this->defaultPlist = new HTMLPurifier_PropertyList(); + } + + /** + * Unserializes the default ConfigSchema. + * @return HTMLPurifier_ConfigSchema + */ + public static function makeFromSerial() + { + $contents = file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema.ser'); + $r = unserialize($contents); + if (!$r) { + $hash = sha1($contents); + trigger_error("Unserialization of configuration schema failed, sha1 of file was $hash", E_USER_ERROR); + } + return $r; + } + + /** + * Retrieves an instance of the application-wide configuration definition. + * @param HTMLPurifier_ConfigSchema $prototype + * @return HTMLPurifier_ConfigSchema + */ + public static function instance($prototype = null) + { + if ($prototype !== null) { + HTMLPurifier_ConfigSchema::$singleton = $prototype; + } elseif (HTMLPurifier_ConfigSchema::$singleton === null || $prototype === true) { + HTMLPurifier_ConfigSchema::$singleton = HTMLPurifier_ConfigSchema::makeFromSerial(); + } + return HTMLPurifier_ConfigSchema::$singleton; + } + + /** + * Defines a directive for configuration + * @warning Will fail of directive's namespace is defined. + * @warning This method's signature is slightly different from the legacy + * define() static method! Beware! + * @param string $key Name of directive + * @param mixed $default Default value of directive + * @param string $type Allowed type of the directive. See + * HTMLPurifier_VarParser::$types for allowed values + * @param bool $allow_null Whether or not to allow null values + */ + public function add($key, $default, $type, $allow_null) + { + $obj = new stdClass(); + $obj->type = is_int($type) ? $type : HTMLPurifier_VarParser::$types[$type]; + if ($allow_null) { + $obj->allow_null = true; + } + $this->info[$key] = $obj; + $this->defaults[$key] = $default; + $this->defaultPlist->set($key, $default); + } + + /** + * Defines a directive value alias. + * + * Directive value aliases are convenient for developers because it lets + * them set a directive to several values and get the same result. + * @param string $key Name of Directive + * @param array $aliases Hash of aliased values to the real alias + */ + public function addValueAliases($key, $aliases) + { + if (!isset($this->info[$key]->aliases)) { + $this->info[$key]->aliases = array(); + } + foreach ($aliases as $alias => $real) { + $this->info[$key]->aliases[$alias] = $real; + } + } + + /** + * Defines a set of allowed values for a directive. + * @warning This is slightly different from the corresponding static + * method definition. + * @param string $key Name of directive + * @param array $allowed Lookup array of allowed values + */ + public function addAllowedValues($key, $allowed) + { + $this->info[$key]->allowed = $allowed; + } + + /** + * Defines a directive alias for backwards compatibility + * @param string $key Directive that will be aliased + * @param string $new_key Directive that the alias will be to + */ + public function addAlias($key, $new_key) + { + $obj = new stdClass; + $obj->key = $new_key; + $obj->isAlias = true; + $this->info[$key] = $obj; + } + + /** + * Replaces any stdClass that only has the type property with type integer. + */ + public function postProcess() + { + foreach ($this->info as $key => $v) { + if (count((array) $v) == 1) { + $this->info[$key] = $v->type; + } elseif (count((array) $v) == 2 && isset($v->allow_null)) { + $this->info[$key] = -$v->type; + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php new file mode 100644 index 0000000..d5906cd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php @@ -0,0 +1,48 @@ +directives as $d) { + $schema->add( + $d->id->key, + $d->default, + $d->type, + $d->typeAllowsNull + ); + if ($d->allowed !== null) { + $schema->addAllowedValues( + $d->id->key, + $d->allowed + ); + } + foreach ($d->aliases as $alias) { + $schema->addAlias( + $alias->key, + $d->id->key + ); + } + if ($d->valueAliases !== null) { + $schema->addValueAliases( + $d->id->key, + $d->valueAliases + ); + } + } + $schema->postProcess(); + return $schema; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php new file mode 100644 index 0000000..5fa56f7 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php @@ -0,0 +1,144 @@ +startElement('div'); + + $purifier = HTMLPurifier::getInstance(); + $html = $purifier->purify($html); + $this->writeAttribute('xmlns', 'http://www.w3.org/1999/xhtml'); + $this->writeRaw($html); + + $this->endElement(); // div + } + + /** + * @param mixed $var + * @return string + */ + protected function export($var) + { + if ($var === array()) { + return 'array()'; + } + return var_export($var, true); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + */ + public function build($interchange) + { + // global access, only use as last resort + $this->interchange = $interchange; + + $this->setIndent(true); + $this->startDocument('1.0', 'UTF-8'); + $this->startElement('configdoc'); + $this->writeElement('title', $interchange->name); + + foreach ($interchange->directives as $directive) { + $this->buildDirective($directive); + } + + if ($this->namespace) { + $this->endElement(); + } // namespace + + $this->endElement(); // configdoc + $this->flush(); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive + */ + public function buildDirective($directive) + { + // Kludge, although I suppose having a notion of a "root namespace" + // certainly makes things look nicer when documentation is built. + // Depends on things being sorted. + if (!$this->namespace || $this->namespace !== $directive->id->getRootNamespace()) { + if ($this->namespace) { + $this->endElement(); + } // namespace + $this->namespace = $directive->id->getRootNamespace(); + $this->startElement('namespace'); + $this->writeAttribute('id', $this->namespace); + $this->writeElement('name', $this->namespace); + } + + $this->startElement('directive'); + $this->writeAttribute('id', $directive->id->toString()); + + $this->writeElement('name', $directive->id->getDirective()); + + $this->startElement('aliases'); + foreach ($directive->aliases as $alias) { + $this->writeElement('alias', $alias->toString()); + } + $this->endElement(); // aliases + + $this->startElement('constraints'); + if ($directive->version) { + $this->writeElement('version', $directive->version); + } + $this->startElement('type'); + if ($directive->typeAllowsNull) { + $this->writeAttribute('allow-null', 'yes'); + } + $this->text($directive->type); + $this->endElement(); // type + if ($directive->allowed) { + $this->startElement('allowed'); + foreach ($directive->allowed as $value => $x) { + $this->writeElement('value', $value); + } + $this->endElement(); // allowed + } + $this->writeElement('default', $this->export($directive->default)); + $this->writeAttribute('xml:space', 'preserve'); + if ($directive->external) { + $this->startElement('external'); + foreach ($directive->external as $project) { + $this->writeElement('project', $project); + } + $this->endElement(); + } + $this->endElement(); // constraints + + if ($directive->deprecatedVersion) { + $this->startElement('deprecated'); + $this->writeElement('version', $directive->deprecatedVersion); + $this->writeElement('use', $directive->deprecatedUse->toString()); + $this->endElement(); // deprecated + } + + $this->startElement('description'); + $this->writeHTMLDiv($directive->description); + $this->endElement(); // description + + $this->endElement(); // directive + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php new file mode 100644 index 0000000..2671516 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php @@ -0,0 +1,11 @@ + array(directive info) + * @type HTMLPurifier_ConfigSchema_Interchange_Directive[] + */ + public $directives = array(); + + /** + * Adds a directive array to $directives + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $directive + * @throws HTMLPurifier_ConfigSchema_Exception + */ + public function addDirective($directive) + { + if (isset($this->directives[$i = $directive->id->toString()])) { + throw new HTMLPurifier_ConfigSchema_Exception("Cannot redefine directive '$i'"); + } + $this->directives[$i] = $directive; + } + + /** + * Convenience function to perform standard validation. Throws exception + * on failed validation. + */ + public function validate() + { + $validator = new HTMLPurifier_ConfigSchema_Validator(); + return $validator->validate($this); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php new file mode 100644 index 0000000..127a39a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php @@ -0,0 +1,89 @@ + true). + * Null if all values are allowed. + * @type array + */ + public $allowed; + + /** + * List of aliases for the directive. + * e.g. array(new HTMLPurifier_ConfigSchema_Interchange_Id('Ns', 'Dir'))). + * @type HTMLPurifier_ConfigSchema_Interchange_Id[] + */ + public $aliases = array(); + + /** + * Hash of value aliases, e.g. array('alt' => 'real'). Null if value + * aliasing is disabled (necessary for non-scalar types). + * @type array + */ + public $valueAliases; + + /** + * Version of HTML Purifier the directive was introduced, e.g. '1.3.1'. + * Null if the directive has always existed. + * @type string + */ + public $version; + + /** + * ID of directive that supercedes this old directive. + * Null if not deprecated. + * @type HTMLPurifier_ConfigSchema_Interchange_Id + */ + public $deprecatedUse; + + /** + * Version of HTML Purifier this directive was deprecated. Null if not + * deprecated. + * @type string + */ + public $deprecatedVersion; + + /** + * List of external projects this directive depends on, e.g. array('CSSTidy'). + * @type array + */ + public $external = array(); +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php new file mode 100644 index 0000000..126f09d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php @@ -0,0 +1,58 @@ +key = $key; + } + + /** + * @return string + * @warning This is NOT magic, to ensure that people don't abuse SPL and + * cause problems for PHP 5.0 support. + */ + public function toString() + { + return $this->key; + } + + /** + * @return string + */ + public function getRootNamespace() + { + return substr($this->key, 0, strpos($this->key, ".")); + } + + /** + * @return string + */ + public function getDirective() + { + return substr($this->key, strpos($this->key, ".") + 1); + } + + /** + * @param string $id + * @return HTMLPurifier_ConfigSchema_Interchange_Id + */ + public static function make($id) + { + return new HTMLPurifier_ConfigSchema_Interchange_Id($id); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php new file mode 100644 index 0000000..655e6dd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php @@ -0,0 +1,226 @@ +varParser = $varParser ? $varParser : new HTMLPurifier_VarParser_Native(); + } + + /** + * @param string $dir + * @return HTMLPurifier_ConfigSchema_Interchange + */ + public static function buildFromDirectory($dir = null) + { + $builder = new HTMLPurifier_ConfigSchema_InterchangeBuilder(); + $interchange = new HTMLPurifier_ConfigSchema_Interchange(); + return $builder->buildDir($interchange, $dir); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @param string $dir + * @return HTMLPurifier_ConfigSchema_Interchange + */ + public function buildDir($interchange, $dir = null) + { + if (!$dir) { + $dir = HTMLPURIFIER_PREFIX . '/HTMLPurifier/ConfigSchema/schema'; + } + if (file_exists($dir . '/info.ini')) { + $info = parse_ini_file($dir . '/info.ini'); + $interchange->name = $info['name']; + } + + $files = array(); + $dh = opendir($dir); + while (false !== ($file = readdir($dh))) { + if (!$file || $file[0] == '.' || strrchr($file, '.') !== '.txt') { + continue; + } + $files[] = $file; + } + closedir($dh); + + sort($files); + foreach ($files as $file) { + $this->buildFile($interchange, $dir . '/' . $file); + } + return $interchange; + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @param string $file + */ + public function buildFile($interchange, $file) + { + $parser = new HTMLPurifier_StringHashParser(); + $this->build( + $interchange, + new HTMLPurifier_StringHash($parser->parseFile($file)) + ); + } + + /** + * Builds an interchange object based on a hash. + * @param HTMLPurifier_ConfigSchema_Interchange $interchange HTMLPurifier_ConfigSchema_Interchange object to build + * @param HTMLPurifier_StringHash $hash source data + * @throws HTMLPurifier_ConfigSchema_Exception + */ + public function build($interchange, $hash) + { + if (!$hash instanceof HTMLPurifier_StringHash) { + $hash = new HTMLPurifier_StringHash($hash); + } + if (!isset($hash['ID'])) { + throw new HTMLPurifier_ConfigSchema_Exception('Hash does not have any ID'); + } + if (strpos($hash['ID'], '.') === false) { + if (count($hash) == 2 && isset($hash['DESCRIPTION'])) { + $hash->offsetGet('DESCRIPTION'); // prevent complaining + } else { + throw new HTMLPurifier_ConfigSchema_Exception('All directives must have a namespace'); + } + } else { + $this->buildDirective($interchange, $hash); + } + $this->_findUnused($hash); + } + + /** + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @param HTMLPurifier_StringHash $hash + * @throws HTMLPurifier_ConfigSchema_Exception + */ + public function buildDirective($interchange, $hash) + { + $directive = new HTMLPurifier_ConfigSchema_Interchange_Directive(); + + // These are required elements: + $directive->id = $this->id($hash->offsetGet('ID')); + $id = $directive->id->toString(); // convenience + + if (isset($hash['TYPE'])) { + $type = explode('/', $hash->offsetGet('TYPE')); + if (isset($type[1])) { + $directive->typeAllowsNull = true; + } + $directive->type = $type[0]; + } else { + throw new HTMLPurifier_ConfigSchema_Exception("TYPE in directive hash '$id' not defined"); + } + + if (isset($hash['DEFAULT'])) { + try { + $directive->default = $this->varParser->parse( + $hash->offsetGet('DEFAULT'), + $directive->type, + $directive->typeAllowsNull + ); + } catch (HTMLPurifier_VarParserException $e) { + throw new HTMLPurifier_ConfigSchema_Exception($e->getMessage() . " in DEFAULT in directive hash '$id'"); + } + } + + if (isset($hash['DESCRIPTION'])) { + $directive->description = $hash->offsetGet('DESCRIPTION'); + } + + if (isset($hash['ALLOWED'])) { + $directive->allowed = $this->lookup($this->evalArray($hash->offsetGet('ALLOWED'))); + } + + if (isset($hash['VALUE-ALIASES'])) { + $directive->valueAliases = $this->evalArray($hash->offsetGet('VALUE-ALIASES')); + } + + if (isset($hash['ALIASES'])) { + $raw_aliases = trim($hash->offsetGet('ALIASES')); + $aliases = preg_split('/\s*,\s*/', $raw_aliases); + foreach ($aliases as $alias) { + $directive->aliases[] = $this->id($alias); + } + } + + if (isset($hash['VERSION'])) { + $directive->version = $hash->offsetGet('VERSION'); + } + + if (isset($hash['DEPRECATED-USE'])) { + $directive->deprecatedUse = $this->id($hash->offsetGet('DEPRECATED-USE')); + } + + if (isset($hash['DEPRECATED-VERSION'])) { + $directive->deprecatedVersion = $hash->offsetGet('DEPRECATED-VERSION'); + } + + if (isset($hash['EXTERNAL'])) { + $directive->external = preg_split('/\s*,\s*/', trim($hash->offsetGet('EXTERNAL'))); + } + + $interchange->addDirective($directive); + } + + /** + * Evaluates an array PHP code string without array() wrapper + * @param string $contents + */ + protected function evalArray($contents) + { + return eval('return array(' . $contents . ');'); + } + + /** + * Converts an array list into a lookup array. + * @param array $array + * @return array + */ + protected function lookup($array) + { + $ret = array(); + foreach ($array as $val) { + $ret[$val] = true; + } + return $ret; + } + + /** + * Convenience function that creates an HTMLPurifier_ConfigSchema_Interchange_Id + * object based on a string Id. + * @param string $id + * @return HTMLPurifier_ConfigSchema_Interchange_Id + */ + protected function id($id) + { + return HTMLPurifier_ConfigSchema_Interchange_Id::make($id); + } + + /** + * Triggers errors for any unused keys passed in the hash; such keys + * may indicate typos, missing values, etc. + * @param HTMLPurifier_StringHash $hash Hash to check. + */ + protected function _findUnused($hash) + { + $accessed = $hash->getAccessed(); + foreach ($hash as $k => $v) { + if (!isset($accessed[$k])) { + trigger_error("String hash key '$k' not used by builder", E_USER_NOTICE); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php new file mode 100644 index 0000000..fb31277 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php @@ -0,0 +1,248 @@ +parser = new HTMLPurifier_VarParser(); + } + + /** + * Validates a fully-formed interchange object. + * @param HTMLPurifier_ConfigSchema_Interchange $interchange + * @return bool + */ + public function validate($interchange) + { + $this->interchange = $interchange; + $this->aliases = array(); + // PHP is a bit lax with integer <=> string conversions in + // arrays, so we don't use the identical !== comparison + foreach ($interchange->directives as $i => $directive) { + $id = $directive->id->toString(); + if ($i != $id) { + $this->error(false, "Integrity violation: key '$i' does not match internal id '$id'"); + } + $this->validateDirective($directive); + } + return true; + } + + /** + * Validates a HTMLPurifier_ConfigSchema_Interchange_Id object. + * @param HTMLPurifier_ConfigSchema_Interchange_Id $id + */ + public function validateId($id) + { + $id_string = $id->toString(); + $this->context[] = "id '$id_string'"; + if (!$id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) { + // handled by InterchangeBuilder + $this->error(false, 'is not an instance of HTMLPurifier_ConfigSchema_Interchange_Id'); + } + // keys are now unconstrained (we might want to narrow down to A-Za-z0-9.) + // we probably should check that it has at least one namespace + $this->with($id, 'key') + ->assertNotEmpty() + ->assertIsString(); // implicit assertIsString handled by InterchangeBuilder + array_pop($this->context); + } + + /** + * Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirective($d) + { + $id = $d->id->toString(); + $this->context[] = "directive '$id'"; + $this->validateId($d->id); + + $this->with($d, 'description') + ->assertNotEmpty(); + + // BEGIN - handled by InterchangeBuilder + $this->with($d, 'type') + ->assertNotEmpty(); + $this->with($d, 'typeAllowsNull') + ->assertIsBool(); + try { + // This also tests validity of $d->type + $this->parser->parse($d->default, $d->type, $d->typeAllowsNull); + } catch (HTMLPurifier_VarParserException $e) { + $this->error('default', 'had error: ' . $e->getMessage()); + } + // END - handled by InterchangeBuilder + + if (!is_null($d->allowed) || !empty($d->valueAliases)) { + // allowed and valueAliases require that we be dealing with + // strings, so check for that early. + $d_int = HTMLPurifier_VarParser::$types[$d->type]; + if (!isset(HTMLPurifier_VarParser::$stringTypes[$d_int])) { + $this->error('type', 'must be a string type when used with allowed or value aliases'); + } + } + + $this->validateDirectiveAllowed($d); + $this->validateDirectiveValueAliases($d); + $this->validateDirectiveAliases($d); + + array_pop($this->context); + } + + /** + * Extra validation if $allowed member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirectiveAllowed($d) + { + if (is_null($d->allowed)) { + return; + } + $this->with($d, 'allowed') + ->assertNotEmpty() + ->assertIsLookup(); // handled by InterchangeBuilder + if (is_string($d->default) && !isset($d->allowed[$d->default])) { + $this->error('default', 'must be an allowed value'); + } + $this->context[] = 'allowed'; + foreach ($d->allowed as $val => $x) { + if (!is_string($val)) { + $this->error("value $val", 'must be a string'); + } + } + array_pop($this->context); + } + + /** + * Extra validation if $valueAliases member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirectiveValueAliases($d) + { + if (is_null($d->valueAliases)) { + return; + } + $this->with($d, 'valueAliases') + ->assertIsArray(); // handled by InterchangeBuilder + $this->context[] = 'valueAliases'; + foreach ($d->valueAliases as $alias => $real) { + if (!is_string($alias)) { + $this->error("alias $alias", 'must be a string'); + } + if (!is_string($real)) { + $this->error("alias target $real from alias '$alias'", 'must be a string'); + } + if ($alias === $real) { + $this->error("alias '$alias'", "must not be an alias to itself"); + } + } + if (!is_null($d->allowed)) { + foreach ($d->valueAliases as $alias => $real) { + if (isset($d->allowed[$alias])) { + $this->error("alias '$alias'", 'must not be an allowed value'); + } elseif (!isset($d->allowed[$real])) { + $this->error("alias '$alias'", 'must be an alias to an allowed value'); + } + } + } + array_pop($this->context); + } + + /** + * Extra validation if $aliases member variable of + * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. + * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d + */ + public function validateDirectiveAliases($d) + { + $this->with($d, 'aliases') + ->assertIsArray(); // handled by InterchangeBuilder + $this->context[] = 'aliases'; + foreach ($d->aliases as $alias) { + $this->validateId($alias); + $s = $alias->toString(); + if (isset($this->interchange->directives[$s])) { + $this->error("alias '$s'", 'collides with another directive'); + } + if (isset($this->aliases[$s])) { + $other_directive = $this->aliases[$s]; + $this->error("alias '$s'", "collides with alias for directive '$other_directive'"); + } + $this->aliases[$s] = $d->id->toString(); + } + array_pop($this->context); + } + + // protected helper functions + + /** + * Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom + * for validating simple member variables of objects. + * @param $obj + * @param $member + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + protected function with($obj, $member) + { + return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->getFormattedContext(), $obj, $member); + } + + /** + * Emits an error, providing helpful context. + * @throws HTMLPurifier_ConfigSchema_Exception + */ + protected function error($target, $msg) + { + if ($target !== false) { + $prefix = ucfirst($target) . ' in ' . $this->getFormattedContext(); + } else { + $prefix = ucfirst($this->getFormattedContext()); + } + throw new HTMLPurifier_ConfigSchema_Exception(trim($prefix . ' ' . $msg)); + } + + /** + * Returns a formatted context string. + * @return string + */ + protected function getFormattedContext() + { + return implode(' in ', array_reverse($this->context)); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php new file mode 100644 index 0000000..c9aa364 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php @@ -0,0 +1,130 @@ +context = $context; + $this->obj = $obj; + $this->member = $member; + $this->contents =& $obj->$member; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsString() + { + if (!is_string($this->contents)) { + $this->error('must be a string'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsBool() + { + if (!is_bool($this->contents)) { + $this->error('must be a boolean'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsArray() + { + if (!is_array($this->contents)) { + $this->error('must be an array'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertNotNull() + { + if ($this->contents === null) { + $this->error('must not be null'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertAlnum() + { + $this->assertIsString(); + if (!ctype_alnum($this->contents)) { + $this->error('must be alphanumeric'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertNotEmpty() + { + if (empty($this->contents)) { + $this->error('must not be empty'); + } + return $this; + } + + /** + * @return HTMLPurifier_ConfigSchema_ValidatorAtom + */ + public function assertIsLookup() + { + $this->assertIsArray(); + foreach ($this->contents as $v) { + if ($v !== true) { + $this->error('must be a lookup array'); + } + } + return $this; + } + + /** + * @param string $msg + * @throws HTMLPurifier_ConfigSchema_Exception + */ + protected function error($msg) + { + throw new HTMLPurifier_ConfigSchema_Exception(ucfirst($this->member) . ' in ' . $this->context . ' ' . $msg); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser new file mode 100644 index 0000000..a5426c7 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser @@ -0,0 +1 @@ +O:25:"HTMLPurifier_ConfigSchema":3:{s:8:"defaults";a:127:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:12:"defaultPlist";O:25:"HTMLPurifier_PropertyList":3:{s:7:"*data";a:127:{s:19:"Attr.AllowedClasses";N;s:24:"Attr.AllowedFrameTargets";a:0:{}s:15:"Attr.AllowedRel";a:0:{}s:15:"Attr.AllowedRev";a:0:{}s:18:"Attr.ClassUseCDATA";N;s:20:"Attr.DefaultImageAlt";N;s:24:"Attr.DefaultInvalidImage";s:0:"";s:27:"Attr.DefaultInvalidImageAlt";s:13:"Invalid image";s:19:"Attr.DefaultTextDir";s:3:"ltr";s:13:"Attr.EnableID";b:0;s:21:"Attr.ForbiddenClasses";a:0:{}s:13:"Attr.ID.HTML5";N;s:16:"Attr.IDBlacklist";a:0:{}s:22:"Attr.IDBlacklistRegexp";N;s:13:"Attr.IDPrefix";s:0:"";s:18:"Attr.IDPrefixLocal";s:0:"";s:24:"AutoFormat.AutoParagraph";b:0;s:17:"AutoFormat.Custom";a:0:{}s:25:"AutoFormat.DisplayLinkURI";b:0;s:18:"AutoFormat.Linkify";b:0;s:33:"AutoFormat.PurifierLinkify.DocURL";s:3:"#%s";s:26:"AutoFormat.PurifierLinkify";b:0;s:32:"AutoFormat.RemoveEmpty.Predicate";a:4:{s:8:"colgroup";a:0:{}s:2:"th";a:0:{}s:2:"td";a:0:{}s:6:"iframe";a:1:{i:0;s:3:"src";}}s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";a:2:{s:2:"td";b:1;s:2:"th";b:1;}s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";b:0;s:22:"AutoFormat.RemoveEmpty";b:0;s:39:"AutoFormat.RemoveSpansWithoutAttributes";b:0;s:19:"CSS.AllowDuplicates";b:0;s:18:"CSS.AllowImportant";b:0;s:15:"CSS.AllowTricky";b:0;s:16:"CSS.AllowedFonts";N;s:21:"CSS.AllowedProperties";N;s:17:"CSS.DefinitionRev";i:1;s:23:"CSS.ForbiddenProperties";a:0:{}s:16:"CSS.MaxImgLength";s:6:"1200px";s:15:"CSS.Proprietary";b:0;s:11:"CSS.Trusted";b:0;s:20:"Cache.DefinitionImpl";s:10:"Serializer";s:20:"Cache.SerializerPath";N;s:27:"Cache.SerializerPermissions";i:493;s:22:"Core.AggressivelyFixLt";b:1;s:29:"Core.AggressivelyRemoveScript";b:1;s:28:"Core.AllowHostnameUnderscore";b:0;s:23:"Core.AllowParseManyTags";b:0;s:18:"Core.CollectErrors";b:0;s:18:"Core.ColorKeywords";a:148:{s:9:"aliceblue";s:7:"#F0F8FF";s:12:"antiquewhite";s:7:"#FAEBD7";s:4:"aqua";s:7:"#00FFFF";s:10:"aquamarine";s:7:"#7FFFD4";s:5:"azure";s:7:"#F0FFFF";s:5:"beige";s:7:"#F5F5DC";s:6:"bisque";s:7:"#FFE4C4";s:5:"black";s:7:"#000000";s:14:"blanchedalmond";s:7:"#FFEBCD";s:4:"blue";s:7:"#0000FF";s:10:"blueviolet";s:7:"#8A2BE2";s:5:"brown";s:7:"#A52A2A";s:9:"burlywood";s:7:"#DEB887";s:9:"cadetblue";s:7:"#5F9EA0";s:10:"chartreuse";s:7:"#7FFF00";s:9:"chocolate";s:7:"#D2691E";s:5:"coral";s:7:"#FF7F50";s:14:"cornflowerblue";s:7:"#6495ED";s:8:"cornsilk";s:7:"#FFF8DC";s:7:"crimson";s:7:"#DC143C";s:4:"cyan";s:7:"#00FFFF";s:8:"darkblue";s:7:"#00008B";s:8:"darkcyan";s:7:"#008B8B";s:13:"darkgoldenrod";s:7:"#B8860B";s:8:"darkgray";s:7:"#A9A9A9";s:8:"darkgrey";s:7:"#A9A9A9";s:9:"darkgreen";s:7:"#006400";s:9:"darkkhaki";s:7:"#BDB76B";s:11:"darkmagenta";s:7:"#8B008B";s:14:"darkolivegreen";s:7:"#556B2F";s:10:"darkorange";s:7:"#FF8C00";s:10:"darkorchid";s:7:"#9932CC";s:7:"darkred";s:7:"#8B0000";s:10:"darksalmon";s:7:"#E9967A";s:12:"darkseagreen";s:7:"#8FBC8F";s:13:"darkslateblue";s:7:"#483D8B";s:13:"darkslategray";s:7:"#2F4F4F";s:13:"darkslategrey";s:7:"#2F4F4F";s:13:"darkturquoise";s:7:"#00CED1";s:10:"darkviolet";s:7:"#9400D3";s:8:"deeppink";s:7:"#FF1493";s:11:"deepskyblue";s:7:"#00BFFF";s:7:"dimgray";s:7:"#696969";s:7:"dimgrey";s:7:"#696969";s:10:"dodgerblue";s:7:"#1E90FF";s:9:"firebrick";s:7:"#B22222";s:11:"floralwhite";s:7:"#FFFAF0";s:11:"forestgreen";s:7:"#228B22";s:7:"fuchsia";s:7:"#FF00FF";s:9:"gainsboro";s:7:"#DCDCDC";s:10:"ghostwhite";s:7:"#F8F8FF";s:4:"gold";s:7:"#FFD700";s:9:"goldenrod";s:7:"#DAA520";s:4:"gray";s:7:"#808080";s:4:"grey";s:7:"#808080";s:5:"green";s:7:"#008000";s:11:"greenyellow";s:7:"#ADFF2F";s:8:"honeydew";s:7:"#F0FFF0";s:7:"hotpink";s:7:"#FF69B4";s:9:"indianred";s:7:"#CD5C5C";s:6:"indigo";s:7:"#4B0082";s:5:"ivory";s:7:"#FFFFF0";s:5:"khaki";s:7:"#F0E68C";s:8:"lavender";s:7:"#E6E6FA";s:13:"lavenderblush";s:7:"#FFF0F5";s:9:"lawngreen";s:7:"#7CFC00";s:12:"lemonchiffon";s:7:"#FFFACD";s:9:"lightblue";s:7:"#ADD8E6";s:10:"lightcoral";s:7:"#F08080";s:9:"lightcyan";s:7:"#E0FFFF";s:20:"lightgoldenrodyellow";s:7:"#FAFAD2";s:9:"lightgray";s:7:"#D3D3D3";s:9:"lightgrey";s:7:"#D3D3D3";s:10:"lightgreen";s:7:"#90EE90";s:9:"lightpink";s:7:"#FFB6C1";s:11:"lightsalmon";s:7:"#FFA07A";s:13:"lightseagreen";s:7:"#20B2AA";s:12:"lightskyblue";s:7:"#87CEFA";s:14:"lightslategray";s:7:"#778899";s:14:"lightslategrey";s:7:"#778899";s:14:"lightsteelblue";s:7:"#B0C4DE";s:11:"lightyellow";s:7:"#FFFFE0";s:4:"lime";s:7:"#00FF00";s:9:"limegreen";s:7:"#32CD32";s:5:"linen";s:7:"#FAF0E6";s:7:"magenta";s:7:"#FF00FF";s:6:"maroon";s:7:"#800000";s:16:"mediumaquamarine";s:7:"#66CDAA";s:10:"mediumblue";s:7:"#0000CD";s:12:"mediumorchid";s:7:"#BA55D3";s:12:"mediumpurple";s:7:"#9370DB";s:14:"mediumseagreen";s:7:"#3CB371";s:15:"mediumslateblue";s:7:"#7B68EE";s:17:"mediumspringgreen";s:7:"#00FA9A";s:15:"mediumturquoise";s:7:"#48D1CC";s:15:"mediumvioletred";s:7:"#C71585";s:12:"midnightblue";s:7:"#191970";s:9:"mintcream";s:7:"#F5FFFA";s:9:"mistyrose";s:7:"#FFE4E1";s:8:"moccasin";s:7:"#FFE4B5";s:11:"navajowhite";s:7:"#FFDEAD";s:4:"navy";s:7:"#000080";s:7:"oldlace";s:7:"#FDF5E6";s:5:"olive";s:7:"#808000";s:9:"olivedrab";s:7:"#6B8E23";s:6:"orange";s:7:"#FFA500";s:9:"orangered";s:7:"#FF4500";s:6:"orchid";s:7:"#DA70D6";s:13:"palegoldenrod";s:7:"#EEE8AA";s:9:"palegreen";s:7:"#98FB98";s:13:"paleturquoise";s:7:"#AFEEEE";s:13:"palevioletred";s:7:"#DB7093";s:10:"papayawhip";s:7:"#FFEFD5";s:9:"peachpuff";s:7:"#FFDAB9";s:4:"peru";s:7:"#CD853F";s:4:"pink";s:7:"#FFC0CB";s:4:"plum";s:7:"#DDA0DD";s:10:"powderblue";s:7:"#B0E0E6";s:6:"purple";s:7:"#800080";s:13:"rebeccapurple";s:7:"#663399";s:3:"red";s:7:"#FF0000";s:9:"rosybrown";s:7:"#BC8F8F";s:9:"royalblue";s:7:"#4169E1";s:11:"saddlebrown";s:7:"#8B4513";s:6:"salmon";s:7:"#FA8072";s:10:"sandybrown";s:7:"#F4A460";s:8:"seagreen";s:7:"#2E8B57";s:8:"seashell";s:7:"#FFF5EE";s:6:"sienna";s:7:"#A0522D";s:6:"silver";s:7:"#C0C0C0";s:7:"skyblue";s:7:"#87CEEB";s:9:"slateblue";s:7:"#6A5ACD";s:9:"slategray";s:7:"#708090";s:9:"slategrey";s:7:"#708090";s:4:"snow";s:7:"#FFFAFA";s:11:"springgreen";s:7:"#00FF7F";s:9:"steelblue";s:7:"#4682B4";s:3:"tan";s:7:"#D2B48C";s:4:"teal";s:7:"#008080";s:7:"thistle";s:7:"#D8BFD8";s:6:"tomato";s:7:"#FF6347";s:9:"turquoise";s:7:"#40E0D0";s:6:"violet";s:7:"#EE82EE";s:5:"wheat";s:7:"#F5DEB3";s:5:"white";s:7:"#FFFFFF";s:10:"whitesmoke";s:7:"#F5F5F5";s:6:"yellow";s:7:"#FFFF00";s:11:"yellowgreen";s:7:"#9ACD32";}s:30:"Core.ConvertDocumentToFragment";b:1;s:36:"Core.DirectLexLineNumberSyncInterval";i:0;s:20:"Core.DisableExcludes";b:0;s:15:"Core.EnableIDNA";b:0;s:13:"Core.Encoding";s:5:"utf-8";s:26:"Core.EscapeInvalidChildren";b:0;s:22:"Core.EscapeInvalidTags";b:0;s:29:"Core.EscapeNonASCIICharacters";b:0;s:19:"Core.HiddenElements";a:2:{s:6:"script";b:1;s:5:"style";b:1;}s:13:"Core.Language";s:2:"en";s:24:"Core.LegacyEntityDecoder";b:0;s:14:"Core.LexerImpl";N;s:24:"Core.MaintainLineNumbers";N;s:22:"Core.NormalizeNewlines";b:1;s:21:"Core.RemoveInvalidImg";b:1;s:33:"Core.RemoveProcessingInstructions";b:0;s:25:"Core.RemoveScriptContents";N;s:13:"Filter.Custom";a:0:{}s:34:"Filter.ExtractStyleBlocks.Escaping";b:1;s:31:"Filter.ExtractStyleBlocks.Scope";N;s:34:"Filter.ExtractStyleBlocks.TidyImpl";N;s:25:"Filter.ExtractStyleBlocks";b:0;s:14:"Filter.YouTube";b:0;s:12:"HTML.Allowed";N;s:22:"HTML.AllowedAttributes";N;s:20:"HTML.AllowedComments";a:0:{}s:26:"HTML.AllowedCommentsRegexp";N;s:20:"HTML.AllowedElements";N;s:19:"HTML.AllowedModules";N;s:23:"HTML.Attr.Name.UseCDATA";b:0;s:17:"HTML.BlockWrapper";s:1:"p";s:16:"HTML.CoreModules";a:7:{s:9:"Structure";b:1;s:4:"Text";b:1;s:9:"Hypertext";b:1;s:4:"List";b:1;s:22:"NonXMLCommonAttributes";b:1;s:19:"XMLCommonAttributes";b:1;s:16:"CommonAttributes";b:1;}s:18:"HTML.CustomDoctype";N;s:17:"HTML.DefinitionID";N;s:18:"HTML.DefinitionRev";i:1;s:12:"HTML.Doctype";N;s:25:"HTML.FlashAllowFullScreen";b:0;s:24:"HTML.ForbiddenAttributes";a:0:{}s:22:"HTML.ForbiddenElements";a:0:{}s:10:"HTML.Forms";b:0;s:17:"HTML.MaxImgLength";i:1200;s:13:"HTML.Nofollow";b:0;s:11:"HTML.Parent";s:3:"div";s:16:"HTML.Proprietary";b:0;s:14:"HTML.SafeEmbed";b:0;s:15:"HTML.SafeIframe";b:0;s:15:"HTML.SafeObject";b:0;s:18:"HTML.SafeScripting";a:0:{}s:11:"HTML.Strict";b:0;s:16:"HTML.TargetBlank";b:0;s:19:"HTML.TargetNoopener";b:1;s:21:"HTML.TargetNoreferrer";b:1;s:12:"HTML.TidyAdd";a:0:{}s:14:"HTML.TidyLevel";s:6:"medium";s:15:"HTML.TidyRemove";a:0:{}s:12:"HTML.Trusted";b:0;s:10:"HTML.XHTML";b:1;s:28:"Output.CommentScriptContents";b:1;s:19:"Output.FixInnerHTML";b:1;s:18:"Output.FlashCompat";b:0;s:14:"Output.Newline";N;s:15:"Output.SortAttr";b:0;s:17:"Output.TidyFormat";b:0;s:17:"Test.ForceNoIconv";b:0;s:18:"URI.AllowedSchemes";a:7:{s:4:"http";b:1;s:5:"https";b:1;s:6:"mailto";b:1;s:3:"ftp";b:1;s:4:"nntp";b:1;s:4:"news";b:1;s:3:"tel";b:1;}s:8:"URI.Base";N;s:17:"URI.DefaultScheme";s:4:"http";s:16:"URI.DefinitionID";N;s:17:"URI.DefinitionRev";i:1;s:11:"URI.Disable";b:0;s:19:"URI.DisableExternal";b:0;s:28:"URI.DisableExternalResources";b:0;s:20:"URI.DisableResources";b:0;s:8:"URI.Host";N;s:17:"URI.HostBlacklist";a:0:{}s:16:"URI.MakeAbsolute";b:0;s:9:"URI.Munge";N;s:18:"URI.MungeResources";b:0;s:18:"URI.MungeSecretKey";N;s:26:"URI.OverrideAllowedSchemes";b:1;s:20:"URI.SafeIframeRegexp";N;}s:9:"*parent";N;s:8:"*cache";N;}s:4:"info";a:140:{s:19:"Attr.AllowedClasses";i:-8;s:24:"Attr.AllowedFrameTargets";i:8;s:15:"Attr.AllowedRel";i:8;s:15:"Attr.AllowedRev";i:8;s:18:"Attr.ClassUseCDATA";i:-7;s:20:"Attr.DefaultImageAlt";i:-1;s:24:"Attr.DefaultInvalidImage";i:1;s:27:"Attr.DefaultInvalidImageAlt";i:1;s:19:"Attr.DefaultTextDir";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:2:{s:3:"ltr";b:1;s:3:"rtl";b:1;}}s:13:"Attr.EnableID";i:7;s:17:"HTML.EnableAttrID";O:8:"stdClass":2:{s:3:"key";s:13:"Attr.EnableID";s:7:"isAlias";b:1;}s:21:"Attr.ForbiddenClasses";i:8;s:13:"Attr.ID.HTML5";i:-7;s:16:"Attr.IDBlacklist";i:9;s:22:"Attr.IDBlacklistRegexp";i:-1;s:13:"Attr.IDPrefix";i:1;s:18:"Attr.IDPrefixLocal";i:1;s:24:"AutoFormat.AutoParagraph";i:7;s:17:"AutoFormat.Custom";i:9;s:25:"AutoFormat.DisplayLinkURI";i:7;s:18:"AutoFormat.Linkify";i:7;s:33:"AutoFormat.PurifierLinkify.DocURL";i:1;s:37:"AutoFormatParam.PurifierLinkifyDocURL";O:8:"stdClass":2:{s:3:"key";s:33:"AutoFormat.PurifierLinkify.DocURL";s:7:"isAlias";b:1;}s:26:"AutoFormat.PurifierLinkify";i:7;s:32:"AutoFormat.RemoveEmpty.Predicate";i:10;s:44:"AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions";i:8;s:33:"AutoFormat.RemoveEmpty.RemoveNbsp";i:7;s:22:"AutoFormat.RemoveEmpty";i:7;s:39:"AutoFormat.RemoveSpansWithoutAttributes";i:7;s:19:"CSS.AllowDuplicates";i:7;s:18:"CSS.AllowImportant";i:7;s:15:"CSS.AllowTricky";i:7;s:16:"CSS.AllowedFonts";i:-8;s:21:"CSS.AllowedProperties";i:-8;s:17:"CSS.DefinitionRev";i:5;s:23:"CSS.ForbiddenProperties";i:8;s:16:"CSS.MaxImgLength";i:-1;s:15:"CSS.Proprietary";i:7;s:11:"CSS.Trusted";i:7;s:20:"Cache.DefinitionImpl";i:-1;s:20:"Core.DefinitionCache";O:8:"stdClass":2:{s:3:"key";s:20:"Cache.DefinitionImpl";s:7:"isAlias";b:1;}s:20:"Cache.SerializerPath";i:-1;s:27:"Cache.SerializerPermissions";i:-5;s:22:"Core.AggressivelyFixLt";i:7;s:29:"Core.AggressivelyRemoveScript";i:7;s:28:"Core.AllowHostnameUnderscore";i:7;s:23:"Core.AllowParseManyTags";i:7;s:18:"Core.CollectErrors";i:7;s:18:"Core.ColorKeywords";i:10;s:30:"Core.ConvertDocumentToFragment";i:7;s:24:"Core.AcceptFullDocuments";O:8:"stdClass":2:{s:3:"key";s:30:"Core.ConvertDocumentToFragment";s:7:"isAlias";b:1;}s:36:"Core.DirectLexLineNumberSyncInterval";i:5;s:20:"Core.DisableExcludes";i:7;s:15:"Core.EnableIDNA";i:7;s:13:"Core.Encoding";i:2;s:26:"Core.EscapeInvalidChildren";i:7;s:22:"Core.EscapeInvalidTags";i:7;s:29:"Core.EscapeNonASCIICharacters";i:7;s:19:"Core.HiddenElements";i:8;s:13:"Core.Language";i:1;s:24:"Core.LegacyEntityDecoder";i:7;s:14:"Core.LexerImpl";i:-11;s:24:"Core.MaintainLineNumbers";i:-7;s:22:"Core.NormalizeNewlines";i:7;s:21:"Core.RemoveInvalidImg";i:7;s:33:"Core.RemoveProcessingInstructions";i:7;s:25:"Core.RemoveScriptContents";i:-7;s:13:"Filter.Custom";i:9;s:34:"Filter.ExtractStyleBlocks.Escaping";i:7;s:33:"Filter.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:38:"FilterParam.ExtractStyleBlocksEscaping";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.Escaping";s:7:"isAlias";b:1;}s:31:"Filter.ExtractStyleBlocks.Scope";i:-1;s:30:"Filter.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:35:"FilterParam.ExtractStyleBlocksScope";O:8:"stdClass":2:{s:3:"key";s:31:"Filter.ExtractStyleBlocks.Scope";s:7:"isAlias";b:1;}s:34:"Filter.ExtractStyleBlocks.TidyImpl";i:-11;s:38:"FilterParam.ExtractStyleBlocksTidyImpl";O:8:"stdClass":2:{s:3:"key";s:34:"Filter.ExtractStyleBlocks.TidyImpl";s:7:"isAlias";b:1;}s:25:"Filter.ExtractStyleBlocks";i:7;s:14:"Filter.YouTube";i:7;s:12:"HTML.Allowed";i:-4;s:22:"HTML.AllowedAttributes";i:-8;s:20:"HTML.AllowedComments";i:8;s:26:"HTML.AllowedCommentsRegexp";i:-1;s:20:"HTML.AllowedElements";i:-8;s:19:"HTML.AllowedModules";i:-8;s:23:"HTML.Attr.Name.UseCDATA";i:7;s:17:"HTML.BlockWrapper";i:1;s:16:"HTML.CoreModules";i:8;s:18:"HTML.CustomDoctype";i:-1;s:17:"HTML.DefinitionID";i:-1;s:18:"HTML.DefinitionRev";i:5;s:12:"HTML.Doctype";O:8:"stdClass":3:{s:4:"type";i:1;s:10:"allow_null";b:1;s:7:"allowed";a:5:{s:22:"HTML 4.01 Transitional";b:1;s:16:"HTML 4.01 Strict";b:1;s:22:"XHTML 1.0 Transitional";b:1;s:16:"XHTML 1.0 Strict";b:1;s:9:"XHTML 1.1";b:1;}}s:25:"HTML.FlashAllowFullScreen";i:7;s:24:"HTML.ForbiddenAttributes";i:8;s:22:"HTML.ForbiddenElements";i:8;s:10:"HTML.Forms";i:7;s:17:"HTML.MaxImgLength";i:-5;s:13:"HTML.Nofollow";i:7;s:11:"HTML.Parent";i:1;s:16:"HTML.Proprietary";i:7;s:14:"HTML.SafeEmbed";i:7;s:15:"HTML.SafeIframe";i:7;s:15:"HTML.SafeObject";i:7;s:18:"HTML.SafeScripting";i:8;s:11:"HTML.Strict";i:7;s:16:"HTML.TargetBlank";i:7;s:19:"HTML.TargetNoopener";i:7;s:21:"HTML.TargetNoreferrer";i:7;s:12:"HTML.TidyAdd";i:8;s:14:"HTML.TidyLevel";O:8:"stdClass":2:{s:4:"type";i:1;s:7:"allowed";a:4:{s:4:"none";b:1;s:5:"light";b:1;s:6:"medium";b:1;s:5:"heavy";b:1;}}s:15:"HTML.TidyRemove";i:8;s:12:"HTML.Trusted";i:7;s:10:"HTML.XHTML";i:7;s:10:"Core.XHTML";O:8:"stdClass":2:{s:3:"key";s:10:"HTML.XHTML";s:7:"isAlias";b:1;}s:28:"Output.CommentScriptContents";i:7;s:26:"Core.CommentScriptContents";O:8:"stdClass":2:{s:3:"key";s:28:"Output.CommentScriptContents";s:7:"isAlias";b:1;}s:19:"Output.FixInnerHTML";i:7;s:18:"Output.FlashCompat";i:7;s:14:"Output.Newline";i:-1;s:15:"Output.SortAttr";i:7;s:17:"Output.TidyFormat";i:7;s:15:"Core.TidyFormat";O:8:"stdClass":2:{s:3:"key";s:17:"Output.TidyFormat";s:7:"isAlias";b:1;}s:17:"Test.ForceNoIconv";i:7;s:18:"URI.AllowedSchemes";i:8;s:8:"URI.Base";i:-1;s:17:"URI.DefaultScheme";i:-1;s:16:"URI.DefinitionID";i:-1;s:17:"URI.DefinitionRev";i:5;s:11:"URI.Disable";i:7;s:15:"Attr.DisableURI";O:8:"stdClass":2:{s:3:"key";s:11:"URI.Disable";s:7:"isAlias";b:1;}s:19:"URI.DisableExternal";i:7;s:28:"URI.DisableExternalResources";i:7;s:20:"URI.DisableResources";i:7;s:8:"URI.Host";i:-1;s:17:"URI.HostBlacklist";i:9;s:16:"URI.MakeAbsolute";i:7;s:9:"URI.Munge";i:-1;s:18:"URI.MungeResources";i:7;s:18:"URI.MungeSecretKey";i:-1;s:26:"URI.OverrideAllowedSchemes";i:7;s:20:"URI.SafeIframeRegexp";i:-1;}} \ No newline at end of file diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt new file mode 100644 index 0000000..0517fed --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt @@ -0,0 +1,8 @@ +Attr.AllowedClasses +TYPE: lookup/null +VERSION: 4.0.0 +DEFAULT: null +--DESCRIPTION-- +List of allowed class values in the class attribute. By default, this is null, +which means all classes are allowed. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt new file mode 100644 index 0000000..249edd6 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt @@ -0,0 +1,12 @@ +Attr.AllowedFrameTargets +TYPE: lookup +DEFAULT: array() +--DESCRIPTION-- +Lookup table of all allowed link frame targets. Some commonly used link +targets include _blank, _self, _parent and _top. Values should be +lowercase, as validation will be done in a case-sensitive manner despite +W3C's recommendation. XHTML 1.0 Strict does not permit the target attribute +so this directive will have no effect in that doctype. XHTML 1.1 does not +enable the Target module by default, you will have to manually enable it +(see the module documentation for more details.) +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt new file mode 100644 index 0000000..9a8fa6a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt @@ -0,0 +1,9 @@ +Attr.AllowedRel +TYPE: lookup +VERSION: 1.6.0 +DEFAULT: array() +--DESCRIPTION-- +List of allowed forward document relationships in the rel attribute. Common +values may be nofollow or print. By default, this is empty, meaning that no +document relationships are allowed. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt new file mode 100644 index 0000000..b017883 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt @@ -0,0 +1,9 @@ +Attr.AllowedRev +TYPE: lookup +VERSION: 1.6.0 +DEFAULT: array() +--DESCRIPTION-- +List of allowed reverse document relationships in the rev attribute. This +attribute is a bit of an edge-case; if you don't know what it is for, stay +away. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt new file mode 100644 index 0000000..e774b82 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt @@ -0,0 +1,19 @@ +Attr.ClassUseCDATA +TYPE: bool/null +DEFAULT: null +VERSION: 4.0.0 +--DESCRIPTION-- +If null, class will auto-detect the doctype and, if matching XHTML 1.1 or +XHTML 2.0, will use the restrictive NMTOKENS specification of class. Otherwise, +it will use a relaxed CDATA definition. If true, the relaxed CDATA definition +is forced; if false, the NMTOKENS definition is forced. To get behavior +of HTML Purifier prior to 4.0.0, set this directive to false. + +Some rational behind the auto-detection: +in previous versions of HTML Purifier, it was assumed that the form of +class was NMTOKENS, as specified by the XHTML Modularization (representing +XHTML 1.1 and XHTML 2.0). The DTDs for HTML 4.01 and XHTML 1.0, however +specify class as CDATA. HTML 5 effectively defines it as CDATA, but +with the additional constraint that each name should be unique (this is not +explicitly outlined in previous specifications). +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt new file mode 100644 index 0000000..533165e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt @@ -0,0 +1,11 @@ +Attr.DefaultImageAlt +TYPE: string/null +DEFAULT: null +VERSION: 3.2.0 +--DESCRIPTION-- +This is the content of the alt tag of an image if the user had not +previously specified an alt attribute. This applies to all images without +a valid alt attribute, as opposed to %Attr.DefaultInvalidImageAlt, which +only applies to invalid images, and overrides in the case of an invalid image. +Default behavior with null is to use the basename of the src tag for the alt. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt new file mode 100644 index 0000000..9eb7e38 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt @@ -0,0 +1,9 @@ +Attr.DefaultInvalidImage +TYPE: string +DEFAULT: '' +--DESCRIPTION-- +This is the default image an img tag will be pointed to if it does not have +a valid src attribute. In future versions, we may allow the image tag to +be removed completely, but due to design issues, this is not possible right +now. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt new file mode 100644 index 0000000..2f17bf4 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt @@ -0,0 +1,8 @@ +Attr.DefaultInvalidImageAlt +TYPE: string +DEFAULT: 'Invalid image' +--DESCRIPTION-- +This is the content of the alt tag of an invalid image if the user had not +previously specified an alt attribute. It has no effect when the image is +valid but there was no alt attribute present. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt new file mode 100644 index 0000000..52654b5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt @@ -0,0 +1,10 @@ +Attr.DefaultTextDir +TYPE: string +DEFAULT: 'ltr' +--DESCRIPTION-- +Defines the default text direction (ltr or rtl) of the document being +parsed. This generally is the same as the value of the dir attribute in +HTML, or ltr if that is not specified. +--ALLOWED-- +'ltr', 'rtl' +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt new file mode 100644 index 0000000..6440d21 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt @@ -0,0 +1,16 @@ +Attr.EnableID +TYPE: bool +DEFAULT: false +VERSION: 1.2.0 +--DESCRIPTION-- +Allows the ID attribute in HTML. This is disabled by default due to the +fact that without proper configuration user input can easily break the +validation of a webpage by specifying an ID that is already on the +surrounding HTML. If you don't mind throwing caution to the wind, enable +this directive, but I strongly recommend you also consider blacklisting IDs +you use (%Attr.IDBlacklist) or prefixing all user supplied IDs +(%Attr.IDPrefix). When set to true HTML Purifier reverts to the behavior of +pre-1.2.0 versions. +--ALIASES-- +HTML.EnableAttrID +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt new file mode 100644 index 0000000..f31d226 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt @@ -0,0 +1,8 @@ +Attr.ForbiddenClasses +TYPE: lookup +VERSION: 4.0.0 +DEFAULT: array() +--DESCRIPTION-- +List of forbidden class values in the class attribute. By default, this is +empty, which means that no classes are forbidden. See also %Attr.AllowedClasses. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ID.HTML5.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ID.HTML5.txt new file mode 100644 index 0000000..735d4b7 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ID.HTML5.txt @@ -0,0 +1,10 @@ +Attr.ID.HTML5 +TYPE: bool/null +DEFAULT: null +VERSION: 4.8.0 +--DESCRIPTION-- +In HTML5, restrictions on the format of the id attribute have been significantly +relaxed, such that any string is valid so long as it contains no spaces and +is at least one character. In lieu of a general HTML5 compatibility flag, +set this configuration directive to true to use the relaxed rules. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt new file mode 100644 index 0000000..5f2b5e3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt @@ -0,0 +1,5 @@ +Attr.IDBlacklist +TYPE: list +DEFAULT: array() +DESCRIPTION: Array of IDs not allowed in the document. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt new file mode 100644 index 0000000..6f58245 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt @@ -0,0 +1,9 @@ +Attr.IDBlacklistRegexp +TYPE: string/null +VERSION: 1.6.0 +DEFAULT: NULL +--DESCRIPTION-- +PCRE regular expression to be matched against all IDs. If the expression is +matches, the ID is rejected. Use this with care: may cause significant +degradation. ID matching is done after all other validation. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt new file mode 100644 index 0000000..cc49d43 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt @@ -0,0 +1,12 @@ +Attr.IDPrefix +TYPE: string +VERSION: 1.2.0 +DEFAULT: '' +--DESCRIPTION-- +String to prefix to IDs. If you have no idea what IDs your pages may use, +you may opt to simply add a prefix to all user-submitted ID attributes so +that they are still usable, but will not conflict with core page IDs. +Example: setting the directive to 'user_' will result in a user submitted +'foo' to become 'user_foo' Be sure to set %HTML.EnableAttrID to true +before using this. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt new file mode 100644 index 0000000..2c5924a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt @@ -0,0 +1,14 @@ +Attr.IDPrefixLocal +TYPE: string +VERSION: 1.2.0 +DEFAULT: '' +--DESCRIPTION-- +Temporary prefix for IDs used in conjunction with %Attr.IDPrefix. If you +need to allow multiple sets of user content on web page, you may need to +have a seperate prefix that changes with each iteration. This way, +seperately submitted user content displayed on the same page doesn't +clobber each other. Ideal values are unique identifiers for the content it +represents (i.e. the id of the row in the database). Be sure to add a +seperator (like an underscore) at the end. Warning: this directive will +not work unless %Attr.IDPrefix is set to a non-empty value! +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt new file mode 100644 index 0000000..d5caa1b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt @@ -0,0 +1,31 @@ +AutoFormat.AutoParagraph +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ This directive turns on auto-paragraphing, where double newlines are + converted in to paragraphs whenever possible. Auto-paragraphing: +

+
    +
  • Always applies to inline elements or text in the root node,
  • +
  • Applies to inline elements or text with double newlines in nodes + that allow paragraph tags,
  • +
  • Applies to double newlines in paragraph tags
  • +
+

+ p tags must be allowed for this directive to take effect. + We do not use br tags for paragraphing, as that is + semantically incorrect. +

+

+ To prevent auto-paragraphing as a content-producer, refrain from using + double-newlines except to specify a new paragraph or in contexts where + it has special meaning (whitespace usually has no meaning except in + tags like pre, so this should not be difficult.) To prevent + the paragraphing of inline text adjacent to block elements, wrap them + in div tags (the behavior is slightly different outside of + the root node.) +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt new file mode 100644 index 0000000..2a47648 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt @@ -0,0 +1,12 @@ +AutoFormat.Custom +TYPE: list +VERSION: 2.0.1 +DEFAULT: array() +--DESCRIPTION-- + +

+ This directive can be used to add custom auto-format injectors. + Specify an array of injector names (class name minus the prefix) + or concrete implementations. Injector class must exist. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt new file mode 100644 index 0000000..663064a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt @@ -0,0 +1,11 @@ +AutoFormat.DisplayLinkURI +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ This directive turns on the in-text display of URIs in <a> tags, and disables + those links. For example, example becomes + example (http://example.com). +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt new file mode 100644 index 0000000..3a48ba9 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt @@ -0,0 +1,12 @@ +AutoFormat.Linkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ This directive turns on linkification, auto-linking http, ftp and + https URLs. a tags with the href attribute + must be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt new file mode 100644 index 0000000..db58b13 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify.DocURL +TYPE: string +VERSION: 2.0.1 +DEFAULT: '#%s' +ALIASES: AutoFormatParam.PurifierLinkifyDocURL +--DESCRIPTION-- +

+ Location of configuration documentation to link to, let %s substitute + into the configuration's namespace and directive names sans the percent + sign. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt new file mode 100644 index 0000000..7996488 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt @@ -0,0 +1,12 @@ +AutoFormat.PurifierLinkify +TYPE: bool +VERSION: 2.0.1 +DEFAULT: false +--DESCRIPTION-- + +

+ Internal auto-formatter that converts configuration directives in + syntax %Namespace.Directive to links. a tags + with the href attribute must be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt new file mode 100644 index 0000000..6367fe2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt @@ -0,0 +1,14 @@ +AutoFormat.RemoveEmpty.Predicate +TYPE: hash +VERSION: 4.7.0 +DEFAULT: array('colgroup' => array(), 'th' => array(), 'td' => array(), 'iframe' => array('src')) +--DESCRIPTION-- +

+ Given that an element has no contents, it will be removed by default, unless + this predicate dictates otherwise. The predicate can either be an associative + map from tag name to list of attributes that must be present for the element + to be considered preserved: thus, the default always preserves colgroup, + th and td, and also iframe if it + has a src. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt new file mode 100644 index 0000000..35c393b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt @@ -0,0 +1,11 @@ +AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions +TYPE: lookup +VERSION: 4.0.0 +DEFAULT: array('td' => true, 'th' => true) +--DESCRIPTION-- +

+ When %AutoFormat.RemoveEmpty and %AutoFormat.RemoveEmpty.RemoveNbsp + are enabled, this directive defines what HTML elements should not be + removede if they have only a non-breaking space in them. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt new file mode 100644 index 0000000..9228dee --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt @@ -0,0 +1,15 @@ +AutoFormat.RemoveEmpty.RemoveNbsp +TYPE: bool +VERSION: 4.0.0 +DEFAULT: false +--DESCRIPTION-- +

+ When enabled, HTML Purifier will treat any elements that contain only + non-breaking spaces as well as regular whitespace as empty, and remove + them when %AutoFormat.RemoveEmpty is enabled. +

+

+ See %AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions for a list of elements + that don't have this behavior applied to them. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt new file mode 100644 index 0000000..34657ba --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt @@ -0,0 +1,46 @@ +AutoFormat.RemoveEmpty +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ When enabled, HTML Purifier will attempt to remove empty elements that + contribute no semantic information to the document. The following types + of nodes will be removed: +

+
  • + Tags with no attributes and no content, and that are not empty + elements (remove <a></a> but not + <br />), and +
  • +
  • + Tags with no content, except for:
      +
    • The colgroup element, or
    • +
    • + Elements with the id or name attribute, + when those attributes are permitted on those elements. +
    • +
  • +
+

+ Please be very careful when using this functionality; while it may not + seem that empty elements contain useful information, they can alter the + layout of a document given appropriate styling. This directive is most + useful when you are processing machine-generated HTML, please avoid using + it on regular user HTML. +

+

+ Elements that contain only whitespace will be treated as empty. Non-breaking + spaces, however, do not count as whitespace. See + %AutoFormat.RemoveEmpty.RemoveNbsp for alternate behavior. +

+

+ This algorithm is not perfect; you may still notice some empty tags, + particularly if a node had elements, but those elements were later removed + because they were not permitted in that context, or tags that, after + being auto-closed by another tag, where empty. This is for safety reasons + to prevent clever code from breaking validation. The general rule of thumb: + if a tag looked empty on the way in, it will get removed; if HTML Purifier + made it empty, it will stay. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt new file mode 100644 index 0000000..dde990a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt @@ -0,0 +1,11 @@ +AutoFormat.RemoveSpansWithoutAttributes +TYPE: bool +VERSION: 4.0.1 +DEFAULT: false +--DESCRIPTION-- +

+ This directive causes span tags without any attributes + to be removed. It will also remove spans that had all attributes + removed during processing. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowDuplicates.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowDuplicates.txt new file mode 100644 index 0000000..4d054b1 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowDuplicates.txt @@ -0,0 +1,11 @@ +CSS.AllowDuplicates +TYPE: bool +DEFAULT: false +VERSION: 4.8.0 +--DESCRIPTION-- +

+ By default, HTML Purifier removes duplicate CSS properties, + like color:red; color:blue. If this is set to + true, duplicate properties are allowed. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt new file mode 100644 index 0000000..b324608 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt @@ -0,0 +1,8 @@ +CSS.AllowImportant +TYPE: bool +DEFAULT: false +VERSION: 3.1.0 +--DESCRIPTION-- +This parameter determines whether or not !important cascade modifiers should +be allowed in user CSS. If false, !important will stripped. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt new file mode 100644 index 0000000..748be0e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt @@ -0,0 +1,11 @@ +CSS.AllowTricky +TYPE: bool +DEFAULT: false +VERSION: 3.1.0 +--DESCRIPTION-- +This parameter determines whether or not to allow "tricky" CSS properties and +values. Tricky CSS properties/values can drastically modify page layout or +be used for deceptive practices but do not directly constitute a security risk. +For example, display:none; is considered a tricky property that +will only be allowed if this directive is set to true. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt new file mode 100644 index 0000000..3fd4654 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt @@ -0,0 +1,12 @@ +CSS.AllowedFonts +TYPE: lookup/null +VERSION: 4.3.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ Allows you to manually specify a set of allowed fonts. If + NULL, all fonts are allowed. This directive + affects generic names (serif, sans-serif, monospace, cursive, + fantasy) as well as specific font families. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt new file mode 100644 index 0000000..460112e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt @@ -0,0 +1,18 @@ +CSS.AllowedProperties +TYPE: lookup/null +VERSION: 3.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If HTML Purifier's style attributes set is unsatisfactory for your needs, + you can overload it with your own list of tags to allow. Note that this + method is subtractive: it does its job by taking away from HTML Purifier + usual feature set, so you cannot add an attribute that HTML Purifier never + supported in the first place. +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt new file mode 100644 index 0000000..5cb7dda --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt @@ -0,0 +1,11 @@ +CSS.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt new file mode 100644 index 0000000..f1f5c5f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt @@ -0,0 +1,13 @@ +CSS.ForbiddenProperties +TYPE: lookup +VERSION: 4.2.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This is the logical inverse of %CSS.AllowedProperties, and it will + override that directive or any other directive. If possible, + %CSS.AllowedProperties is recommended over this directive, + because it can sometimes be difficult to tell whether or not you've + forbidden all of the CSS properties you truly would like to disallow. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt new file mode 100644 index 0000000..7a32914 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt @@ -0,0 +1,16 @@ +CSS.MaxImgLength +TYPE: string/null +DEFAULT: '1200px' +VERSION: 3.1.1 +--DESCRIPTION-- +

+ This parameter sets the maximum allowed length on img tags, + effectively the width and height properties. + Only absolute units of measurement (in, pt, pc, mm, cm) and pixels (px) are allowed. This is + in place to prevent imagecrash attacks, disable with null at your own risk. + This directive is similar to %HTML.MaxImgLength, and both should be + concurrently edited, although there are + subtle differences in the input format (the CSS max is a number with + a unit). +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt new file mode 100644 index 0000000..148eedb --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt @@ -0,0 +1,10 @@ +CSS.Proprietary +TYPE: bool +VERSION: 3.0.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Whether or not to allow safe, proprietary CSS values. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt new file mode 100644 index 0000000..e733a61 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt @@ -0,0 +1,9 @@ +CSS.Trusted +TYPE: bool +VERSION: 4.2.1 +DEFAULT: false +--DESCRIPTION-- +Indicates whether or not the user's CSS input is trusted or not. If the +input is trusted, a more expansive set of allowed properties. See +also %HTML.Trusted. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt new file mode 100644 index 0000000..c486724 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt @@ -0,0 +1,14 @@ +Cache.DefinitionImpl +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: 'Serializer' +--DESCRIPTION-- + +This directive defines which method to use when caching definitions, +the complex data-type that makes HTML Purifier tick. Set to null +to disable caching (not recommended, as you will see a definite +performance degradation). + +--ALIASES-- +Core.DefinitionCache +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt new file mode 100644 index 0000000..5403650 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt @@ -0,0 +1,13 @@ +Cache.SerializerPath +TYPE: string/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Absolute path with no trailing slash to store serialized definitions in. + Default is within the + HTML Purifier library inside DefinitionCache/Serializer. This + path must be writable by the webserver. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt new file mode 100644 index 0000000..2e0cc81 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt @@ -0,0 +1,16 @@ +Cache.SerializerPermissions +TYPE: int/null +VERSION: 4.3.0 +DEFAULT: 0755 +--DESCRIPTION-- + +

+ Directory permissions of the files and directories created inside + the DefinitionCache/Serializer or other custom serializer path. +

+

+ In HTML Purifier 4.8.0, this also supports NULL, + which means that no chmod'ing or directory creation shall + occur. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt new file mode 100644 index 0000000..568cbf3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt @@ -0,0 +1,18 @@ +Core.AggressivelyFixLt +TYPE: bool +VERSION: 2.1.0 +DEFAULT: true +--DESCRIPTION-- +

+ This directive enables aggressive pre-filter fixes HTML Purifier can + perform in order to ensure that open angled-brackets do not get killed + during parsing stage. Enabling this will result in two preg_replace_callback + calls and at least two preg_replace calls for every HTML document parsed; + if your users make very well-formed HTML, you can set this directive false. + This has no effect when DirectLex is used. +

+

+ Notice: This directive's default turned from false to true + in HTML Purifier 3.2.0. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt new file mode 100644 index 0000000..b2b6ab1 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt @@ -0,0 +1,16 @@ +Core.AggressivelyRemoveScript +TYPE: bool +VERSION: 4.9.0 +DEFAULT: true +--DESCRIPTION-- +

+ This directive enables aggressive pre-filter removal of + script tags. This is not necessary for security, + but it can help work around a bug in libxml where embedded + HTML elements inside script sections cause the parser to + choke. To revert to pre-4.9.0 behavior, set this to false. + This directive has no effect if %Core.Trusted is true, + %Core.RemoveScriptContents is false, or %Core.HiddenElements + does not contain script. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt new file mode 100644 index 0000000..2c910cc --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt @@ -0,0 +1,16 @@ +Core.AllowHostnameUnderscore +TYPE: bool +VERSION: 4.6.0 +DEFAULT: false +--DESCRIPTION-- +

+ By RFC 1123, underscores are not permitted in host names. + (This is in contrast to the specification for DNS, RFC + 2181, which allows underscores.) + However, most browsers do the right thing when faced with + an underscore in the host name, and so some poorly written + websites are written with the expectation this should work. + Setting this parameter to true relaxes our allowed character + check so that underscores are permitted. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt new file mode 100644 index 0000000..06278f8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowParseManyTags.txt @@ -0,0 +1,12 @@ +Core.AllowParseManyTags +TYPE: bool +DEFAULT: false +VERSION: 4.10.1 +--DESCRIPTION-- +

+ This directive allows parsing of many nested tags. + If you set true, relaxes any hardcoded limit from the parser. + However, in that case it may cause a Dos attack. + Be careful when enabling it. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt new file mode 100644 index 0000000..d731791 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt @@ -0,0 +1,12 @@ +Core.CollectErrors +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- + +Whether or not to collect errors found while filtering the document. This +is a useful way to give feedback to your users. Warning: +Currently this feature is very patchy and experimental, with lots of +possible error messages not yet implemented. It will not cause any +problems, but it may not help your users either. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt new file mode 100644 index 0000000..a75844c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt @@ -0,0 +1,160 @@ +Core.ColorKeywords +TYPE: hash +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'aliceblue' => '#F0F8FF', + 'antiquewhite' => '#FAEBD7', + 'aqua' => '#00FFFF', + 'aquamarine' => '#7FFFD4', + 'azure' => '#F0FFFF', + 'beige' => '#F5F5DC', + 'bisque' => '#FFE4C4', + 'black' => '#000000', + 'blanchedalmond' => '#FFEBCD', + 'blue' => '#0000FF', + 'blueviolet' => '#8A2BE2', + 'brown' => '#A52A2A', + 'burlywood' => '#DEB887', + 'cadetblue' => '#5F9EA0', + 'chartreuse' => '#7FFF00', + 'chocolate' => '#D2691E', + 'coral' => '#FF7F50', + 'cornflowerblue' => '#6495ED', + 'cornsilk' => '#FFF8DC', + 'crimson' => '#DC143C', + 'cyan' => '#00FFFF', + 'darkblue' => '#00008B', + 'darkcyan' => '#008B8B', + 'darkgoldenrod' => '#B8860B', + 'darkgray' => '#A9A9A9', + 'darkgrey' => '#A9A9A9', + 'darkgreen' => '#006400', + 'darkkhaki' => '#BDB76B', + 'darkmagenta' => '#8B008B', + 'darkolivegreen' => '#556B2F', + 'darkorange' => '#FF8C00', + 'darkorchid' => '#9932CC', + 'darkred' => '#8B0000', + 'darksalmon' => '#E9967A', + 'darkseagreen' => '#8FBC8F', + 'darkslateblue' => '#483D8B', + 'darkslategray' => '#2F4F4F', + 'darkslategrey' => '#2F4F4F', + 'darkturquoise' => '#00CED1', + 'darkviolet' => '#9400D3', + 'deeppink' => '#FF1493', + 'deepskyblue' => '#00BFFF', + 'dimgray' => '#696969', + 'dimgrey' => '#696969', + 'dodgerblue' => '#1E90FF', + 'firebrick' => '#B22222', + 'floralwhite' => '#FFFAF0', + 'forestgreen' => '#228B22', + 'fuchsia' => '#FF00FF', + 'gainsboro' => '#DCDCDC', + 'ghostwhite' => '#F8F8FF', + 'gold' => '#FFD700', + 'goldenrod' => '#DAA520', + 'gray' => '#808080', + 'grey' => '#808080', + 'green' => '#008000', + 'greenyellow' => '#ADFF2F', + 'honeydew' => '#F0FFF0', + 'hotpink' => '#FF69B4', + 'indianred' => '#CD5C5C', + 'indigo' => '#4B0082', + 'ivory' => '#FFFFF0', + 'khaki' => '#F0E68C', + 'lavender' => '#E6E6FA', + 'lavenderblush' => '#FFF0F5', + 'lawngreen' => '#7CFC00', + 'lemonchiffon' => '#FFFACD', + 'lightblue' => '#ADD8E6', + 'lightcoral' => '#F08080', + 'lightcyan' => '#E0FFFF', + 'lightgoldenrodyellow' => '#FAFAD2', + 'lightgray' => '#D3D3D3', + 'lightgrey' => '#D3D3D3', + 'lightgreen' => '#90EE90', + 'lightpink' => '#FFB6C1', + 'lightsalmon' => '#FFA07A', + 'lightseagreen' => '#20B2AA', + 'lightskyblue' => '#87CEFA', + 'lightslategray' => '#778899', + 'lightslategrey' => '#778899', + 'lightsteelblue' => '#B0C4DE', + 'lightyellow' => '#FFFFE0', + 'lime' => '#00FF00', + 'limegreen' => '#32CD32', + 'linen' => '#FAF0E6', + 'magenta' => '#FF00FF', + 'maroon' => '#800000', + 'mediumaquamarine' => '#66CDAA', + 'mediumblue' => '#0000CD', + 'mediumorchid' => '#BA55D3', + 'mediumpurple' => '#9370DB', + 'mediumseagreen' => '#3CB371', + 'mediumslateblue' => '#7B68EE', + 'mediumspringgreen' => '#00FA9A', + 'mediumturquoise' => '#48D1CC', + 'mediumvioletred' => '#C71585', + 'midnightblue' => '#191970', + 'mintcream' => '#F5FFFA', + 'mistyrose' => '#FFE4E1', + 'moccasin' => '#FFE4B5', + 'navajowhite' => '#FFDEAD', + 'navy' => '#000080', + 'oldlace' => '#FDF5E6', + 'olive' => '#808000', + 'olivedrab' => '#6B8E23', + 'orange' => '#FFA500', + 'orangered' => '#FF4500', + 'orchid' => '#DA70D6', + 'palegoldenrod' => '#EEE8AA', + 'palegreen' => '#98FB98', + 'paleturquoise' => '#AFEEEE', + 'palevioletred' => '#DB7093', + 'papayawhip' => '#FFEFD5', + 'peachpuff' => '#FFDAB9', + 'peru' => '#CD853F', + 'pink' => '#FFC0CB', + 'plum' => '#DDA0DD', + 'powderblue' => '#B0E0E6', + 'purple' => '#800080', + 'rebeccapurple' => '#663399', + 'red' => '#FF0000', + 'rosybrown' => '#BC8F8F', + 'royalblue' => '#4169E1', + 'saddlebrown' => '#8B4513', + 'salmon' => '#FA8072', + 'sandybrown' => '#F4A460', + 'seagreen' => '#2E8B57', + 'seashell' => '#FFF5EE', + 'sienna' => '#A0522D', + 'silver' => '#C0C0C0', + 'skyblue' => '#87CEEB', + 'slateblue' => '#6A5ACD', + 'slategray' => '#708090', + 'slategrey' => '#708090', + 'snow' => '#FFFAFA', + 'springgreen' => '#00FF7F', + 'steelblue' => '#4682B4', + 'tan' => '#D2B48C', + 'teal' => '#008080', + 'thistle' => '#D8BFD8', + 'tomato' => '#FF6347', + 'turquoise' => '#40E0D0', + 'violet' => '#EE82EE', + 'wheat' => '#F5DEB3', + 'white' => '#FFFFFF', + 'whitesmoke' => '#F5F5F5', + 'yellow' => '#FFFF00', + 'yellowgreen' => '#9ACD32' +) +--DESCRIPTION-- + +Lookup array of color names to six digit hexadecimal number corresponding +to color, with preceding hash mark. Used when parsing colors. The lookup +is done in a case-insensitive manner. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt new file mode 100644 index 0000000..64b114f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt @@ -0,0 +1,14 @@ +Core.ConvertDocumentToFragment +TYPE: bool +DEFAULT: true +--DESCRIPTION-- + +This parameter determines whether or not the filter should convert +input that is a full document with html and body tags to a fragment +of just the contents of a body tag. This parameter is simply something +HTML Purifier can do during an edge-case: for most inputs, this +processing is not necessary. + +--ALIASES-- +Core.AcceptFullDocuments +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt new file mode 100644 index 0000000..36f16e0 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt @@ -0,0 +1,17 @@ +Core.DirectLexLineNumberSyncInterval +TYPE: int +VERSION: 2.0.0 +DEFAULT: 0 +--DESCRIPTION-- + +

+ Specifies the number of tokens the DirectLex line number tracking + implementations should process before attempting to resyncronize the + current line count by manually counting all previous new-lines. When + at 0, this functionality is disabled. Lower values will decrease + performance, and this is only strictly necessary if the counting + algorithm is buggy (in which case you should report it as a bug). + This has no effect when %Core.MaintainLineNumbers is disabled or DirectLex is + not being used. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt new file mode 100644 index 0000000..1cd4c2c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt @@ -0,0 +1,14 @@ +Core.DisableExcludes +TYPE: bool +DEFAULT: false +VERSION: 4.5.0 +--DESCRIPTION-- +

+ This directive disables SGML-style exclusions, e.g. the exclusion of + <object> in any descendant of a + <pre> tag. Disabling excludes will allow some + invalid documents to pass through HTML Purifier, but HTML Purifier + will also be less likely to accidentally remove large documents during + processing. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt new file mode 100644 index 0000000..ce243c3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt @@ -0,0 +1,9 @@ +Core.EnableIDNA +TYPE: bool +DEFAULT: false +VERSION: 4.4.0 +--DESCRIPTION-- +Allows international domain names in URLs. This configuration option +requires the PEAR Net_IDNA2 module to be installed. It operates by +punycoding any internationalized host names for maximum portability. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt new file mode 100644 index 0000000..8bfb47c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt @@ -0,0 +1,15 @@ +Core.Encoding +TYPE: istring +DEFAULT: 'utf-8' +--DESCRIPTION-- +If for some reason you are unable to convert all webpages to UTF-8, you can +use this directive as a stop-gap compatibility change to let HTML Purifier +deal with non UTF-8 input. This technique has notable deficiencies: +absolutely no characters outside of the selected character encoding will be +preserved, not even the ones that have been ampersand escaped (this is due +to a UTF-8 specific feature that automatically resolves all +entities), making it pretty useless for anything except the most I18N-blind +applications, although %Core.EscapeNonASCIICharacters offers fixes this +trouble with another tradeoff. This directive only accepts ISO-8859-1 if +iconv is not enabled. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt new file mode 100644 index 0000000..a3881be --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt @@ -0,0 +1,12 @@ +Core.EscapeInvalidChildren +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +

Warning: this configuration option is no longer does anything as of 4.6.0.

+ +

When true, a child is found that is not allowed in the context of the +parent element will be transformed into text as if it were ASCII. When +false, that element and all internal tags will be dropped, though text will +be preserved. There is no option for dropping the element but preserving +child nodes.

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt new file mode 100644 index 0000000..a7a5b24 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt @@ -0,0 +1,7 @@ +Core.EscapeInvalidTags +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When true, invalid tags will be written back to the document as plain text. +Otherwise, they are silently dropped. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt new file mode 100644 index 0000000..abb4999 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt @@ -0,0 +1,13 @@ +Core.EscapeNonASCIICharacters +TYPE: bool +VERSION: 1.4.0 +DEFAULT: false +--DESCRIPTION-- +This directive overcomes a deficiency in %Core.Encoding by blindly +converting all non-ASCII characters into decimal numeric entities before +converting it to its native encoding. This means that even characters that +can be expressed in the non-UTF-8 encoding will be entity-ized, which can +be a real downer for encodings like Big5. It also assumes that the ASCII +repetoire is available, although this is the case for almost all encodings. +Anyway, use UTF-8! +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt new file mode 100644 index 0000000..915391e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt @@ -0,0 +1,19 @@ +Core.HiddenElements +TYPE: lookup +--DEFAULT-- +array ( + 'script' => true, + 'style' => true, +) +--DESCRIPTION-- + +

+ This directive is a lookup array of elements which should have their + contents removed when they are not allowed by the HTML definition. + For example, the contents of a script tag are not + normally shown in a document, so if script tags are to be removed, + their contents should be removed to. This is opposed to a b + tag, which defines some presentational changes but does not hide its + contents. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt new file mode 100644 index 0000000..233fca1 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt @@ -0,0 +1,10 @@ +Core.Language +TYPE: string +VERSION: 2.0.0 +DEFAULT: 'en' +--DESCRIPTION-- + +ISO 639 language code for localizable things in HTML Purifier to use, +which is mainly error reporting. There is currently only an English (en) +translation, so this directive is currently useless. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt new file mode 100644 index 0000000..392b436 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt @@ -0,0 +1,36 @@ +Core.LegacyEntityDecoder +TYPE: bool +VERSION: 4.9.0 +DEFAULT: false +--DESCRIPTION-- +

+ Prior to HTML Purifier 4.9.0, entities were decoded by performing + a global search replace for all entities whose decoded versions + did not have special meanings under HTML, and replaced them with + their decoded versions. We would match all entities, even if they did + not have a trailing semicolon, but only if there weren't any trailing + alphanumeric characters. +

+ + + + + + +
OriginalTextAttribute
&yen;¥¥
&yen¥¥
&yena&yena&yena
&yen=¥=¥=
+

+ In HTML Purifier 4.9.0, we changed the behavior of entity parsing + to match entities that had missing trailing semicolons in less + cases, to more closely match HTML5 parsing behavior: +

+ + + + + + +
OriginalTextAttribute
&yen;¥¥
&yen¥¥
&yena¥a&yena
&yen=¥=&yen=
+

+ This flag reverts back to pre-HTML Purifier 4.9.0 behavior. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt new file mode 100644 index 0000000..8983e2c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt @@ -0,0 +1,34 @@ +Core.LexerImpl +TYPE: mixed/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ This parameter determines what lexer implementation can be used. The + valid values are: +

+
+
null
+
+ Recommended, the lexer implementation will be auto-detected based on + your PHP-version and configuration. +
+
string lexer identifier
+
+ This is a slim way of manually overridding the implementation. + Currently recognized values are: DOMLex (the default PHP5 +implementation) + and DirectLex (the default PHP4 implementation). Only use this if + you know what you are doing: usually, the auto-detection will + manage things for cases you aren't even aware of. +
+
object lexer instance
+
+ Super-advanced: you can specify your own, custom, implementation that + implements the interface defined by HTMLPurifier_Lexer. + I may remove this option simply because I don't expect anyone + to use it. +
+
+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt new file mode 100644 index 0000000..eb841a7 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt @@ -0,0 +1,16 @@ +Core.MaintainLineNumbers +TYPE: bool/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If true, HTML Purifier will add line number information to all tokens. + This is useful when error reporting is turned on, but can result in + significant performance degradation and should not be used when + unnecessary. This directive must be used with the DirectLex lexer, + as the DOMLex lexer does not (yet) support this functionality. + If the value is null, an appropriate value will be selected based + on other configuration. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt new file mode 100644 index 0000000..d77f536 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt @@ -0,0 +1,11 @@ +Core.NormalizeNewlines +TYPE: bool +VERSION: 4.2.0 +DEFAULT: true +--DESCRIPTION-- +

+ Whether or not to normalize newlines to the operating + system default. When false, HTML Purifier + will attempt to preserve mixed newline files. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt new file mode 100644 index 0000000..4070c2a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt @@ -0,0 +1,12 @@ +Core.RemoveInvalidImg +TYPE: bool +DEFAULT: true +VERSION: 1.3.0 +--DESCRIPTION-- + +

+ This directive enables pre-emptive URI checking in img + tags, as the attribute validation strategy is not authorized to + remove elements from the document. Revert to pre-1.3.0 behavior by setting to false. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt new file mode 100644 index 0000000..3397d9f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt @@ -0,0 +1,11 @@ +Core.RemoveProcessingInstructions +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +Instead of escaping processing instructions in the form <? ... +?>, remove it out-right. This may be useful if the HTML +you are validating contains XML processing instruction gunk, however, +it can also be user-unfriendly for people attempting to post PHP +snippets. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt new file mode 100644 index 0000000..a4cd966 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt @@ -0,0 +1,12 @@ +Core.RemoveScriptContents +TYPE: bool/null +DEFAULT: NULL +VERSION: 2.0.0 +DEPRECATED-VERSION: 2.1.0 +DEPRECATED-USE: Core.HiddenElements +--DESCRIPTION-- +

+ This directive enables HTML Purifier to remove not only script tags + but all of their contents. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt new file mode 100644 index 0000000..3db50ef --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt @@ -0,0 +1,11 @@ +Filter.Custom +TYPE: list +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This directive can be used to add custom filters; it is nearly the + equivalent of the now deprecated HTMLPurifier->addFilter() + method. Specify an array of concrete implementations. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt new file mode 100644 index 0000000..16829bc --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt @@ -0,0 +1,14 @@ +Filter.ExtractStyleBlocks.Escaping +TYPE: bool +VERSION: 3.0.0 +DEFAULT: true +ALIASES: Filter.ExtractStyleBlocksEscaping, FilterParam.ExtractStyleBlocksEscaping +--DESCRIPTION-- + +

+ Whether or not to escape the dangerous characters <, > and & + as \3C, \3E and \26, respectively. This is can be safely set to false + if the contents of StyleBlocks will be placed in an external stylesheet, + where there is no risk of it being interpreted as HTML. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt new file mode 100644 index 0000000..7f95f54 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt @@ -0,0 +1,29 @@ +Filter.ExtractStyleBlocks.Scope +TYPE: string/null +VERSION: 3.0.0 +DEFAULT: NULL +ALIASES: Filter.ExtractStyleBlocksScope, FilterParam.ExtractStyleBlocksScope +--DESCRIPTION-- + +

+ If you would like users to be able to define external stylesheets, but + only allow them to specify CSS declarations for a specific node and + prevent them from fiddling with other elements, use this directive. + It accepts any valid CSS selector, and will prepend this to any + CSS declaration extracted from the document. For example, if this + directive is set to #user-content and a user uses the + selector a:hover, the final selector will be + #user-content a:hover. +

+

+ The comma shorthand may be used; consider the above example, with + #user-content, #user-content2, the final selector will + be #user-content a:hover, #user-content2 a:hover. +

+

+ Warning: It is possible for users to bypass this measure + using a naughty + selector. This is a bug in CSS Tidy 1.3, not HTML + Purifier, and I am working to get it fixed. Until then, HTML Purifier + performs a basic check to prevent this. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt new file mode 100644 index 0000000..6c231b2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt @@ -0,0 +1,16 @@ +Filter.ExtractStyleBlocks.TidyImpl +TYPE: mixed/null +VERSION: 3.1.0 +DEFAULT: NULL +ALIASES: FilterParam.ExtractStyleBlocksTidyImpl +--DESCRIPTION-- +

+ If left NULL, HTML Purifier will attempt to instantiate a csstidy + class to use for internal cleaning. This will usually be good enough. +

+

+ However, for trusted user input, you can set this to false to + disable cleaning. In addition, you can supply your own concrete implementation + of Tidy's interface to use, although I don't know why you'd want to do that. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt new file mode 100644 index 0000000..078d087 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt @@ -0,0 +1,74 @@ +Filter.ExtractStyleBlocks +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +EXTERNAL: CSSTidy +--DESCRIPTION-- +

+ This directive turns on the style block extraction filter, which removes + style blocks from input HTML, cleans them up with CSSTidy, + and places them in the StyleBlocks context variable, for further + use by you, usually to be placed in an external stylesheet, or a + style block in the head of your document. +

+

+ Sample usage: +

+
';
+?>
+
+
+
+  Filter.ExtractStyleBlocks
+body {color:#F00;} Some text';
+
+    $config = HTMLPurifier_Config::createDefault();
+    $config->set('Filter', 'ExtractStyleBlocks', true);
+    $purifier = new HTMLPurifier($config);
+
+    $html = $purifier->purify($dirty);
+
+    // This implementation writes the stylesheets to the styles/ directory.
+    // You can also echo the styles inside the document, but it's a bit
+    // more difficult to make sure they get interpreted properly by
+    // browsers; try the usual CSS armoring techniques.
+    $styles = $purifier->context->get('StyleBlocks');
+    $dir = 'styles/';
+    if (!is_dir($dir)) mkdir($dir);
+    $hash = sha1($_GET['html']);
+    foreach ($styles as $i => $style) {
+        file_put_contents($name = $dir . $hash . "_$i");
+        echo '';
+    }
+?>
+
+
+  
+ +
+ + +]]>
+

+ Warning: It is possible for a user to mount an + imagecrash attack using this CSS. Counter-measures are difficult; + it is not simply enough to limit the range of CSS lengths (using + relative lengths with many nesting levels allows for large values + to be attained without actually specifying them in the stylesheet), + and the flexible nature of selectors makes it difficult to selectively + disable lengths on image tags (HTML Purifier, however, does disable + CSS width and height in inline styling). There are probably two effective + counter measures: an explicit width and height set to auto in all + images in your document (unlikely) or the disabling of width and + height (somewhat reasonable). Whether or not these measures should be + used is left to the reader. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt new file mode 100644 index 0000000..321eaa2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt @@ -0,0 +1,16 @@ +Filter.YouTube +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ Warning: Deprecated in favor of %HTML.SafeObject and + %Output.FlashCompat (turn both on to allow YouTube videos and other + Flash content). +

+

+ This directive enables YouTube video embedding in HTML Purifier. Check + this document + on embedding videos for more information on what this filter does. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt new file mode 100644 index 0000000..0b2c106 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt @@ -0,0 +1,25 @@ +HTML.Allowed +TYPE: itext/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ This is a preferred convenience directive that combines + %HTML.AllowedElements and %HTML.AllowedAttributes. + Specify elements and attributes that are allowed using: + element1[attr1|attr2],element2.... For example, + if you would like to only allow paragraphs and links, specify + a[href],p. You can specify attributes that apply + to all elements using an asterisk, e.g. *[lang]. + You can also use newlines instead of commas to separate elements. +

+

+ Warning: + All of the constraints on the component directives are still enforced. + The syntax is a subset of TinyMCE's valid_elements + whitelist: directly copy-pasting it here will probably result in + broken whitelists. If %HTML.AllowedElements or %HTML.AllowedAttributes + are set, this directive has no effect. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt new file mode 100644 index 0000000..fcf093f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt @@ -0,0 +1,19 @@ +HTML.AllowedAttributes +TYPE: lookup/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ If HTML Purifier's attribute set is unsatisfactory, overload it! + The syntax is "tag.attr" or "*.attr" for the global attributes + (style, id, class, dir, lang, xml:lang). +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. For + example, %HTML.EnableAttrID will take precedence over *.id in this + directive. You must set that directive to true before you can use + IDs at all. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt new file mode 100644 index 0000000..140e214 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt @@ -0,0 +1,10 @@ +HTML.AllowedComments +TYPE: lookup +VERSION: 4.4.0 +DEFAULT: array() +--DESCRIPTION-- +A whitelist which indicates what explicit comment bodies should be +allowed, modulo leading and trailing whitespace. See also %HTML.AllowedCommentsRegexp +(these directives are union'ed together, so a comment is considered +valid if any directive deems it valid.) +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt new file mode 100644 index 0000000..f22e977 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt @@ -0,0 +1,15 @@ +HTML.AllowedCommentsRegexp +TYPE: string/null +VERSION: 4.4.0 +DEFAULT: NULL +--DESCRIPTION-- +A regexp, which if it matches the body of a comment, indicates that +it should be allowed. Trailing and leading spaces are removed prior +to running this regular expression. +Warning: Make sure you specify +correct anchor metacharacters ^regex$, otherwise you may accept +comments that you did not mean to! In particular, the regex /foo|bar/ +is probably not sufficiently strict, since it also allows foobar. +See also %HTML.AllowedComments (these directives are union'ed together, +so a comment is considered valid if any directive deems it valid.) +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt new file mode 100644 index 0000000..1d3fa79 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt @@ -0,0 +1,23 @@ +HTML.AllowedElements +TYPE: lookup/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ If HTML Purifier's tag set is unsatisfactory for your needs, you can + overload it with your own list of tags to allow. If you change + this, you probably also want to change %HTML.AllowedAttributes; see + also %HTML.Allowed which lets you set allowed elements and + attributes at the same time. +

+

+ If you attempt to allow an element that HTML Purifier does not know + about, HTML Purifier will raise an error. You will need to manually + tell HTML Purifier about this element by using the + advanced customization features. +

+

+ Warning: If another directive conflicts with the + elements here, that directive will win and override. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt new file mode 100644 index 0000000..5a59a55 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt @@ -0,0 +1,20 @@ +HTML.AllowedModules +TYPE: lookup/null +VERSION: 2.0.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ A doctype comes with a set of usual modules to use. Without having + to mucking about with the doctypes, you can quickly activate or + disable these modules by specifying which modules you wish to allow + with this directive. This is most useful for unit testing specific + modules, although end users may find it useful for their own ends. +

+

+ If you specify a module that does not exist, the manager will silently + fail to use it, so be careful! User-defined modules are not affected + by this directive. Modules defined in %HTML.CoreModules are not + affected by this directive. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt new file mode 100644 index 0000000..151fb7b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt @@ -0,0 +1,11 @@ +HTML.Attr.Name.UseCDATA +TYPE: bool +DEFAULT: false +VERSION: 4.0.0 +--DESCRIPTION-- +The W3C specification DTD defines the name attribute to be CDATA, not ID, due +to limitations of DTD. In certain documents, this relaxed behavior is desired, +whether it is to specify duplicate names, or to specify names that would be +illegal IDs (for example, names that begin with a digit.) Set this configuration +directive to true to use the relaxed parsing rules. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt new file mode 100644 index 0000000..45ae469 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt @@ -0,0 +1,18 @@ +HTML.BlockWrapper +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'p' +--DESCRIPTION-- + +

+ String name of element to wrap inline elements that are inside a block + context. This only occurs in the children of blockquote in strict mode. +

+

+ Example: by default value, + <blockquote>Foo</blockquote> would become + <blockquote><p>Foo</p></blockquote>. + The <p> tags can be replaced with whatever you desire, + as long as it is a block level element. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt new file mode 100644 index 0000000..5246188 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt @@ -0,0 +1,23 @@ +HTML.CoreModules +TYPE: lookup +VERSION: 2.0.0 +--DEFAULT-- +array ( + 'Structure' => true, + 'Text' => true, + 'Hypertext' => true, + 'List' => true, + 'NonXMLCommonAttributes' => true, + 'XMLCommonAttributes' => true, + 'CommonAttributes' => true, +) +--DESCRIPTION-- + +

+ Certain modularized doctypes (XHTML, namely), have certain modules + that must be included for the doctype to be an conforming document + type: put those modules here. By default, XHTML's core modules + are used. You can set this to a blank array to disable core module + protection, but this is not recommended. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt new file mode 100644 index 0000000..6ed70b5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt @@ -0,0 +1,9 @@ +HTML.CustomDoctype +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +A custom doctype for power-users who defined their own document +type. This directive only applies when %HTML.Doctype is blank. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt new file mode 100644 index 0000000..103db75 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt @@ -0,0 +1,33 @@ +HTML.DefinitionID +TYPE: string/null +DEFAULT: NULL +VERSION: 2.0.0 +--DESCRIPTION-- + +

+ Unique identifier for a custom-built HTML definition. If you edit + the raw version of the HTMLDefinition, introducing changes that the + configuration object does not reflect, you must specify this variable. + If you change your custom edits, you should change this directive, or + clear your cache. Example: +

+
+$config = HTMLPurifier_Config::createDefault();
+$config->set('HTML', 'DefinitionID', '1');
+$def = $config->getHTMLDefinition();
+$def->addAttribute('a', 'tabindex', 'Number');
+
+

+ In the above example, the configuration is still at the defaults, but + using the advanced API, an extra attribute has been added. The + configuration object normally has no way of knowing that this change + has taken place, so it needs an extra directive: %HTML.DefinitionID. + If someone else attempts to use the default configuration, these two + pieces of code will not clobber each other in the cache, since one has + an extra directive attached to it. +

+

+ You must specify a value to this directive to use the + advanced API features. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt new file mode 100644 index 0000000..229ae02 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt @@ -0,0 +1,16 @@ +HTML.DefinitionRev +TYPE: int +VERSION: 2.0.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition specified in + %HTML.DefinitionID. This serves the same purpose: uniquely identifying + your custom definition, but this one does so in a chronological + context: revision 3 is more up-to-date then revision 2. Thus, when + this gets incremented, the cache handling is smart enough to clean + up any older revisions of your definition as well as flush the + cache. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt new file mode 100644 index 0000000..9dab497 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt @@ -0,0 +1,11 @@ +HTML.Doctype +TYPE: string/null +DEFAULT: NULL +--DESCRIPTION-- +Doctype to use during filtering. Technically speaking this is not actually +a doctype (as it does not identify a corresponding DTD), but we are using +this name for sake of simplicity. When non-blank, this will override any +older directives like %HTML.XHTML or %HTML.Strict. +--ALLOWED-- +'HTML 4.01 Transitional', 'HTML 4.01 Strict', 'XHTML 1.0 Transitional', 'XHTML 1.0 Strict', 'XHTML 1.1' +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt new file mode 100644 index 0000000..7878dc0 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt @@ -0,0 +1,11 @@ +HTML.FlashAllowFullScreen +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit embedded Flash content from + %HTML.SafeObject to expand to the full screen. Corresponds to + the allowFullScreen parameter. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt new file mode 100644 index 0000000..57358f9 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt @@ -0,0 +1,21 @@ +HTML.ForbiddenAttributes +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ While this directive is similar to %HTML.AllowedAttributes, for + forwards-compatibility with XML, this attribute has a different syntax. Instead of + tag.attr, use tag@attr. To disallow href + attributes in a tags, set this directive to + a@href. You can also disallow an attribute globally with + attr or *@attr (either syntax is fine; the latter + is provided for consistency with %HTML.AllowedAttributes). +

+

+ Warning: This directive complements %HTML.ForbiddenElements, + accordingly, check + out that directive for a discussion of why you + should think twice before using this directive. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt new file mode 100644 index 0000000..93a53e1 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt @@ -0,0 +1,20 @@ +HTML.ForbiddenElements +TYPE: lookup +VERSION: 3.1.0 +DEFAULT: array() +--DESCRIPTION-- +

+ This was, perhaps, the most requested feature ever in HTML + Purifier. Please don't abuse it! This is the logical inverse of + %HTML.AllowedElements, and it will override that directive, or any + other directive. +

+

+ If possible, %HTML.Allowed is recommended over this directive, because it + can sometimes be difficult to tell whether or not you've forbidden all of + the behavior you would like to disallow. If you forbid img + with the expectation of preventing images on your site, you'll be in for + a nasty surprise when people start using the background-image + CSS property. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Forms.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Forms.txt new file mode 100644 index 0000000..4a432d8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Forms.txt @@ -0,0 +1,11 @@ +HTML.Forms +TYPE: bool +VERSION: 4.13.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit form elements in the user input, regardless of + %HTML.Trusted value. Please be very careful when using this functionality, as + enabling forms in untrusted documents may allow for phishing attacks. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt new file mode 100644 index 0000000..e424c38 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt @@ -0,0 +1,14 @@ +HTML.MaxImgLength +TYPE: int/null +DEFAULT: 1200 +VERSION: 3.1.1 +--DESCRIPTION-- +

+ This directive controls the maximum number of pixels in the width and + height attributes in img tags. This is + in place to prevent imagecrash attacks, disable with null at your own risk. + This directive is similar to %CSS.MaxImgLength, and both should be + concurrently edited, although there are + subtle differences in the input format (the HTML max is an integer). +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt new file mode 100644 index 0000000..700b309 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt @@ -0,0 +1,7 @@ +HTML.Nofollow +TYPE: bool +VERSION: 4.3.0 +DEFAULT: FALSE +--DESCRIPTION-- +If enabled, nofollow rel attributes are added to all outgoing links. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt new file mode 100644 index 0000000..62e8e16 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt @@ -0,0 +1,12 @@ +HTML.Parent +TYPE: string +VERSION: 1.3.0 +DEFAULT: 'div' +--DESCRIPTION-- + +

+ String name of element that HTML fragment passed to library will be + inserted in. An interesting variation would be using span as the + parent element, meaning that only inline tags would be allowed. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt new file mode 100644 index 0000000..dfb7204 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt @@ -0,0 +1,12 @@ +HTML.Proprietary +TYPE: bool +VERSION: 3.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to allow proprietary elements and attributes in your + documents, as per HTMLPurifier_HTMLModule_Proprietary. + Warning: This can cause your documents to stop + validating! +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt new file mode 100644 index 0000000..cdda09a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt @@ -0,0 +1,13 @@ +HTML.SafeEmbed +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit embed tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to embed tags. Embed is a proprietary + element and will cause your website to stop validating; you should + see if you can use %Output.FlashCompat with %HTML.SafeObject instead + first.

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt new file mode 100644 index 0000000..5eb6ec2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt @@ -0,0 +1,13 @@ +HTML.SafeIframe +TYPE: bool +VERSION: 4.4.0 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit iframe tags in untrusted documents. This + directive must be accompanied by a whitelist of permitted iframes, + such as %URI.SafeIframeRegexp, otherwise it will fatally error. + This directive has no effect on strict doctypes, as iframes are not + valid. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt new file mode 100644 index 0000000..ceb342e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt @@ -0,0 +1,13 @@ +HTML.SafeObject +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Whether or not to permit object tags in documents, with a number of extra + security features added to prevent script execution. This is similar to + what websites like MySpace do to object tags. You should also enable + %Output.FlashCompat in order to generate Internet Explorer + compatibility code for your object tags. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt new file mode 100644 index 0000000..5ebc7a1 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt @@ -0,0 +1,10 @@ +HTML.SafeScripting +TYPE: lookup +VERSION: 4.5.0 +DEFAULT: array() +--DESCRIPTION-- +

+ Whether or not to permit script tags to external scripts in documents. + Inline scripting is not allowed, and the script must match an explicit whitelist. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt new file mode 100644 index 0000000..a8b1de5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt @@ -0,0 +1,9 @@ +HTML.Strict +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not to use Transitional (loose) or Strict rulesets. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt new file mode 100644 index 0000000..587a167 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt @@ -0,0 +1,8 @@ +HTML.TargetBlank +TYPE: bool +VERSION: 4.4.0 +DEFAULT: FALSE +--DESCRIPTION-- +If enabled, target=blank attributes are added to all outgoing links. +(This includes links from an HTTPS version of a page to an HTTP version.) +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt new file mode 100644 index 0000000..dd514c0 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt @@ -0,0 +1,10 @@ +--# vim: et sw=4 sts=4 +HTML.TargetNoopener +TYPE: bool +VERSION: 4.8.0 +DEFAULT: TRUE +--DESCRIPTION-- +If enabled, noopener rel attributes are added to links which have +a target attribute associated with them. This prevents malicious +destinations from overwriting the original window. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt new file mode 100644 index 0000000..cb5a0b0 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoreferrer.txt @@ -0,0 +1,9 @@ +HTML.TargetNoreferrer +TYPE: bool +VERSION: 4.8.0 +DEFAULT: TRUE +--DESCRIPTION-- +If enabled, noreferrer rel attributes are added to links which have +a target attribute associated with them. This prevents malicious +destinations from overwriting the original window. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt new file mode 100644 index 0000000..b4c271b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt @@ -0,0 +1,8 @@ +HTML.TidyAdd +TYPE: lookup +VERSION: 2.0.0 +DEFAULT: array() +--DESCRIPTION-- + +Fixes to add to the default set of Tidy fixes as per your level. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt new file mode 100644 index 0000000..4186ccd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt @@ -0,0 +1,24 @@ +HTML.TidyLevel +TYPE: string +VERSION: 2.0.0 +DEFAULT: 'medium' +--DESCRIPTION-- + +

General level of cleanliness the Tidy module should enforce. +There are four allowed values:

+
+
none
+
No extra tidying should be done
+
light
+
Only fix elements that would be discarded otherwise due to + lack of support in doctype
+
medium
+
Enforce best practices
+
heavy
+
Transform all deprecated elements and attributes to standards + compliant equivalents
+
+ +--ALLOWED-- +'none', 'light', 'medium', 'heavy' +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt new file mode 100644 index 0000000..996762b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt @@ -0,0 +1,8 @@ +HTML.TidyRemove +TYPE: lookup +VERSION: 2.0.0 +DEFAULT: array() +--DESCRIPTION-- + +Fixes to remove from the default set of Tidy fixes as per your level. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt new file mode 100644 index 0000000..1db9237 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt @@ -0,0 +1,9 @@ +HTML.Trusted +TYPE: bool +VERSION: 2.0.0 +DEFAULT: false +--DESCRIPTION-- +Indicates whether or not the user input is trusted or not. If the input is +trusted, a more expansive set of allowed tags and attributes will be used. +See also %CSS.Trusted. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt new file mode 100644 index 0000000..2a47e38 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt @@ -0,0 +1,11 @@ +HTML.XHTML +TYPE: bool +DEFAULT: true +VERSION: 1.1.0 +DEPRECATED-VERSION: 1.7.0 +DEPRECATED-USE: HTML.Doctype +--DESCRIPTION-- +Determines whether or not output is XHTML 1.0 or HTML 4.01 flavor. +--ALIASES-- +Core.XHTML +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt new file mode 100644 index 0000000..08921fd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt @@ -0,0 +1,10 @@ +Output.CommentScriptContents +TYPE: bool +VERSION: 2.0.0 +DEFAULT: true +--DESCRIPTION-- +Determines whether or not HTML Purifier should attempt to fix up the +contents of script tags for legacy browsers with comments. +--ALIASES-- +Core.CommentScriptContents +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt new file mode 100644 index 0000000..d6f0d9f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt @@ -0,0 +1,15 @@ +Output.FixInnerHTML +TYPE: bool +VERSION: 4.3.0 +DEFAULT: true +--DESCRIPTION-- +

+ If true, HTML Purifier will protect against Internet Explorer's + mishandling of the innerHTML attribute by appending + a space to any attribute that does not contain angled brackets, spaces + or quotes, but contains a backtick. This slightly changes the + semantics of any given attribute, so if this is unacceptable and + you do not use innerHTML on any of your pages, you can + turn this directive off. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt new file mode 100644 index 0000000..93398e8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt @@ -0,0 +1,11 @@ +Output.FlashCompat +TYPE: bool +VERSION: 4.1.0 +DEFAULT: false +--DESCRIPTION-- +

+ If true, HTML Purifier will generate Internet Explorer compatibility + code for all object code. This is highly recommended if you enable + %HTML.SafeObject. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt new file mode 100644 index 0000000..79f8ad8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt @@ -0,0 +1,13 @@ +Output.Newline +TYPE: string/null +VERSION: 2.0.1 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Newline string to format final output with. If left null, HTML Purifier + will auto-detect the default newline type of the system and use that; + you can manually override it here. Remember, \r\n is Windows, \r + is Mac, and \n is Unix. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt new file mode 100644 index 0000000..232b023 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt @@ -0,0 +1,14 @@ +Output.SortAttr +TYPE: bool +VERSION: 3.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ If true, HTML Purifier will sort attributes by name before writing them back + to the document, converting a tag like: <el b="" a="" c="" /> + to <el a="" b="" c="" />. This is a workaround for + a bug in FCKeditor which causes it to swap attributes order, adding noise + to text diffs. If you're not seeing this bug, chances are, you don't need + this directive. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt new file mode 100644 index 0000000..06bab00 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt @@ -0,0 +1,25 @@ +Output.TidyFormat +TYPE: bool +VERSION: 1.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ Determines whether or not to run Tidy on the final output for pretty + formatting reasons, such as indentation and wrap. +

+

+ This can greatly improve readability for editors who are hand-editing + the HTML, but is by no means necessary as HTML Purifier has already + fixed all major errors the HTML may have had. Tidy is a non-default + extension, and this directive will silently fail if Tidy is not + available. +

+

+ If you are looking to make the overall look of your page's source + better, I recommend running Tidy on the entire page rather than just + user-content (after all, the indentation relative to the containing + blocks will be incorrect). +

+--ALIASES-- +Core.TidyFormat +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt new file mode 100644 index 0000000..071bc02 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt @@ -0,0 +1,7 @@ +Test.ForceNoIconv +TYPE: bool +DEFAULT: false +--DESCRIPTION-- +When set to true, HTMLPurifier_Encoder will act as if iconv does not exist +and use only pure PHP implementations. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt new file mode 100644 index 0000000..eb97307 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt @@ -0,0 +1,18 @@ +URI.AllowedSchemes +TYPE: lookup +--DEFAULT-- +array ( + 'http' => true, + 'https' => true, + 'mailto' => true, + 'ftp' => true, + 'nntp' => true, + 'news' => true, + 'tel' => true, +) +--DESCRIPTION-- +Whitelist that defines the schemes that a URI is allowed to have. This +prevents XSS attacks from using pseudo-schemes like javascript or mocha. +There is also support for the data and file +URI schemes, but they are not enabled by default. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt new file mode 100644 index 0000000..876f068 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt @@ -0,0 +1,17 @@ +URI.Base +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ The base URI is the URI of the document this purified HTML will be + inserted into. This information is important if HTML Purifier needs + to calculate absolute URIs from relative URIs, such as when %URI.MakeAbsolute + is on. You may use a non-absolute URI for this value, but behavior + may vary (%URI.MakeAbsolute deals nicely with both absolute and + relative paths, but forwards-compatibility is not guaranteed). + Warning: If set, the scheme on this URI + overrides the one specified by %URI.DefaultScheme. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt new file mode 100644 index 0000000..834bc08 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt @@ -0,0 +1,15 @@ +URI.DefaultScheme +TYPE: string/null +DEFAULT: 'http' +--DESCRIPTION-- + +

+ Defines through what scheme the output will be served, in order to + select the proper object validator when no scheme information is present. +

+ +

+ Starting with HTML Purifier 4.9.0, the default scheme can be null, in + which case we reject all URIs which do not have explicit schemes. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt new file mode 100644 index 0000000..f05312b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt @@ -0,0 +1,11 @@ +URI.DefinitionID +TYPE: string/null +VERSION: 2.1.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Unique identifier for a custom-built URI definition. If you want + to add custom URIFilters, you must specify this value. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt new file mode 100644 index 0000000..80cfea9 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt @@ -0,0 +1,11 @@ +URI.DefinitionRev +TYPE: int +VERSION: 2.1.0 +DEFAULT: 1 +--DESCRIPTION-- + +

+ Revision identifier for your custom definition. See + %HTML.DefinitionRev for details. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt new file mode 100644 index 0000000..71ce025 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt @@ -0,0 +1,14 @@ +URI.Disable +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Disables all URIs in all forms. Not sure why you'd want to do that + (after all, the Internet's founded on the notion of a hyperlink). +

+ +--ALIASES-- +Attr.DisableURI +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt new file mode 100644 index 0000000..13c122c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt @@ -0,0 +1,11 @@ +URI.DisableExternal +TYPE: bool +VERSION: 1.2.0 +DEFAULT: false +--DESCRIPTION-- +Disables links to external websites. This is a highly effective anti-spam +and anti-pagerank-leech measure, but comes at a hefty price: nolinks or +images outside of your domain will be allowed. Non-linkified URIs will +still be preserved. If you want to be able to link to subdomains or use +absolute URIs, specify %URI.Host for your website. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt new file mode 100644 index 0000000..abcc1ef --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt @@ -0,0 +1,13 @@ +URI.DisableExternalResources +TYPE: bool +VERSION: 1.3.0 +DEFAULT: false +--DESCRIPTION-- +Disables the embedding of external resources, preventing users from +embedding things like images from other hosts. This prevents access +tracking (good for email viewers), bandwidth leeching, cross-site request +forging, goatse.cx posting, and other nasties, but also results in a loss +of end-user functionality (they can't directly post a pic they posted from +Flickr anymore). Use it if you don't have a robust user-content moderation +team. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt new file mode 100644 index 0000000..f891de4 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt @@ -0,0 +1,15 @@ +URI.DisableResources +TYPE: bool +VERSION: 4.2.0 +DEFAULT: false +--DESCRIPTION-- +

+ Disables embedding resources, essentially meaning no pictures. You can + still link to them though. See %URI.DisableExternalResources for why + this might be a good idea. +

+

+ Note: While this directive has been available since 1.3.0, + it didn't actually start doing anything until 4.2.0. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt new file mode 100644 index 0000000..ee83b12 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt @@ -0,0 +1,19 @@ +URI.Host +TYPE: string/null +VERSION: 1.2.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Defines the domain name of the server, so we can determine whether or + an absolute URI is from your website or not. Not strictly necessary, + as users should be using relative URIs to reference resources on your + website. It will, however, let you use absolute URIs to link to + subdomains of the domain you post here: i.e. example.com will allow + sub.example.com. However, higher up domains will still be excluded: + if you set %URI.Host to sub.example.com, example.com will be blocked. + Note: This directive overrides %URI.Base because + a given page may be on a sub-domain, but you wish HTML Purifier to be + more relaxed and allow some of the parent domains too. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt new file mode 100644 index 0000000..0b6df76 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt @@ -0,0 +1,9 @@ +URI.HostBlacklist +TYPE: list +VERSION: 1.3.0 +DEFAULT: array() +--DESCRIPTION-- +List of strings that are forbidden in the host of any URI. Use it to kill +domain names of spam, etc. Note that it will catch anything in the domain, +so moo.com will catch moo.com.example.com. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt new file mode 100644 index 0000000..4214900 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt @@ -0,0 +1,13 @@ +URI.MakeAbsolute +TYPE: bool +VERSION: 2.1.0 +DEFAULT: false +--DESCRIPTION-- + +

+ Converts all URIs into absolute forms. This is useful when the HTML + being filtered assumes a specific base path, but will actually be + viewed in a different context (and setting an alternate base URI is + not possible). %URI.Base must be set for this directive to work. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt new file mode 100644 index 0000000..58c81dc --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt @@ -0,0 +1,83 @@ +URI.Munge +TYPE: string/null +VERSION: 1.3.0 +DEFAULT: NULL +--DESCRIPTION-- + +

+ Munges all browsable (usually http, https and ftp) + absolute URIs into another URI, usually a URI redirection service. + This directive accepts a URI, formatted with a %s where + the url-encoded original URI should be inserted (sample: + http://www.google.com/url?q=%s). +

+

+ Uses for this directive: +

+
    +
  • + Prevent PageRank leaks, while being fairly transparent + to users (you may also want to add some client side JavaScript to + override the text in the statusbar). Notice: + Many security experts believe that this form of protection does not deter spam-bots. +
  • +
  • + Redirect users to a splash page telling them they are leaving your + website. While this is poor usability practice, it is often mandated + in corporate environments. +
  • +
+

+ Prior to HTML Purifier 3.1.1, this directive also enabled the munging + of browsable external resources, which could break things if your redirection + script was a splash page or used meta tags. To revert to + previous behavior, please use %URI.MungeResources. +

+

+ You may want to also use %URI.MungeSecretKey along with this directive + in order to enforce what URIs your redirector script allows. Open + redirector scripts can be a security risk and negatively affect the + reputation of your domain name. +

+

+ Starting with HTML Purifier 3.1.1, there is also these substitutions: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyDescriptionExample <a href="">
%r1 - The URI embeds a resource
(blank) - The URI is merely a link
%nThe name of the tag this URI came froma
%mThe name of the attribute this URI came fromhref
%pThe name of the CSS property this URI came from, or blank if irrelevant
+

+ Admittedly, these letters are somewhat arbitrary; the only stipulation + was that they couldn't be a through f. r is for resource (I would have preferred + e, but you take what you can get), n is for name, m + was picked because it came after n (and I couldn't use a), p is for + property. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt new file mode 100644 index 0000000..6fce0fd --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt @@ -0,0 +1,17 @@ +URI.MungeResources +TYPE: bool +VERSION: 3.1.1 +DEFAULT: false +--DESCRIPTION-- +

+ If true, any URI munging directives like %URI.Munge + will also apply to embedded resources, such as <img src="">. + Be careful enabling this directive if you have a redirector script + that does not use the Location HTTP header; all of your images + and other embedded resources will break. +

+

+ Warning: It is strongly advised you use this in conjunction + %URI.MungeSecretKey to mitigate the security risk of an open redirector. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt new file mode 100644 index 0000000..1e17c1d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt @@ -0,0 +1,30 @@ +URI.MungeSecretKey +TYPE: string/null +VERSION: 3.1.1 +DEFAULT: NULL +--DESCRIPTION-- +

+ This directive enables secure checksum generation along with %URI.Munge. + It should be set to a secure key that is not shared with anyone else. + The checksum can be placed in the URI using %t. Use of this checksum + affords an additional level of protection by allowing a redirector + to check if a URI has passed through HTML Purifier with this line: +

+ +
$checksum === hash_hmac("sha256", $url, $secret_key)
+ +

+ If the output is TRUE, the redirector script should accept the URI. +

+ +

+ Please note that it would still be possible for an attacker to procure + secure hashes en-mass by abusing your website's Preview feature or the + like, but this service affords an additional level of protection + that should be combined with website blacklisting. +

+ +

+ Remember this has no effect if %URI.Munge is not on. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt new file mode 100644 index 0000000..23331a4 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt @@ -0,0 +1,9 @@ +URI.OverrideAllowedSchemes +TYPE: bool +DEFAULT: true +--DESCRIPTION-- +If this is set to true (which it is by default), you can override +%URI.AllowedSchemes by simply registering a HTMLPurifier_URIScheme to the +registry. If false, you will also have to update that directive in order +to add more schemes. +--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt new file mode 100644 index 0000000..7908483 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt @@ -0,0 +1,22 @@ +URI.SafeIframeRegexp +TYPE: string/null +VERSION: 4.4.0 +DEFAULT: NULL +--DESCRIPTION-- +

+ A PCRE regular expression that will be matched against an iframe URI. This is + a relatively inflexible scheme, but works well enough for the most common + use-case of iframes: embedded video. This directive only has an effect if + %HTML.SafeIframe is enabled. Here are some example values: +

+
    +
  • %^http://www.youtube.com/embed/% - Allow YouTube videos
  • +
  • %^http://player.vimeo.com/video/% - Allow Vimeo videos
  • +
  • %^http://(www.youtube.com/embed/|player.vimeo.com/video/)% - Allow both
  • +
+

+ Note that this directive does not give you enough granularity to, say, disable + all autoplay videos. Pipe up on the HTML Purifier forums if this + is a capability you want. +

+--# vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini new file mode 100644 index 0000000..5de4505 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini @@ -0,0 +1,3 @@ +name = "HTML Purifier" + +; vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php new file mode 100644 index 0000000..543e3f8 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php @@ -0,0 +1,170 @@ + true) indexed by name. + * @type array + * @note This is in HTMLPurifier_HTMLDefinition->info_content_sets + */ + public $lookup = array(); + + /** + * Synchronized list of defined content sets (keys of info). + * @type array + */ + protected $keys = array(); + /** + * Synchronized list of defined content values (values of info). + * @type array + */ + protected $values = array(); + + /** + * Merges in module's content sets, expands identifiers in the content + * sets and populates the keys, values and lookup member variables. + * @param HTMLPurifier_HTMLModule[] $modules List of HTMLPurifier_HTMLModule + */ + public function __construct($modules) + { + if (!is_array($modules)) { + $modules = array($modules); + } + // populate content_sets based on module hints + // sorry, no way of overloading + foreach ($modules as $module) { + foreach ($module->content_sets as $key => $value) { + $temp = $this->convertToLookup($value); + if (isset($this->lookup[$key])) { + // add it into the existing content set + $this->lookup[$key] = array_merge($this->lookup[$key], $temp); + } else { + $this->lookup[$key] = $temp; + } + } + } + $old_lookup = false; + while ($old_lookup !== $this->lookup) { + $old_lookup = $this->lookup; + foreach ($this->lookup as $i => $set) { + $add = array(); + foreach ($set as $element => $x) { + if (isset($this->lookup[$element])) { + $add += $this->lookup[$element]; + unset($this->lookup[$i][$element]); + } + } + $this->lookup[$i] += $add; + } + } + + foreach ($this->lookup as $key => $lookup) { + $this->info[$key] = implode(' | ', array_keys($lookup)); + } + $this->keys = array_keys($this->info); + $this->values = array_values($this->info); + } + + /** + * Accepts a definition; generates and assigns a ChildDef for it + * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef reference + * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef + */ + public function generateChildDef(&$def, $module) + { + if (!empty($def->child)) { // already done! + return; + } + $content_model = $def->content_model; + if (is_string($content_model)) { + // Assume that $this->keys is alphanumeric + $def->content_model = preg_replace_callback( + '/\b(' . implode('|', $this->keys) . ')\b/', + array($this, 'generateChildDefCallback'), + $content_model + ); + //$def->content_model = str_replace( + // $this->keys, $this->values, $content_model); + } + $def->child = $this->getChildDef($def, $module); + } + + public function generateChildDefCallback($matches) + { + return $this->info[$matches[0]]; + } + + /** + * Instantiates a ChildDef based on content_model and content_model_type + * member variables in HTMLPurifier_ElementDef + * @note This will also defer to modules for custom HTMLPurifier_ChildDef + * subclasses that need content set expansion + * @param HTMLPurifier_ElementDef $def HTMLPurifier_ElementDef to have ChildDef extracted + * @param HTMLPurifier_HTMLModule $module Module that defined the ElementDef + * @return HTMLPurifier_ChildDef corresponding to ElementDef + */ + public function getChildDef($def, $module) + { + $value = $def->content_model; + if (is_object($value)) { + trigger_error( + 'Literal object child definitions should be stored in '. + 'ElementDef->child not ElementDef->content_model', + E_USER_NOTICE + ); + return $value; + } + switch ($def->content_model_type) { + case 'required': + return new HTMLPurifier_ChildDef_Required($value); + case 'optional': + return new HTMLPurifier_ChildDef_Optional($value); + case 'empty': + return new HTMLPurifier_ChildDef_Empty(); + case 'custom': + return new HTMLPurifier_ChildDef_Custom($value); + } + // defer to its module + $return = false; + if ($module->defines_child_def) { // save a func call + $return = $module->getChildDef($def); + } + if ($return !== false) { + return $return; + } + // error-out + trigger_error( + 'Could not determine which ChildDef class to instantiate', + E_USER_ERROR + ); + return false; + } + + /** + * Converts a string list of elements separated by pipes into + * a lookup array. + * @param string $string List of elements + * @return array Lookup array of elements + */ + protected function convertToLookup($string) + { + $array = explode('|', str_replace(' ', '', $string)); + $ret = array(); + foreach ($array as $k) { + $ret[$k] = true; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php new file mode 100644 index 0000000..00e509c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php @@ -0,0 +1,95 @@ +_storage)) { + trigger_error( + "Name $name produces collision, cannot re-register", + E_USER_ERROR + ); + return; + } + $this->_storage[$name] =& $ref; + } + + /** + * Retrieves a variable reference from the context. + * @param string $name String name + * @param bool $ignore_error Boolean whether or not to ignore error + * @return mixed + */ + public function &get($name, $ignore_error = false) + { + if (!array_key_exists($name, $this->_storage)) { + if (!$ignore_error) { + trigger_error( + "Attempted to retrieve non-existent variable $name", + E_USER_ERROR + ); + } + $var = null; // so we can return by reference + return $var; + } + return $this->_storage[$name]; + } + + /** + * Destroys a variable in the context. + * @param string $name String name + */ + public function destroy($name) + { + if (!array_key_exists($name, $this->_storage)) { + trigger_error( + "Attempted to destroy non-existent variable $name", + E_USER_ERROR + ); + return; + } + unset($this->_storage[$name]); + } + + /** + * Checks whether or not the variable exists. + * @param string $name String name + * @return bool + */ + public function exists($name) + { + return array_key_exists($name, $this->_storage); + } + + /** + * Loads a series of variables from an associative array + * @param array $context_array Assoc array of variables to load + */ + public function loadArray($context_array) + { + foreach ($context_array as $key => $discard) { + $this->register($key, $context_array[$key]); + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php new file mode 100644 index 0000000..bc6d433 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php @@ -0,0 +1,55 @@ +setup) { + return; + } + $this->setup = true; + $this->doSetup($config); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php new file mode 100644 index 0000000..9aa8ff3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php @@ -0,0 +1,129 @@ +type = $type; + } + + /** + * Generates a unique identifier for a particular configuration + * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config + * @return string + */ + public function generateKey($config) + { + return $config->version . ',' . // possibly replace with function calls + $config->getBatchSerial($this->type) . ',' . + $config->get($this->type . '.DefinitionRev'); + } + + /** + * Tests whether or not a key is old with respect to the configuration's + * version and revision number. + * @param string $key Key to test + * @param HTMLPurifier_Config $config Instance of HTMLPurifier_Config to test against + * @return bool + */ + public function isOld($key, $config) + { + if (substr_count($key, ',') < 2) { + return true; + } + list($version, $hash, $revision) = explode(',', $key, 3); + $compare = version_compare($version, $config->version); + // version mismatch, is always old + if ($compare != 0) { + return true; + } + // versions match, ids match, check revision number + if ($hash == $config->getBatchSerial($this->type) && + $revision < $config->get($this->type . '.DefinitionRev')) { + return true; + } + return false; + } + + /** + * Checks if a definition's type jives with the cache's type + * @note Throws an error on failure + * @param HTMLPurifier_Definition $def Definition object to check + * @return bool true if good, false if not + */ + public function checkDefType($def) + { + if ($def->type !== $this->type) { + trigger_error("Cannot use definition of type {$def->type} in cache for {$this->type}"); + return false; + } + return true; + } + + /** + * Adds a definition object to the cache + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + */ + abstract public function add($def, $config); + + /** + * Unconditionally saves a definition object to the cache + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + */ + abstract public function set($def, $config); + + /** + * Replace an object in the cache + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + */ + abstract public function replace($def, $config); + + /** + * Retrieves a definition object from the cache + * @param HTMLPurifier_Config $config + */ + abstract public function get($config); + + /** + * Removes a definition object to the cache + * @param HTMLPurifier_Config $config + */ + abstract public function remove($config); + + /** + * Clears all objects from cache + * @param HTMLPurifier_Config $config + */ + abstract public function flush($config); + + /** + * Clears all expired (older version or revision) objects from cache + * @note Be careful implementing this method as flush. Flush must + * not interfere with other Definition types, and cleanup() + * should not be repeatedly called by userland code. + * @param HTMLPurifier_Config $config + */ + abstract public function cleanup($config); +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php new file mode 100644 index 0000000..b57a51b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php @@ -0,0 +1,112 @@ +copy(); + // reference is necessary for mocks in PHP 4 + $decorator->cache =& $cache; + $decorator->type = $cache->type; + return $decorator; + } + + /** + * Cross-compatible clone substitute + * @return HTMLPurifier_DefinitionCache_Decorator + */ + public function copy() + { + return new HTMLPurifier_DefinitionCache_Decorator(); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function add($def, $config) + { + return $this->cache->add($def, $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function set($def, $config) + { + return $this->cache->set($def, $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function replace($def, $config) + { + return $this->cache->replace($def, $config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function get($config) + { + return $this->cache->get($config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function remove($config) + { + return $this->cache->remove($config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function flush($config) + { + return $this->cache->flush($config); + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function cleanup($config) + { + return $this->cache->cleanup($config); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php new file mode 100644 index 0000000..4991777 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php @@ -0,0 +1,78 @@ +definitions[$this->generateKey($config)] = $def; + } + return $status; + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function set($def, $config) + { + $status = parent::set($def, $config); + if ($status) { + $this->definitions[$this->generateKey($config)] = $def; + } + return $status; + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function replace($def, $config) + { + $status = parent::replace($def, $config); + if ($status) { + $this->definitions[$this->generateKey($config)] = $def; + } + return $status; + } + + /** + * @param HTMLPurifier_Config $config + * @return mixed + */ + public function get($config) + { + $key = $this->generateKey($config); + if (isset($this->definitions[$key])) { + return $this->definitions[$key]; + } + $this->definitions[$key] = parent::get($config); + return $this->definitions[$key]; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in new file mode 100644 index 0000000..b1fec8d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in @@ -0,0 +1,82 @@ +checkDefType($def)) { + return; + } + $file = $this->generateFilePath($config); + if (file_exists($file)) { + return false; + } + if (!$this->_prepareDir($config)) { + return false; + } + return $this->_write($file, serialize($def), $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return int|bool + */ + public function set($def, $config) + { + if (!$this->checkDefType($def)) { + return; + } + $file = $this->generateFilePath($config); + if (!$this->_prepareDir($config)) { + return false; + } + return $this->_write($file, serialize($def), $config); + } + + /** + * @param HTMLPurifier_Definition $def + * @param HTMLPurifier_Config $config + * @return int|bool + */ + public function replace($def, $config) + { + if (!$this->checkDefType($def)) { + return; + } + $file = $this->generateFilePath($config); + if (!file_exists($file)) { + return false; + } + if (!$this->_prepareDir($config)) { + return false; + } + return $this->_write($file, serialize($def), $config); + } + + /** + * @param HTMLPurifier_Config $config + * @return bool|HTMLPurifier_Config + */ + public function get($config) + { + $file = $this->generateFilePath($config); + if (!file_exists($file)) { + return false; + } + return unserialize(file_get_contents($file)); + } + + /** + * @param HTMLPurifier_Config $config + * @return bool + */ + public function remove($config) + { + $file = $this->generateFilePath($config); + if (!file_exists($file)) { + return false; + } + return unlink($file); + } + + /** + * @param HTMLPurifier_Config $config + * @return bool + */ + public function flush($config) + { + if (!$this->_prepareDir($config)) { + return false; + } + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + // Apparently, on some versions of PHP, readdir will return + // an empty string if you pass an invalid argument to readdir. + // So you need this test. See #49. + if (false === $dh) { + return false; + } + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) { + continue; + } + if ($filename[0] === '.') { + continue; + } + unlink($dir . '/' . $filename); + } + closedir($dh); + return true; + } + + /** + * @param HTMLPurifier_Config $config + * @return bool + */ + public function cleanup($config) + { + if (!$this->_prepareDir($config)) { + return false; + } + $dir = $this->generateDirectoryPath($config); + $dh = opendir($dir); + // See #49 (and above). + if (false === $dh) { + return false; + } + while (false !== ($filename = readdir($dh))) { + if (empty($filename)) { + continue; + } + if ($filename[0] === '.') { + continue; + } + $key = substr($filename, 0, strlen($filename) - 4); + if ($this->isOld($key, $config)) { + unlink($dir . '/' . $filename); + } + } + closedir($dh); + return true; + } + + /** + * Generates the file path to the serial file corresponding to + * the configuration and definition name + * @param HTMLPurifier_Config $config + * @return string + * @todo Make protected + */ + public function generateFilePath($config) + { + $key = $this->generateKey($config); + return $this->generateDirectoryPath($config) . '/' . $key . '.ser'; + } + + /** + * Generates the path to the directory contain this cache's serial files + * @param HTMLPurifier_Config $config + * @return string + * @note No trailing slash + * @todo Make protected + */ + public function generateDirectoryPath($config) + { + $base = $this->generateBaseDirectoryPath($config); + return $base . '/' . $this->type; + } + + /** + * Generates path to base directory that contains all definition type + * serials + * @param HTMLPurifier_Config $config + * @return mixed|string + * @todo Make protected + */ + public function generateBaseDirectoryPath($config) + { + $base = $config->get('Cache.SerializerPath'); + $base = is_null($base) ? HTMLPURIFIER_PREFIX . '/HTMLPurifier/DefinitionCache/Serializer' : $base; + return $base; + } + + /** + * Convenience wrapper function for file_put_contents + * @param string $file File name to write to + * @param string $data Data to write into file + * @param HTMLPurifier_Config $config + * @return int|bool Number of bytes written if success, or false if failure. + */ + private function _write($file, $data, $config) + { + $result = file_put_contents($file, $data); + if ($result !== false) { + // set permissions of the new file (no execute) + $chmod = $config->get('Cache.SerializerPermissions'); + if ($chmod !== null) { + chmod($file, $chmod & 0666); + } + } + return $result; + } + + /** + * Prepares the directory that this type stores the serials in + * @param HTMLPurifier_Config $config + * @return bool True if successful + */ + private function _prepareDir($config) + { + $directory = $this->generateDirectoryPath($config); + $chmod = $config->get('Cache.SerializerPermissions'); + if ($chmod === null) { + if (!@mkdir($directory) && !is_dir($directory)) { + trigger_error( + 'Could not create directory ' . $directory . '', + E_USER_WARNING + ); + return false; + } + return true; + } + if (!is_dir($directory)) { + $base = $this->generateBaseDirectoryPath($config); + if (!is_dir($base)) { + trigger_error( + 'Base directory ' . $base . ' does not exist, + please create or change using %Cache.SerializerPath', + E_USER_WARNING + ); + return false; + } elseif (!$this->_testPermissions($base, $chmod)) { + return false; + } + if (!@mkdir($directory, $chmod) && !is_dir($directory)) { + trigger_error( + 'Could not create directory ' . $directory . '', + E_USER_WARNING + ); + return false; + } + if (!$this->_testPermissions($directory, $chmod)) { + return false; + } + } elseif (!$this->_testPermissions($directory, $chmod)) { + return false; + } + return true; + } + + /** + * Tests permissions on a directory and throws out friendly + * error messages and attempts to chmod it itself if possible + * @param string $dir Directory path + * @param int $chmod Permissions + * @return bool True if directory is writable + */ + private function _testPermissions($dir, $chmod) + { + // early abort, if it is writable, everything is hunky-dory + if (is_writable($dir)) { + return true; + } + if (!is_dir($dir)) { + // generally, you'll want to handle this beforehand + // so a more specific error message can be given + trigger_error( + 'Directory ' . $dir . ' does not exist', + E_USER_WARNING + ); + return false; + } + if (function_exists('posix_getuid') && $chmod !== null) { + // POSIX system, we can give more specific advice + if (fileowner($dir) === posix_getuid()) { + // we can chmod it ourselves + $chmod = $chmod | 0700; + if (chmod($dir, $chmod)) { + return true; + } + } elseif (filegroup($dir) === posix_getgid()) { + $chmod = $chmod | 0070; + } else { + // PHP's probably running as nobody, it is + // not obvious how to fix this (777 is probably + // bad if you are multi-user), let the user figure it out + $chmod = null; + } + trigger_error( + 'Directory ' . $dir . ' not writable. ' . + ($chmod === null ? '' : 'Please chmod to ' . decoct($chmod)), + E_USER_WARNING + ); + } else { + // generic error message + trigger_error( + 'Directory ' . $dir . ' not writable, ' . + 'please alter file permissions', + E_USER_WARNING + ); + } + return false; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README new file mode 100644 index 0000000..2e35c1c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README @@ -0,0 +1,3 @@ +This is a dummy file to prevent Git from ignoring this empty directory. + + vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php new file mode 100644 index 0000000..3a0f461 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php @@ -0,0 +1,106 @@ + array()); + + /** + * @type array + */ + protected $implementations = array(); + + /** + * @type HTMLPurifier_DefinitionCache_Decorator[] + */ + protected $decorators = array(); + + /** + * Initialize default decorators + */ + public function setup() + { + $this->addDecorator('Cleanup'); + } + + /** + * Retrieves an instance of global definition cache factory. + * @param HTMLPurifier_DefinitionCacheFactory $prototype + * @return HTMLPurifier_DefinitionCacheFactory + */ + public static function instance($prototype = null) + { + static $instance; + if ($prototype !== null) { + $instance = $prototype; + } elseif ($instance === null || $prototype === true) { + $instance = new HTMLPurifier_DefinitionCacheFactory(); + $instance->setup(); + } + return $instance; + } + + /** + * Registers a new definition cache object + * @param string $short Short name of cache object, for reference + * @param string $long Full class name of cache object, for construction + */ + public function register($short, $long) + { + $this->implementations[$short] = $long; + } + + /** + * Factory method that creates a cache object based on configuration + * @param string $type Name of definitions handled by cache + * @param HTMLPurifier_Config $config Config instance + * @return mixed + */ + public function create($type, $config) + { + $method = $config->get('Cache.DefinitionImpl'); + if ($method === null) { + return new HTMLPurifier_DefinitionCache_Null($type); + } + if (!empty($this->caches[$method][$type])) { + return $this->caches[$method][$type]; + } + if (isset($this->implementations[$method]) && + class_exists($class = $this->implementations[$method])) { + $cache = new $class($type); + } else { + if ($method != 'Serializer') { + trigger_error("Unrecognized DefinitionCache $method, using Serializer instead", E_USER_WARNING); + } + $cache = new HTMLPurifier_DefinitionCache_Serializer($type); + } + foreach ($this->decorators as $decorator) { + $new_cache = $decorator->decorate($cache); + // prevent infinite recursion in PHP 4 + unset($cache); + $cache = $new_cache; + } + $this->caches[$method][$type] = $cache; + return $this->caches[$method][$type]; + } + + /** + * Registers a decorator to add to all new cache objects + * @param HTMLPurifier_DefinitionCache_Decorator|string $decorator An instance or the name of a decorator + */ + public function addDecorator($decorator) + { + if (is_string($decorator)) { + $class = "HTMLPurifier_DefinitionCache_Decorator_$decorator"; + $decorator = new $class; + } + $this->decorators[$decorator->name] = $decorator; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php new file mode 100644 index 0000000..4acd06e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php @@ -0,0 +1,73 @@ +renderDoctype. + * If structure changes, please update that function. + */ +class HTMLPurifier_Doctype +{ + /** + * Full name of doctype + * @type string + */ + public $name; + + /** + * List of standard modules (string identifiers or literal objects) + * that this doctype uses + * @type array + */ + public $modules = array(); + + /** + * List of modules to use for tidying up code + * @type array + */ + public $tidyModules = array(); + + /** + * Is the language derived from XML (i.e. XHTML)? + * @type bool + */ + public $xml = true; + + /** + * List of aliases for this doctype + * @type array + */ + public $aliases = array(); + + /** + * Public DTD identifier + * @type string + */ + public $dtdPublic; + + /** + * System DTD identifier + * @type string + */ + public $dtdSystem; + + public function __construct( + $name = null, + $xml = true, + $modules = array(), + $tidyModules = array(), + $aliases = array(), + $dtd_public = null, + $dtd_system = null + ) { + $this->name = $name; + $this->xml = $xml; + $this->modules = $modules; + $this->tidyModules = $tidyModules; + $this->aliases = $aliases; + $this->dtdPublic = $dtd_public; + $this->dtdSystem = $dtd_system; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php new file mode 100644 index 0000000..acc1d64 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php @@ -0,0 +1,142 @@ +doctypes[$doctype->name] = $doctype; + $name = $doctype->name; + // hookup aliases + foreach ($doctype->aliases as $alias) { + if (isset($this->doctypes[$alias])) { + continue; + } + $this->aliases[$alias] = $name; + } + // remove old aliases + if (isset($this->aliases[$name])) { + unset($this->aliases[$name]); + } + return $doctype; + } + + /** + * Retrieves reference to a doctype of a certain name + * @note This function resolves aliases + * @note When possible, use the more fully-featured make() + * @param string $doctype Name of doctype + * @return HTMLPurifier_Doctype Editable doctype object + */ + public function get($doctype) + { + if (isset($this->aliases[$doctype])) { + $doctype = $this->aliases[$doctype]; + } + if (!isset($this->doctypes[$doctype])) { + trigger_error('Doctype ' . htmlspecialchars($doctype) . ' does not exist', E_USER_ERROR); + $anon = new HTMLPurifier_Doctype($doctype); + return $anon; + } + return $this->doctypes[$doctype]; + } + + /** + * Creates a doctype based on a configuration object, + * will perform initialization on the doctype + * @note Use this function to get a copy of doctype that config + * can hold on to (this is necessary in order to tell + * Generator whether or not the current document is XML + * based or not). + * @param HTMLPurifier_Config $config + * @return HTMLPurifier_Doctype + */ + public function make($config) + { + return clone $this->get($this->getDoctypeFromConfig($config)); + } + + /** + * Retrieves the doctype from the configuration object + * @param HTMLPurifier_Config $config + * @return string + */ + public function getDoctypeFromConfig($config) + { + // recommended test + $doctype = $config->get('HTML.Doctype'); + if (!empty($doctype)) { + return $doctype; + } + $doctype = $config->get('HTML.CustomDoctype'); + if (!empty($doctype)) { + return $doctype; + } + // backwards-compatibility + if ($config->get('HTML.XHTML')) { + $doctype = 'XHTML 1.0'; + } else { + $doctype = 'HTML 4.01'; + } + if ($config->get('HTML.Strict')) { + $doctype .= ' Strict'; + } else { + $doctype .= ' Transitional'; + } + return $doctype; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php new file mode 100644 index 0000000..57cfd2b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php @@ -0,0 +1,216 @@ +setup(), this array may also + * contain an array at index 0 that indicates which attribute + * collections to load into the full array. It may also + * contain string indentifiers in lieu of HTMLPurifier_AttrDef, + * see HTMLPurifier_AttrTypes on how they are expanded during + * HTMLPurifier_HTMLDefinition->setup() processing. + */ + public $attr = array(); + + // XXX: Design note: currently, it's not possible to override + // previously defined AttrTransforms without messing around with + // the final generated config. This is by design; a previous version + // used an associated list of attr_transform, but it was extremely + // easy to accidentally override other attribute transforms by + // forgetting to specify an index (and just using 0.) While we + // could check this by checking the index number and complaining, + // there is a second problem which is that it is not at all easy to + // tell when something is getting overridden. Combine this with a + // codebase where this isn't really being used, and it's perfect for + // nuking. + + /** + * List of tags HTMLPurifier_AttrTransform to be done before validation. + * @type array + */ + public $attr_transform_pre = array(); + + /** + * List of tags HTMLPurifier_AttrTransform to be done after validation. + * @type array + */ + public $attr_transform_post = array(); + + /** + * HTMLPurifier_ChildDef of this tag. + * @type HTMLPurifier_ChildDef + */ + public $child; + + /** + * Abstract string representation of internal ChildDef rules. + * @see HTMLPurifier_ContentSets for how this is parsed and then transformed + * into an HTMLPurifier_ChildDef. + * @warning This is a temporary variable that is not available after + * being processed by HTMLDefinition + * @type string + */ + public $content_model; + + /** + * Value of $child->type, used to determine which ChildDef to use, + * used in combination with $content_model. + * @warning This must be lowercase + * @warning This is a temporary variable that is not available after + * being processed by HTMLDefinition + * @type string + */ + public $content_model_type; + + /** + * Does the element have a content model (#PCDATA | Inline)*? This + * is important for chameleon ins and del processing in + * HTMLPurifier_ChildDef_Chameleon. Dynamically set: modules don't + * have to worry about this one. + * @type bool + */ + public $descendants_are_inline = false; + + /** + * List of the names of required attributes this element has. + * Dynamically populated by HTMLPurifier_HTMLDefinition::getElement() + * @type array + */ + public $required_attr = array(); + + /** + * Lookup table of tags excluded from all descendants of this tag. + * @type array + * @note SGML permits exclusions for all descendants, but this is + * not possible with DTDs or XML Schemas. W3C has elected to + * use complicated compositions of content_models to simulate + * exclusion for children, but we go the simpler, SGML-style + * route of flat-out exclusions, which correctly apply to + * all descendants and not just children. Note that the XHTML + * Modularization Abstract Modules are blithely unaware of such + * distinctions. + */ + public $excludes = array(); + + /** + * This tag is explicitly auto-closed by the following tags. + * @type array + */ + public $autoclose = array(); + + /** + * If a foreign element is found in this element, test if it is + * allowed by this sub-element; if it is, instead of closing the + * current element, place it inside this element. + * @type string + */ + public $wrap; + + /** + * Whether or not this is a formatting element affected by the + * "Active Formatting Elements" algorithm. + * @type bool + */ + public $formatting; + + /** + * Low-level factory constructor for creating new standalone element defs + */ + public static function create($content_model, $content_model_type, $attr) + { + $def = new HTMLPurifier_ElementDef(); + $def->content_model = $content_model; + $def->content_model_type = $content_model_type; + $def->attr = $attr; + return $def; + } + + /** + * Merges the values of another element definition into this one. + * Values from the new element def take precedence if a value is + * not mergeable. + * @param HTMLPurifier_ElementDef $def + */ + public function mergeIn($def) + { + // later keys takes precedence + foreach ($def->attr as $k => $v) { + if ($k === 0) { + // merge in the includes + // sorry, no way to override an include + foreach ($v as $v2) { + $this->attr[0][] = $v2; + } + continue; + } + if ($v === false) { + if (isset($this->attr[$k])) { + unset($this->attr[$k]); + } + continue; + } + $this->attr[$k] = $v; + } + $this->_mergeAssocArray($this->excludes, $def->excludes); + $this->attr_transform_pre = array_merge($this->attr_transform_pre, $def->attr_transform_pre); + $this->attr_transform_post = array_merge($this->attr_transform_post, $def->attr_transform_post); + + if (!empty($def->content_model)) { + $this->content_model = + str_replace("#SUPER", (string)$this->content_model, $def->content_model); + $this->child = false; + } + if (!empty($def->content_model_type)) { + $this->content_model_type = $def->content_model_type; + $this->child = false; + } + if (!is_null($def->child)) { + $this->child = $def->child; + } + if (!is_null($def->formatting)) { + $this->formatting = $def->formatting; + } + if ($def->descendants_are_inline) { + $this->descendants_are_inline = $def->descendants_are_inline; + } + } + + /** + * Merges one array into another, removes values which equal false + * @param $a1 Array by reference that is merged into + * @param $a2 Array that merges into $a1 + */ + private function _mergeAssocArray(&$a1, $a2) + { + foreach ($a2 as $k => $v) { + if ($v === false) { + if (isset($a1[$k])) { + unset($a1[$k]); + } + continue; + } + $a1[$k] = $v; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php new file mode 100644 index 0000000..d4791cc --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php @@ -0,0 +1,617 @@ += $c) { + $r .= self::unsafeIconv($in, $out, substr($text, $i)); + break; + } + // wibble the boundary + if (0x80 != (0xC0 & ord($text[$i + $max_chunk_size]))) { + $chunk_size = $max_chunk_size; + } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 1]))) { + $chunk_size = $max_chunk_size - 1; + } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 2]))) { + $chunk_size = $max_chunk_size - 2; + } elseif (0x80 != (0xC0 & ord($text[$i + $max_chunk_size - 3]))) { + $chunk_size = $max_chunk_size - 3; + } else { + return false; // rather confusing UTF-8... + } + $chunk = substr($text, $i, $chunk_size); // substr doesn't mind overlong lengths + $r .= self::unsafeIconv($in, $out, $chunk); + $i += $chunk_size; + } + return $r; + } else { + return false; + } + } else { + return false; + } + } + + /** + * Cleans a UTF-8 string for well-formedness and SGML validity + * + * It will parse according to UTF-8 and return a valid UTF8 string, with + * non-SGML codepoints excluded. + * + * Specifically, it will permit: + * \x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF} + * Source: https://www.w3.org/TR/REC-xml/#NT-Char + * Arguably this function should be modernized to the HTML5 set + * of allowed characters: + * https://www.w3.org/TR/html5/syntax.html#preprocessing-the-input-stream + * which simultaneously expand and restrict the set of allowed characters. + * + * @param string $str The string to clean + * @param bool $force_php + * @return string + * + * @note Just for reference, the non-SGML code points are 0 to 31 and + * 127 to 159, inclusive. However, we allow code points 9, 10 + * and 13, which are the tab, line feed and carriage return + * respectively. 128 and above the code points map to multibyte + * UTF-8 representations. + * + * @note Fallback code adapted from utf8ToUnicode by Henri Sivonen and + * hsivonen@iki.fi at under the + * LGPL license. Notes on what changed are inside, but in general, + * the original code transformed UTF-8 text into an array of integer + * Unicode codepoints. Understandably, transforming that back to + * a string would be somewhat expensive, so the function was modded to + * directly operate on the string. However, this discourages code + * reuse, and the logic enumerated here would be useful for any + * function that needs to be able to understand UTF-8 characters. + * As of right now, only smart lossless character encoding converters + * would need that, and I'm probably not going to implement them. + */ + public static function cleanUTF8($str, $force_php = false) + { + // UTF-8 validity is checked since PHP 4.3.5 + // This is an optimization: if the string is already valid UTF-8, no + // need to do PHP stuff. 99% of the time, this will be the case. + if (preg_match( + '/^[\x{9}\x{A}\x{D}\x{20}-\x{7E}\x{A0}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]*$/Du', + $str + )) { + return $str; + } + + $mState = 0; // cached expected number of octets after the current octet + // until the beginning of the next UTF8 character sequence + $mUcs4 = 0; // cached Unicode character + $mBytes = 1; // cached expected number of octets in the current sequence + + // original code involved an $out that was an array of Unicode + // codepoints. Instead of having to convert back into UTF-8, we've + // decided to directly append valid UTF-8 characters onto a string + // $out once they're done. $char accumulates raw bytes, while $mUcs4 + // turns into the Unicode code point, so there's some redundancy. + + $out = ''; + $char = ''; + + $len = strlen($str); + for ($i = 0; $i < $len; $i++) { + $in = ord($str[$i]); + $char .= $str[$i]; // append byte to char + if (0 == $mState) { + // When mState is zero we expect either a US-ASCII character + // or a multi-octet sequence. + if (0 == (0x80 & ($in))) { + // US-ASCII, pass straight through. + if (($in <= 31 || $in == 127) && + !($in == 9 || $in == 13 || $in == 10) // save \r\t\n + ) { + // control characters, remove + } else { + $out .= $char; + } + // reset + $char = ''; + $mBytes = 1; + } elseif (0xC0 == (0xE0 & ($in))) { + // First octet of 2 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x1F) << 6; + $mState = 1; + $mBytes = 2; + } elseif (0xE0 == (0xF0 & ($in))) { + // First octet of 3 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x0F) << 12; + $mState = 2; + $mBytes = 3; + } elseif (0xF0 == (0xF8 & ($in))) { + // First octet of 4 octet sequence + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x07) << 18; + $mState = 3; + $mBytes = 4; + } elseif (0xF8 == (0xFC & ($in))) { + // First octet of 5 octet sequence. + // + // This is illegal because the encoded codepoint must be + // either: + // (a) not the shortest form or + // (b) outside the Unicode range of 0-0x10FFFF. + // Rather than trying to resynchronize, we will carry on + // until the end of the sequence and let the later error + // handling code catch it. + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 0x03) << 24; + $mState = 4; + $mBytes = 5; + } elseif (0xFC == (0xFE & ($in))) { + // First octet of 6 octet sequence, see comments for 5 + // octet sequence. + $mUcs4 = ($in); + $mUcs4 = ($mUcs4 & 1) << 30; + $mState = 5; + $mBytes = 6; + } else { + // Current octet is neither in the US-ASCII range nor a + // legal first octet of a multi-octet sequence. + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char = ''; + } + } else { + // When mState is non-zero, we expect a continuation of the + // multi-octet sequence + if (0x80 == (0xC0 & ($in))) { + // Legal continuation. + $shift = ($mState - 1) * 6; + $tmp = $in; + $tmp = ($tmp & 0x0000003F) << $shift; + $mUcs4 |= $tmp; + + if (0 == --$mState) { + // End of the multi-octet sequence. mUcs4 now contains + // the final Unicode codepoint to be output + + // Check for illegal sequences and codepoints. + + // From Unicode 3.1, non-shortest form is illegal + if (((2 == $mBytes) && ($mUcs4 < 0x0080)) || + ((3 == $mBytes) && ($mUcs4 < 0x0800)) || + ((4 == $mBytes) && ($mUcs4 < 0x10000)) || + (4 < $mBytes) || + // From Unicode 3.2, surrogate characters = illegal + (($mUcs4 & 0xFFFFF800) == 0xD800) || + // Codepoints outside the Unicode range are illegal + ($mUcs4 > 0x10FFFF) + ) { + + } elseif (0xFEFF != $mUcs4 && // omit BOM + // check for valid Char unicode codepoints + ( + 0x9 == $mUcs4 || + 0xA == $mUcs4 || + 0xD == $mUcs4 || + (0x20 <= $mUcs4 && 0x7E >= $mUcs4) || + // 7F-9F is not strictly prohibited by XML, + // but it is non-SGML, and thus we don't allow it + (0xA0 <= $mUcs4 && 0xD7FF >= $mUcs4) || + (0xE000 <= $mUcs4 && 0xFFFD >= $mUcs4) || + (0x10000 <= $mUcs4 && 0x10FFFF >= $mUcs4) + ) + ) { + $out .= $char; + } + // initialize UTF8 cache (reset) + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char = ''; + } + } else { + // ((0xC0 & (*in) != 0x80) && (mState != 0)) + // Incomplete multi-octet sequence. + // used to result in complete fail, but we'll reset + $mState = 0; + $mUcs4 = 0; + $mBytes = 1; + $char =''; + } + } + } + return $out; + } + + /** + * Translates a Unicode codepoint into its corresponding UTF-8 character. + * @note Based on Feyd's function at + * , + * which is in public domain. + * @note While we're going to do code point parsing anyway, a good + * optimization would be to refuse to translate code points that + * are non-SGML characters. However, this could lead to duplication. + * @note This is very similar to the unichr function in + * maintenance/generate-entity-file.php (although this is superior, + * due to its sanity checks). + */ + + // +----------+----------+----------+----------+ + // | 33222222 | 22221111 | 111111 | | + // | 10987654 | 32109876 | 54321098 | 76543210 | bit + // +----------+----------+----------+----------+ + // | | | | 0xxxxxxx | 1 byte 0x00000000..0x0000007F + // | | | 110yyyyy | 10xxxxxx | 2 byte 0x00000080..0x000007FF + // | | 1110zzzz | 10yyyyyy | 10xxxxxx | 3 byte 0x00000800..0x0000FFFF + // | 11110www | 10wwzzzz | 10yyyyyy | 10xxxxxx | 4 byte 0x00010000..0x0010FFFF + // +----------+----------+----------+----------+ + // | 00000000 | 00011111 | 11111111 | 11111111 | Theoretical upper limit of legal scalars: 2097151 (0x001FFFFF) + // | 00000000 | 00010000 | 11111111 | 11111111 | Defined upper limit of legal scalar codes + // +----------+----------+----------+----------+ + + public static function unichr($code) + { + if ($code > 1114111 or $code < 0 or + ($code >= 55296 and $code <= 57343) ) { + // bits are set outside the "valid" range as defined + // by UNICODE 4.1.0 + return ''; + } + + $x = $y = $z = $w = 0; + if ($code < 128) { + // regular ASCII character + $x = $code; + } else { + // set up bits for UTF-8 + $x = ($code & 63) | 128; + if ($code < 2048) { + $y = (($code & 2047) >> 6) | 192; + } else { + $y = (($code & 4032) >> 6) | 128; + if ($code < 65536) { + $z = (($code >> 12) & 15) | 224; + } else { + $z = (($code >> 12) & 63) | 128; + $w = (($code >> 18) & 7) | 240; + } + } + } + // set up the actual character + $ret = ''; + if ($w) { + $ret .= chr($w); + } + if ($z) { + $ret .= chr($z); + } + if ($y) { + $ret .= chr($y); + } + $ret .= chr($x); + + return $ret; + } + + /** + * @return bool + */ + public static function iconvAvailable() + { + static $iconv = null; + if ($iconv === null) { + $iconv = function_exists('iconv') && self::testIconvTruncateBug() != self::ICONV_UNUSABLE; + } + return $iconv; + } + + /** + * Convert a string to UTF-8 based on configuration. + * @param string $str The string to convert + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public static function convertToUTF8($str, $config, $context) + { + $encoding = $config->get('Core.Encoding'); + if ($encoding === 'utf-8') { + return $str; + } + static $iconv = null; + if ($iconv === null) { + $iconv = self::iconvAvailable(); + } + if ($iconv && !$config->get('Test.ForceNoIconv')) { + // unaffected by bugs, since UTF-8 support all characters + $str = self::unsafeIconv($encoding, 'utf-8//IGNORE', $str); + if ($str === false) { + // $encoding is not a valid encoding + trigger_error('Invalid encoding ' . $encoding, E_USER_ERROR); + return ''; + } + // If the string is bjorked by Shift_JIS or a similar encoding + // that doesn't support all of ASCII, convert the naughty + // characters to their true byte-wise ASCII/UTF-8 equivalents. + $str = strtr($str, self::testEncodingSupportsASCII($encoding)); + return $str; + } elseif ($encoding === 'iso-8859-1' && function_exists('mb_convert_encoding')) { + $str = mb_convert_encoding($str, 'UTF-8', 'ISO-8859-1'); + return $str; + } + $bug = HTMLPurifier_Encoder::testIconvTruncateBug(); + if ($bug == self::ICONV_OK) { + trigger_error('Encoding not supported, please install iconv', E_USER_ERROR); + } else { + trigger_error( + 'You have a buggy version of iconv, see https://bugs.php.net/bug.php?id=48147 ' . + 'and http://sourceware.org/bugzilla/show_bug.cgi?id=13541', + E_USER_ERROR + ); + } + } + + /** + * Converts a string from UTF-8 based on configuration. + * @param string $str The string to convert + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + * @note Currently, this is a lossy conversion, with unexpressable + * characters being omitted. + */ + public static function convertFromUTF8($str, $config, $context) + { + $encoding = $config->get('Core.Encoding'); + if ($escape = $config->get('Core.EscapeNonASCIICharacters')) { + $str = self::convertToASCIIDumbLossless($str); + } + if ($encoding === 'utf-8') { + return $str; + } + static $iconv = null; + if ($iconv === null) { + $iconv = self::iconvAvailable(); + } + if ($iconv && !$config->get('Test.ForceNoIconv')) { + // Undo our previous fix in convertToUTF8, otherwise iconv will barf + $ascii_fix = self::testEncodingSupportsASCII($encoding); + if (!$escape && !empty($ascii_fix)) { + $clear_fix = array(); + foreach ($ascii_fix as $utf8 => $native) { + $clear_fix[$utf8] = ''; + } + $str = strtr($str, $clear_fix); + } + $str = strtr($str, array_flip($ascii_fix)); + // Normal stuff + $str = self::iconv('utf-8', $encoding . '//IGNORE', $str); + return $str; + } elseif ($encoding === 'iso-8859-1' && function_exists('mb_convert_encoding')) { + $str = mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8'); + return $str; + } + trigger_error('Encoding not supported', E_USER_ERROR); + // You might be tempted to assume that the ASCII representation + // might be OK, however, this is *not* universally true over all + // encodings. So we take the conservative route here, rather + // than forcibly turn on %Core.EscapeNonASCIICharacters + } + + /** + * Lossless (character-wise) conversion of HTML to ASCII + * @param string $str UTF-8 string to be converted to ASCII + * @return string ASCII encoded string with non-ASCII character entity-ized + * @warning Adapted from MediaWiki, claiming fair use: this is a common + * algorithm. If you disagree with this license fudgery, + * implement it yourself. + * @note Uses decimal numeric entities since they are best supported. + * @note This is a DUMB function: it has no concept of keeping + * character entities that the projected character encoding + * can allow. We could possibly implement a smart version + * but that would require it to also know which Unicode + * codepoints the charset supported (not an easy task). + * @note Sort of with cleanUTF8() but it assumes that $str is + * well-formed UTF-8 + */ + public static function convertToASCIIDumbLossless($str) + { + $bytesleft = 0; + $result = ''; + $working = 0; + $len = strlen($str); + for ($i = 0; $i < $len; $i++) { + $bytevalue = ord($str[$i]); + if ($bytevalue <= 0x7F) { //0xxx xxxx + $result .= chr($bytevalue); + $bytesleft = 0; + } elseif ($bytevalue <= 0xBF) { //10xx xxxx + $working = $working << 6; + $working += ($bytevalue & 0x3F); + $bytesleft--; + if ($bytesleft <= 0) { + $result .= "&#" . $working . ";"; + } + } elseif ($bytevalue <= 0xDF) { //110x xxxx + $working = $bytevalue & 0x1F; + $bytesleft = 1; + } elseif ($bytevalue <= 0xEF) { //1110 xxxx + $working = $bytevalue & 0x0F; + $bytesleft = 2; + } else { //1111 0xxx + $working = $bytevalue & 0x07; + $bytesleft = 3; + } + } + return $result; + } + + /** No bugs detected in iconv. */ + const ICONV_OK = 0; + + /** Iconv truncates output if converting from UTF-8 to another + * character set with //IGNORE, and a non-encodable character is found */ + const ICONV_TRUNCATES = 1; + + /** Iconv does not support //IGNORE, making it unusable for + * transcoding purposes */ + const ICONV_UNUSABLE = 2; + + /** + * glibc iconv has a known bug where it doesn't handle the magic + * //IGNORE stanza correctly. In particular, rather than ignore + * characters, it will return an EILSEQ after consuming some number + * of characters, and expect you to restart iconv as if it were + * an E2BIG. Old versions of PHP did not respect the errno, and + * returned the fragment, so as a result you would see iconv + * mysteriously truncating output. We can work around this by + * manually chopping our input into segments of about 8000 + * characters, as long as PHP ignores the error code. If PHP starts + * paying attention to the error code, iconv becomes unusable. + * + * @return int Error code indicating severity of bug. + */ + public static function testIconvTruncateBug() + { + static $code = null; + if ($code === null) { + // better not use iconv, otherwise infinite loop! + $r = self::unsafeIconv('utf-8', 'ascii//IGNORE', "\xCE\xB1" . str_repeat('a', 9000)); + if ($r === false) { + $code = self::ICONV_UNUSABLE; + } elseif (($c = strlen($r)) < 9000) { + $code = self::ICONV_TRUNCATES; + } elseif ($c > 9000) { + trigger_error( + 'Your copy of iconv is extremely buggy. Please notify HTML Purifier maintainers: ' . + 'include your iconv version as per phpversion()', + E_USER_ERROR + ); + } else { + $code = self::ICONV_OK; + } + } + return $code; + } + + /** + * This expensive function tests whether or not a given character + * encoding supports ASCII. 7/8-bit encodings like Shift_JIS will + * fail this test, and require special processing. Variable width + * encodings shouldn't ever fail. + * + * @param string $encoding Encoding name to test, as per iconv format + * @param bool $bypass Whether or not to bypass the precompiled arrays. + * @return Array of UTF-8 characters to their corresponding ASCII, + * which can be used to "undo" any overzealous iconv action. + */ + public static function testEncodingSupportsASCII($encoding, $bypass = false) + { + // All calls to iconv here are unsafe, proof by case analysis: + // If ICONV_OK, no difference. + // If ICONV_TRUNCATE, all calls involve one character inputs, + // so bug is not triggered. + // If ICONV_UNUSABLE, this call is irrelevant + static $encodings = array(); + if (!$bypass) { + if (isset($encodings[$encoding])) { + return $encodings[$encoding]; + } + $lenc = strtolower($encoding); + switch ($lenc) { + case 'shift_jis': + return array("\xC2\xA5" => '\\', "\xE2\x80\xBE" => '~'); + case 'johab': + return array("\xE2\x82\xA9" => '\\'); + } + if (strpos($lenc, 'iso-8859-') === 0) { + return array(); + } + } + $ret = array(); + if (self::unsafeIconv('UTF-8', $encoding, 'a') === false) { + return false; + } + for ($i = 0x20; $i <= 0x7E; $i++) { // all printable ASCII chars + $c = chr($i); // UTF-8 char + $r = self::unsafeIconv('UTF-8', "$encoding//IGNORE", $c); // initial conversion + if ($r === '' || + // This line is needed for iconv implementations that do not + // omit characters that do not exist in the target character set + ($r === $c && self::unsafeIconv($encoding, 'UTF-8//IGNORE', $r) !== $c) + ) { + // Reverse engineer: what's the UTF-8 equiv of this byte + // sequence? This assumes that there's no variable width + // encoding that doesn't support ASCII. + $ret[self::unsafeIconv($encoding, 'UTF-8//IGNORE', $c)] = $c; + } + } + $encodings[$encoding] = $ret; + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php new file mode 100644 index 0000000..f12ff13 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php @@ -0,0 +1,48 @@ +table = unserialize(file_get_contents($file)); + } + + /** + * Retrieves sole instance of the object. + * @param bool|HTMLPurifier_EntityLookup $prototype Optional prototype of custom lookup table to overload with. + * @return HTMLPurifier_EntityLookup + */ + public static function instance($prototype = false) + { + // no references, since PHP doesn't copy unless modified + static $instance = null; + if ($prototype) { + $instance = $prototype; + } elseif (!$instance) { + $instance = new HTMLPurifier_EntityLookup(); + $instance->setup(); + } + return $instance; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser new file mode 100644 index 0000000..e8b0812 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser @@ -0,0 +1 @@ +a:253:{s:4:"fnof";s:2:"ƒ";s:5:"Alpha";s:2:"Α";s:4:"Beta";s:2:"Β";s:5:"Gamma";s:2:"Γ";s:5:"Delta";s:2:"Δ";s:7:"Epsilon";s:2:"Ε";s:4:"Zeta";s:2:"Ζ";s:3:"Eta";s:2:"Η";s:5:"Theta";s:2:"Θ";s:4:"Iota";s:2:"Ι";s:5:"Kappa";s:2:"Κ";s:6:"Lambda";s:2:"Λ";s:2:"Mu";s:2:"Μ";s:2:"Nu";s:2:"Ν";s:2:"Xi";s:2:"Ξ";s:7:"Omicron";s:2:"Ο";s:2:"Pi";s:2:"Π";s:3:"Rho";s:2:"Ρ";s:5:"Sigma";s:2:"Σ";s:3:"Tau";s:2:"Τ";s:7:"Upsilon";s:2:"Υ";s:3:"Phi";s:2:"Φ";s:3:"Chi";s:2:"Χ";s:3:"Psi";s:2:"Ψ";s:5:"Omega";s:2:"Ω";s:5:"alpha";s:2:"α";s:4:"beta";s:2:"β";s:5:"gamma";s:2:"γ";s:5:"delta";s:2:"δ";s:7:"epsilon";s:2:"ε";s:4:"zeta";s:2:"ζ";s:3:"eta";s:2:"η";s:5:"theta";s:2:"θ";s:4:"iota";s:2:"ι";s:5:"kappa";s:2:"κ";s:6:"lambda";s:2:"λ";s:2:"mu";s:2:"μ";s:2:"nu";s:2:"ν";s:2:"xi";s:2:"ξ";s:7:"omicron";s:2:"ο";s:2:"pi";s:2:"π";s:3:"rho";s:2:"ρ";s:6:"sigmaf";s:2:"ς";s:5:"sigma";s:2:"σ";s:3:"tau";s:2:"τ";s:7:"upsilon";s:2:"υ";s:3:"phi";s:2:"φ";s:3:"chi";s:2:"χ";s:3:"psi";s:2:"ψ";s:5:"omega";s:2:"ω";s:8:"thetasym";s:2:"ϑ";s:5:"upsih";s:2:"ϒ";s:3:"piv";s:2:"ϖ";s:4:"bull";s:3:"•";s:6:"hellip";s:3:"…";s:5:"prime";s:3:"′";s:5:"Prime";s:3:"″";s:5:"oline";s:3:"‾";s:5:"frasl";s:3:"⁄";s:6:"weierp";s:3:"℘";s:5:"image";s:3:"ℑ";s:4:"real";s:3:"ℜ";s:5:"trade";s:3:"™";s:7:"alefsym";s:3:"ℵ";s:4:"larr";s:3:"←";s:4:"uarr";s:3:"↑";s:4:"rarr";s:3:"→";s:4:"darr";s:3:"↓";s:4:"harr";s:3:"↔";s:5:"crarr";s:3:"↵";s:4:"lArr";s:3:"⇐";s:4:"uArr";s:3:"⇑";s:4:"rArr";s:3:"⇒";s:4:"dArr";s:3:"⇓";s:4:"hArr";s:3:"⇔";s:6:"forall";s:3:"∀";s:4:"part";s:3:"∂";s:5:"exist";s:3:"∃";s:5:"empty";s:3:"∅";s:5:"nabla";s:3:"∇";s:4:"isin";s:3:"∈";s:5:"notin";s:3:"∉";s:2:"ni";s:3:"∋";s:4:"prod";s:3:"∏";s:3:"sum";s:3:"∑";s:5:"minus";s:3:"−";s:6:"lowast";s:3:"∗";s:5:"radic";s:3:"√";s:4:"prop";s:3:"∝";s:5:"infin";s:3:"∞";s:3:"ang";s:3:"∠";s:3:"and";s:3:"∧";s:2:"or";s:3:"∨";s:3:"cap";s:3:"∩";s:3:"cup";s:3:"∪";s:3:"int";s:3:"∫";s:6:"there4";s:3:"∴";s:3:"sim";s:3:"∼";s:4:"cong";s:3:"≅";s:5:"asymp";s:3:"≈";s:2:"ne";s:3:"≠";s:5:"equiv";s:3:"≡";s:2:"le";s:3:"≤";s:2:"ge";s:3:"≥";s:3:"sub";s:3:"⊂";s:3:"sup";s:3:"⊃";s:4:"nsub";s:3:"⊄";s:4:"sube";s:3:"⊆";s:4:"supe";s:3:"⊇";s:5:"oplus";s:3:"⊕";s:6:"otimes";s:3:"⊗";s:4:"perp";s:3:"⊥";s:4:"sdot";s:3:"⋅";s:5:"lceil";s:3:"⌈";s:5:"rceil";s:3:"⌉";s:6:"lfloor";s:3:"⌊";s:6:"rfloor";s:3:"⌋";s:4:"lang";s:3:"〈";s:4:"rang";s:3:"〉";s:3:"loz";s:3:"◊";s:6:"spades";s:3:"♠";s:5:"clubs";s:3:"♣";s:6:"hearts";s:3:"♥";s:5:"diams";s:3:"♦";s:4:"quot";s:1:""";s:3:"amp";s:1:"&";s:2:"lt";s:1:"<";s:2:"gt";s:1:">";s:4:"apos";s:1:"'";s:5:"OElig";s:2:"Œ";s:5:"oelig";s:2:"œ";s:6:"Scaron";s:2:"Š";s:6:"scaron";s:2:"š";s:4:"Yuml";s:2:"Ÿ";s:4:"circ";s:2:"ˆ";s:5:"tilde";s:2:"˜";s:4:"ensp";s:3:" ";s:4:"emsp";s:3:" ";s:6:"thinsp";s:3:" ";s:4:"zwnj";s:3:"‌";s:3:"zwj";s:3:"‍";s:3:"lrm";s:3:"‎";s:3:"rlm";s:3:"‏";s:5:"ndash";s:3:"–";s:5:"mdash";s:3:"—";s:5:"lsquo";s:3:"‘";s:5:"rsquo";s:3:"’";s:5:"sbquo";s:3:"‚";s:5:"ldquo";s:3:"“";s:5:"rdquo";s:3:"”";s:5:"bdquo";s:3:"„";s:6:"dagger";s:3:"†";s:6:"Dagger";s:3:"‡";s:6:"permil";s:3:"‰";s:6:"lsaquo";s:3:"‹";s:6:"rsaquo";s:3:"›";s:4:"euro";s:3:"€";s:4:"nbsp";s:2:" ";s:5:"iexcl";s:2:"¡";s:4:"cent";s:2:"¢";s:5:"pound";s:2:"£";s:6:"curren";s:2:"¤";s:3:"yen";s:2:"¥";s:6:"brvbar";s:2:"¦";s:4:"sect";s:2:"§";s:3:"uml";s:2:"¨";s:4:"copy";s:2:"©";s:4:"ordf";s:2:"ª";s:5:"laquo";s:2:"«";s:3:"not";s:2:"¬";s:3:"shy";s:2:"­";s:3:"reg";s:2:"®";s:4:"macr";s:2:"¯";s:3:"deg";s:2:"°";s:6:"plusmn";s:2:"±";s:4:"sup2";s:2:"²";s:4:"sup3";s:2:"³";s:5:"acute";s:2:"´";s:5:"micro";s:2:"µ";s:4:"para";s:2:"¶";s:6:"middot";s:2:"·";s:5:"cedil";s:2:"¸";s:4:"sup1";s:2:"¹";s:4:"ordm";s:2:"º";s:5:"raquo";s:2:"»";s:6:"frac14";s:2:"¼";s:6:"frac12";s:2:"½";s:6:"frac34";s:2:"¾";s:6:"iquest";s:2:"¿";s:6:"Agrave";s:2:"À";s:6:"Aacute";s:2:"Á";s:5:"Acirc";s:2:"Â";s:6:"Atilde";s:2:"Ã";s:4:"Auml";s:2:"Ä";s:5:"Aring";s:2:"Å";s:5:"AElig";s:2:"Æ";s:6:"Ccedil";s:2:"Ç";s:6:"Egrave";s:2:"È";s:6:"Eacute";s:2:"É";s:5:"Ecirc";s:2:"Ê";s:4:"Euml";s:2:"Ë";s:6:"Igrave";s:2:"Ì";s:6:"Iacute";s:2:"Í";s:5:"Icirc";s:2:"Î";s:4:"Iuml";s:2:"Ï";s:3:"ETH";s:2:"Ð";s:6:"Ntilde";s:2:"Ñ";s:6:"Ograve";s:2:"Ò";s:6:"Oacute";s:2:"Ó";s:5:"Ocirc";s:2:"Ô";s:6:"Otilde";s:2:"Õ";s:4:"Ouml";s:2:"Ö";s:5:"times";s:2:"×";s:6:"Oslash";s:2:"Ø";s:6:"Ugrave";s:2:"Ù";s:6:"Uacute";s:2:"Ú";s:5:"Ucirc";s:2:"Û";s:4:"Uuml";s:2:"Ü";s:6:"Yacute";s:2:"Ý";s:5:"THORN";s:2:"Þ";s:5:"szlig";s:2:"ß";s:6:"agrave";s:2:"à";s:6:"aacute";s:2:"á";s:5:"acirc";s:2:"â";s:6:"atilde";s:2:"ã";s:4:"auml";s:2:"ä";s:5:"aring";s:2:"å";s:5:"aelig";s:2:"æ";s:6:"ccedil";s:2:"ç";s:6:"egrave";s:2:"è";s:6:"eacute";s:2:"é";s:5:"ecirc";s:2:"ê";s:4:"euml";s:2:"ë";s:6:"igrave";s:2:"ì";s:6:"iacute";s:2:"í";s:5:"icirc";s:2:"î";s:4:"iuml";s:2:"ï";s:3:"eth";s:2:"ð";s:6:"ntilde";s:2:"ñ";s:6:"ograve";s:2:"ò";s:6:"oacute";s:2:"ó";s:5:"ocirc";s:2:"ô";s:6:"otilde";s:2:"õ";s:4:"ouml";s:2:"ö";s:6:"divide";s:2:"÷";s:6:"oslash";s:2:"ø";s:6:"ugrave";s:2:"ù";s:6:"uacute";s:2:"ú";s:5:"ucirc";s:2:"û";s:4:"uuml";s:2:"ü";s:6:"yacute";s:2:"ý";s:5:"thorn";s:2:"þ";s:4:"yuml";s:2:"ÿ";} \ No newline at end of file diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php new file mode 100644 index 0000000..3ef2d09 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php @@ -0,0 +1,285 @@ +_semiOptionalPrefixRegex = "/&()()()($semi_optional)/"; + + $this->_textEntitiesRegex = + '/&(?:'. + // hex + '[#]x([a-fA-F0-9]+);?|'. + // dec + '[#]0*(\d+);?|'. + // string (mandatory semicolon) + // NB: order matters: match semicolon preferentially + '([A-Za-z_:][A-Za-z0-9.\-_:]*);|'. + // string (optional semicolon) + "($semi_optional)". + ')/'; + + $this->_attrEntitiesRegex = + '/&(?:'. + // hex + '[#]x([a-fA-F0-9]+);?|'. + // dec + '[#]0*(\d+);?|'. + // string (mandatory semicolon) + // NB: order matters: match semicolon preferentially + '([A-Za-z_:][A-Za-z0-9.\-_:]*);|'. + // string (optional semicolon) + // don't match if trailing is equals or alphanumeric (URL + // like) + "($semi_optional)(?![=;A-Za-z0-9])". + ')/'; + + } + + /** + * Substitute entities with the parsed equivalents. Use this on + * textual data in an HTML document (as opposed to attributes.) + * + * @param string $string String to have entities parsed. + * @return string Parsed string. + */ + public function substituteTextEntities($string) + { + return preg_replace_callback( + $this->_textEntitiesRegex, + array($this, 'entityCallback'), + $string + ); + } + + /** + * Substitute entities with the parsed equivalents. Use this on + * attribute contents in documents. + * + * @param string $string String to have entities parsed. + * @return string Parsed string. + */ + public function substituteAttrEntities($string) + { + return preg_replace_callback( + $this->_attrEntitiesRegex, + array($this, 'entityCallback'), + $string + ); + } + + /** + * Callback function for substituteNonSpecialEntities() that does the work. + * + * @param array $matches PCRE matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @return string Replacement string. + */ + + protected function entityCallback($matches) + { + $entity = $matches[0]; + $hex_part = @$matches[1]; + $dec_part = @$matches[2]; + $named_part = empty($matches[3]) ? (empty($matches[4]) ? "" : $matches[4]) : $matches[3]; + if ($hex_part !== NULL && $hex_part !== "") { + return HTMLPurifier_Encoder::unichr(hexdec($hex_part)); + } elseif ($dec_part !== NULL && $dec_part !== "") { + return HTMLPurifier_Encoder::unichr((int) $dec_part); + } else { + if (!$this->_entity_lookup) { + $this->_entity_lookup = HTMLPurifier_EntityLookup::instance(); + } + if (isset($this->_entity_lookup->table[$named_part])) { + return $this->_entity_lookup->table[$named_part]; + } else { + // exact match didn't match anything, so test if + // any of the semicolon optional match the prefix. + // Test that this is an EXACT match is important to + // prevent infinite loop + if (!empty($matches[3])) { + return preg_replace_callback( + $this->_semiOptionalPrefixRegex, + array($this, 'entityCallback'), + $entity + ); + } + return $entity; + } + } + } + + // LEGACY CODE BELOW + + /** + * Callback regex string for parsing entities. + * @type string + */ + protected $_substituteEntitiesRegex = + '/&(?:[#]x([a-fA-F0-9]+)|[#]0*(\d+)|([A-Za-z_:][A-Za-z0-9.\-_:]*));?/'; + // 1. hex 2. dec 3. string (XML style) + + /** + * Decimal to parsed string conversion table for special entities. + * @type array + */ + protected $_special_dec2str = + array( + 34 => '"', + 38 => '&', + 39 => "'", + 60 => '<', + 62 => '>' + ); + + /** + * Stripped entity names to decimal conversion table for special entities. + * @type array + */ + protected $_special_ent2dec = + array( + 'quot' => 34, + 'amp' => 38, + 'lt' => 60, + 'gt' => 62 + ); + + /** + * Substitutes non-special entities with their parsed equivalents. Since + * running this whenever you have parsed character is t3h 5uck, we run + * it before everything else. + * + * @param string $string String to have non-special entities parsed. + * @return string Parsed string. + */ + public function substituteNonSpecialEntities($string) + { + // it will try to detect missing semicolons, but don't rely on it + return preg_replace_callback( + $this->_substituteEntitiesRegex, + array($this, 'nonSpecialEntityCallback'), + $string + ); + } + + /** + * Callback function for substituteNonSpecialEntities() that does the work. + * + * @param array $matches PCRE matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @return string Replacement string. + */ + + protected function nonSpecialEntityCallback($matches) + { + // replaces all but big five + $entity = $matches[0]; + $is_num = (@$matches[0][1] === '#'); + if ($is_num) { + $is_hex = (@$entity[2] === 'x'); + $code = $is_hex ? hexdec($matches[1]) : (int) $matches[2]; + // abort for special characters + if (isset($this->_special_dec2str[$code])) { + return $entity; + } + return HTMLPurifier_Encoder::unichr($code); + } else { + if (isset($this->_special_ent2dec[$matches[3]])) { + return $entity; + } + if (!$this->_entity_lookup) { + $this->_entity_lookup = HTMLPurifier_EntityLookup::instance(); + } + if (isset($this->_entity_lookup->table[$matches[3]])) { + return $this->_entity_lookup->table[$matches[3]]; + } else { + return $entity; + } + } + } + + /** + * Substitutes only special entities with their parsed equivalents. + * + * @notice We try to avoid calling this function because otherwise, it + * would have to be called a lot (for every parsed section). + * + * @param string $string String to have non-special entities parsed. + * @return string Parsed string. + */ + public function substituteSpecialEntities($string) + { + return preg_replace_callback( + $this->_substituteEntitiesRegex, + array($this, 'specialEntityCallback'), + $string + ); + } + + /** + * Callback function for substituteSpecialEntities() that does the work. + * + * This callback has same syntax as nonSpecialEntityCallback(). + * + * @param array $matches PCRE-style matches array, with 0 the entire match, and + * either index 1, 2 or 3 set with a hex value, dec value, + * or string (respectively). + * @return string Replacement string. + */ + protected function specialEntityCallback($matches) + { + $entity = $matches[0]; + $is_num = (@$matches[0][1] === '#'); + if ($is_num) { + $is_hex = (@$entity[2] === 'x'); + $int = $is_hex ? hexdec($matches[1]) : (int) $matches[2]; + return isset($this->_special_dec2str[$int]) ? + $this->_special_dec2str[$int] : + $entity; + } else { + return isset($this->_special_ent2dec[$matches[3]]) ? + $this->_special_dec2str[$this->_special_ent2dec[$matches[3]]] : + $entity; + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php new file mode 100644 index 0000000..d47e3f2 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php @@ -0,0 +1,244 @@ +locale =& $context->get('Locale'); + $this->context = $context; + $this->_current =& $this->_stacks[0]; + $this->errors =& $this->_stacks[0]; + } + + /** + * Sends an error message to the collector for later use + * @param int $severity Error severity, PHP error style (don't use E_USER_) + * @param string $msg Error message text + */ + public function send($severity, $msg) + { + $args = array(); + if (func_num_args() > 2) { + $args = func_get_args(); + array_shift($args); + unset($args[0]); + } + + $token = $this->context->get('CurrentToken', true); + $line = $token ? $token->line : $this->context->get('CurrentLine', true); + $col = $token ? $token->col : $this->context->get('CurrentCol', true); + $attr = $this->context->get('CurrentAttr', true); + + // perform special substitutions, also add custom parameters + $subst = array(); + if (!is_null($token)) { + $args['CurrentToken'] = $token; + } + if (!is_null($attr)) { + $subst['$CurrentAttr.Name'] = $attr; + if (isset($token->attr[$attr])) { + $subst['$CurrentAttr.Value'] = $token->attr[$attr]; + } + } + + if (empty($args)) { + $msg = $this->locale->getMessage($msg); + } else { + $msg = $this->locale->formatMessage($msg, $args); + } + + if (!empty($subst)) { + $msg = strtr($msg, $subst); + } + + // (numerically indexed) + $error = array( + self::LINENO => $line, + self::SEVERITY => $severity, + self::MESSAGE => $msg, + self::CHILDREN => array() + ); + $this->_current[] = $error; + + // NEW CODE BELOW ... + // Top-level errors are either: + // TOKEN type, if $value is set appropriately, or + // "syntax" type, if $value is null + $new_struct = new HTMLPurifier_ErrorStruct(); + $new_struct->type = HTMLPurifier_ErrorStruct::TOKEN; + if ($token) { + $new_struct->value = clone $token; + } + if (is_int($line) && is_int($col)) { + if (isset($this->lines[$line][$col])) { + $struct = $this->lines[$line][$col]; + } else { + $struct = $this->lines[$line][$col] = $new_struct; + } + // These ksorts may present a performance problem + ksort($this->lines[$line], SORT_NUMERIC); + } else { + if (isset($this->lines[-1])) { + $struct = $this->lines[-1]; + } else { + $struct = $this->lines[-1] = $new_struct; + } + } + ksort($this->lines, SORT_NUMERIC); + + // Now, check if we need to operate on a lower structure + if (!empty($attr)) { + $struct = $struct->getChild(HTMLPurifier_ErrorStruct::ATTR, $attr); + if (!$struct->value) { + $struct->value = array($attr, 'PUT VALUE HERE'); + } + } + if (!empty($cssprop)) { + $struct = $struct->getChild(HTMLPurifier_ErrorStruct::CSSPROP, $cssprop); + if (!$struct->value) { + // if we tokenize CSS this might be a little more difficult to do + $struct->value = array($cssprop, 'PUT VALUE HERE'); + } + } + + // Ok, structs are all setup, now time to register the error + $struct->addError($severity, $msg); + } + + /** + * Retrieves raw error data for custom formatter to use + */ + public function getRaw() + { + return $this->errors; + } + + /** + * Default HTML formatting implementation for error messages + * @param HTMLPurifier_Config $config Configuration, vital for HTML output nature + * @param array $errors Errors array to display; used for recursion. + * @return string + */ + public function getHTMLFormatted($config, $errors = null) + { + $ret = array(); + + $this->generator = new HTMLPurifier_Generator($config, $this->context); + if ($errors === null) { + $errors = $this->errors; + } + + // 'At line' message needs to be removed + + // generation code for new structure goes here. It needs to be recursive. + foreach ($this->lines as $line => $col_array) { + if ($line == -1) { + continue; + } + foreach ($col_array as $col => $struct) { + $this->_renderStruct($ret, $struct, $line, $col); + } + } + if (isset($this->lines[-1])) { + $this->_renderStruct($ret, $this->lines[-1]); + } + + if (empty($errors)) { + return '

' . $this->locale->getMessage('ErrorCollector: No errors') . '

'; + } else { + return '
  • ' . implode('
  • ', $ret) . '
'; + } + + } + + private function _renderStruct(&$ret, $struct, $line = null, $col = null) + { + $stack = array($struct); + $context_stack = array(array()); + while ($current = array_pop($stack)) { + $context = array_pop($context_stack); + foreach ($current->errors as $error) { + list($severity, $msg) = $error; + $string = ''; + $string .= '
'; + // W3C uses an icon to indicate the severity of the error. + $error = $this->locale->getErrorName($severity); + $string .= "$error "; + if (!is_null($line) && !is_null($col)) { + $string .= "Line $line, Column $col: "; + } else { + $string .= 'End of Document: '; + } + $string .= '' . $this->generator->escape($msg) . ' '; + $string .= '
'; + // Here, have a marker for the character on the column appropriate. + // Be sure to clip extremely long lines. + //$string .= '
';
+                //$string .= '';
+                //$string .= '
'; + $ret[] = $string; + } + foreach ($current->children as $array) { + $context[] = $current; + $stack = array_merge($stack, array_reverse($array, true)); + for ($i = count($array); $i > 0; $i--) { + $context_stack[] = $context; + } + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php new file mode 100644 index 0000000..cf869d3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php @@ -0,0 +1,74 @@ +children[$type][$id])) { + $this->children[$type][$id] = new HTMLPurifier_ErrorStruct(); + $this->children[$type][$id]->type = $type; + } + return $this->children[$type][$id]; + } + + /** + * @param int $severity + * @param string $message + */ + public function addError($severity, $message) + { + $this->errors[] = array($severity, $message); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php new file mode 100644 index 0000000..be85b4c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php @@ -0,0 +1,12 @@ +preFilter, + * 2->preFilter, 3->preFilter, purify, 3->postFilter, 2->postFilter, + * 1->postFilter. + * + * @note Methods are not declared abstract as it is perfectly legitimate + * for an implementation not to want anything to happen on a step + */ + +class HTMLPurifier_Filter +{ + + /** + * Name of the filter for identification purposes. + * @type string + */ + public $name; + + /** + * Pre-processor function, handles HTML before HTML Purifier + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function preFilter($html, $config, $context) + { + return $html; + } + + /** + * Post-processor function, handles HTML after HTML Purifier + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + return $html; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php new file mode 100644 index 0000000..6f8e779 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php @@ -0,0 +1,345 @@ + blocks from input HTML, cleans them up + * using CSSTidy, and then places them in $purifier->context->get('StyleBlocks') + * so they can be used elsewhere in the document. + * + * @note + * See tests/HTMLPurifier/Filter/ExtractStyleBlocksTest.php for + * sample usage. + * + * @note + * This filter can also be used on stylesheets not included in the + * document--something purists would probably prefer. Just directly + * call HTMLPurifier_Filter_ExtractStyleBlocks->cleanCSS() + */ +class HTMLPurifier_Filter_ExtractStyleBlocks extends HTMLPurifier_Filter +{ + /** + * @type string + */ + public $name = 'ExtractStyleBlocks'; + + /** + * @type array + */ + private $_styleMatches = array(); + + /** + * @type csstidy + */ + private $_tidy; + + /** + * @type HTMLPurifier_AttrDef_HTML_ID + */ + private $_id_attrdef; + + /** + * @type HTMLPurifier_AttrDef_CSS_Ident + */ + private $_class_attrdef; + + /** + * @type HTMLPurifier_AttrDef_Enum + */ + private $_enum_attrdef; + + public function __construct() + { + $this->_tidy = new csstidy(); + $this->_tidy->set_cfg('lowercase_s', false); + $this->_id_attrdef = new HTMLPurifier_AttrDef_HTML_ID(true); + $this->_class_attrdef = new HTMLPurifier_AttrDef_CSS_Ident(); + $this->_enum_attrdef = new HTMLPurifier_AttrDef_Enum( + array( + 'first-child', + 'link', + 'visited', + 'active', + 'hover', + 'focus' + ) + ); + } + + /** + * Save the contents of CSS blocks to style matches + * @param array $matches preg_replace style $matches array + */ + protected function styleCallback($matches) + { + $this->_styleMatches[] = $matches[1]; + } + + /** + * Removes inline + // we must not grab foo in a font-family prop). + if ($config->get('Filter.ExtractStyleBlocks.Escaping')) { + $css = str_replace( + array('<', '>', '&'), + array('\3C ', '\3E ', '\26 '), + $css + ); + } + return $css; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php new file mode 100644 index 0000000..276d836 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php @@ -0,0 +1,65 @@ +]+>.+?' . + '(?:http:)?//www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+).+?#s'; + $pre_replace = '\1'; + return preg_replace($pre_regex, $pre_replace, $html); + } + + /** + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return string + */ + public function postFilter($html, $config, $context) + { + $post_regex = '#((?:v|cp)/[A-Za-z0-9\-_=]+)#'; + return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); + } + + /** + * @param $url + * @return string + */ + protected function armorUrl($url) + { + return str_replace('--', '--', $url); + } + + /** + * @param array $matches + * @return string + */ + protected function postFilterCallback($matches) + { + $url = $this->armorUrl($matches[1]); + return '' . + '' . + '' . + ''; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php new file mode 100644 index 0000000..eb56e2d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php @@ -0,0 +1,286 @@ + tags. + * @type bool + */ + private $_scriptFix = false; + + /** + * Cache of HTMLDefinition during HTML output to determine whether or + * not attributes should be minimized. + * @type HTMLPurifier_HTMLDefinition + */ + private $_def; + + /** + * Cache of %Output.SortAttr. + * @type bool + */ + private $_sortAttr; + + /** + * Cache of %Output.FlashCompat. + * @type bool + */ + private $_flashCompat; + + /** + * Cache of %Output.FixInnerHTML. + * @type bool + */ + private $_innerHTMLFix; + + /** + * Stack for keeping track of object information when outputting IE + * compatibility code. + * @type array + */ + private $_flashStack = array(); + + /** + * Configuration for the generator + * @type HTMLPurifier_Config + */ + protected $config; + + /** + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + */ + public function __construct($config, $context) + { + $this->config = $config; + $this->_scriptFix = $config->get('Output.CommentScriptContents'); + $this->_innerHTMLFix = $config->get('Output.FixInnerHTML'); + $this->_sortAttr = $config->get('Output.SortAttr'); + $this->_flashCompat = $config->get('Output.FlashCompat'); + $this->_def = $config->getHTMLDefinition(); + $this->_xhtml = $this->_def->doctype->xml; + } + + /** + * Generates HTML from an array of tokens. + * @param HTMLPurifier_Token[] $tokens Array of HTMLPurifier_Token + * @return string Generated HTML + */ + public function generateFromTokens($tokens) + { + if (!$tokens) { + return ''; + } + + // Basic algorithm + $html = ''; + for ($i = 0, $size = count($tokens); $i < $size; $i++) { + if ($this->_scriptFix && $tokens[$i]->name === 'script' + && $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) { + // script special case + // the contents of the script block must be ONE token + // for this to work. + $html .= $this->generateFromToken($tokens[$i++]); + $html .= $this->generateScriptFromToken($tokens[$i++]); + } + $html .= $this->generateFromToken($tokens[$i]); + } + + // Tidy cleanup + if (extension_loaded('tidy') && $this->config->get('Output.TidyFormat')) { + $tidy = new Tidy; + $tidy->parseString( + $html, + array( + 'indent'=> true, + 'output-xhtml' => $this->_xhtml, + 'show-body-only' => true, + 'indent-spaces' => 2, + 'wrap' => 68, + ), + 'utf8' + ); + $tidy->cleanRepair(); + $html = (string) $tidy; // explicit cast necessary + } + + // Normalize newlines to system defined value + if ($this->config->get('Core.NormalizeNewlines')) { + $nl = $this->config->get('Output.Newline'); + if ($nl === null) { + $nl = PHP_EOL; + } + if ($nl !== "\n") { + $html = str_replace("\n", $nl, $html); + } + } + return $html; + } + + /** + * Generates HTML from a single token. + * @param HTMLPurifier_Token $token HTMLPurifier_Token object. + * @return string Generated HTML + */ + public function generateFromToken($token) + { + if (!$token instanceof HTMLPurifier_Token) { + trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING); + return ''; + + } elseif ($token instanceof HTMLPurifier_Token_Start) { + $attr = $this->generateAttributes($token->attr, $token->name); + if ($this->_flashCompat) { + if ($token->name == "object") { + $flash = new stdClass(); + $flash->attr = $token->attr; + $flash->param = array(); + $this->_flashStack[] = $flash; + } + } + return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_End) { + $_extra = ''; + if ($this->_flashCompat) { + if ($token->name == "object" && !empty($this->_flashStack)) { + // doesn't do anything for now + } + } + return $_extra . 'name . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + if ($this->_flashCompat && $token->name == "param" && !empty($this->_flashStack)) { + $this->_flashStack[count($this->_flashStack)-1]->param[$token->attr['name']] = $token->attr['value']; + } + $attr = $this->generateAttributes($token->attr, $token->name); + return '<' . $token->name . ($attr ? ' ' : '') . $attr . + ( $this->_xhtml ? ' /': '' ) //
v.
+ . '>'; + + } elseif ($token instanceof HTMLPurifier_Token_Text) { + return $this->escape($token->data, ENT_NOQUOTES); + + } elseif ($token instanceof HTMLPurifier_Token_Comment) { + return ''; + } else { + return ''; + + } + } + + /** + * Special case processor for the contents of script tags + * @param HTMLPurifier_Token $token HTMLPurifier_Token object. + * @return string + * @warning This runs into problems if there's already a literal + * --> somewhere inside the script contents. + */ + public function generateScriptFromToken($token) + { + if (!$token instanceof HTMLPurifier_Token_Text) { + return $this->generateFromToken($token); + } + // Thanks + $data = preg_replace('#//\s*$#', '', $token->data); + return ''; + } + + /** + * Generates attribute declarations from attribute array. + * @note This does not include the leading or trailing space. + * @param array $assoc_array_of_attributes Attribute array + * @param string $element Name of element attributes are for, used to check + * attribute minimization. + * @return string Generated HTML fragment for insertion. + */ + public function generateAttributes($assoc_array_of_attributes, $element = '') + { + $html = ''; + if ($this->_sortAttr) { + ksort($assoc_array_of_attributes); + } + foreach ($assoc_array_of_attributes as $key => $value) { + if (!$this->_xhtml) { + // Remove namespaced attributes + if (strpos($key, ':') !== false) { + continue; + } + // Check if we should minimize the attribute: val="val" -> val + if ($element && !empty($this->_def->info[$element]->attr[$key]->minimized)) { + $html .= $key . ' '; + continue; + } + } + // Workaround for Internet Explorer innerHTML bug. + // Essentially, Internet Explorer, when calculating + // innerHTML, omits quotes if there are no instances of + // angled brackets, quotes or spaces. However, when parsing + // HTML (for example, when you assign to innerHTML), it + // treats backticks as quotes. Thus, + // `` + // becomes + // `` + // becomes + // + // Fortunately, all we need to do is trigger an appropriate + // quoting style, which we do by adding an extra space. + // This also is consistent with the W3C spec, which states + // that user agents may ignore leading or trailing + // whitespace (in fact, most don't, at least for attributes + // like alt, but an extra space at the end is barely + // noticeable). Still, we have a configuration knob for + // this, since this transformation is not necesary if you + // don't process user input with innerHTML or you don't plan + // on supporting Internet Explorer. + if ($this->_innerHTMLFix) { + if (strpos($value, '`') !== false) { + // check if correct quoting style would not already be + // triggered + if (strcspn($value, '"\' <>') === strlen($value)) { + // protect! + $value .= ' '; + } + } + } + $html .= $key.'="'.$this->escape($value).'" '; + } + return rtrim($html); + } + + /** + * Escapes raw text data. + * @todo This really ought to be protected, but until we have a facility + * for properly generating HTML here w/o using tokens, it stays + * public. + * @param string $string String data to escape for HTML. + * @param int $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is + * permissible for non-attribute output. + * @return string escaped data. + */ + public function escape($string, $quote = null) + { + // Workaround for APC bug on Mac Leopard reported by sidepodcast + // http://htmlpurifier.org/phorum/read.php?3,4823,4846 + if ($quote === null) { + $quote = ENT_COMPAT; + } + return htmlspecialchars($string, $quote, 'UTF-8'); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php new file mode 100644 index 0000000..9b7b334 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php @@ -0,0 +1,493 @@ +getAnonymousModule(); + if (!isset($module->info[$element_name])) { + $element = $module->addBlankElement($element_name); + } else { + $element = $module->info[$element_name]; + } + $element->attr[$attr_name] = $def; + } + + /** + * Adds a custom element to your HTML definition + * @see HTMLPurifier_HTMLModule::addElement() for detailed + * parameter and return value descriptions. + */ + public function addElement($element_name, $type, $contents, $attr_collections, $attributes = array()) + { + $module = $this->getAnonymousModule(); + // assume that if the user is calling this, the element + // is safe. This may not be a good idea + $element = $module->addElement($element_name, $type, $contents, $attr_collections, $attributes); + return $element; + } + + /** + * Adds a blank element to your HTML definition, for overriding + * existing behavior + * @param string $element_name + * @return HTMLPurifier_ElementDef + * @see HTMLPurifier_HTMLModule::addBlankElement() for detailed + * parameter and return value descriptions. + */ + public function addBlankElement($element_name) + { + $module = $this->getAnonymousModule(); + $element = $module->addBlankElement($element_name); + return $element; + } + + /** + * Retrieves a reference to the anonymous module, so you can + * bust out advanced features without having to make your own + * module. + * @return HTMLPurifier_HTMLModule + */ + public function getAnonymousModule() + { + if (!$this->_anonModule) { + $this->_anonModule = new HTMLPurifier_HTMLModule(); + $this->_anonModule->name = 'Anonymous'; + } + return $this->_anonModule; + } + + private $_anonModule = null; + + // PUBLIC BUT INTERNAL VARIABLES -------------------------------------- + + /** + * @type string + */ + public $type = 'HTML'; + + /** + * @type HTMLPurifier_HTMLModuleManager + */ + public $manager; + + /** + * Performs low-cost, preliminary initialization. + */ + public function __construct() + { + $this->manager = new HTMLPurifier_HTMLModuleManager(); + } + + /** + * @param HTMLPurifier_Config $config + */ + protected function doSetup($config) + { + $this->processModules($config); + $this->setupConfigStuff($config); + unset($this->manager); + + // cleanup some of the element definitions + foreach ($this->info as $k => $v) { + unset($this->info[$k]->content_model); + unset($this->info[$k]->content_model_type); + } + } + + /** + * Extract out the information from the manager + * @param HTMLPurifier_Config $config + */ + protected function processModules($config) + { + if ($this->_anonModule) { + // for user specific changes + // this is late-loaded so we don't have to deal with PHP4 + // reference wonky-ness + $this->manager->addModule($this->_anonModule); + unset($this->_anonModule); + } + + $this->manager->setup($config); + $this->doctype = $this->manager->doctype; + + foreach ($this->manager->modules as $module) { + foreach ($module->info_tag_transform as $k => $v) { + if ($v === false) { + unset($this->info_tag_transform[$k]); + } else { + $this->info_tag_transform[$k] = $v; + } + } + foreach ($module->info_attr_transform_pre as $k => $v) { + if ($v === false) { + unset($this->info_attr_transform_pre[$k]); + } else { + $this->info_attr_transform_pre[$k] = $v; + } + } + foreach ($module->info_attr_transform_post as $k => $v) { + if ($v === false) { + unset($this->info_attr_transform_post[$k]); + } else { + $this->info_attr_transform_post[$k] = $v; + } + } + foreach ($module->info_injector as $k => $v) { + if ($v === false) { + unset($this->info_injector[$k]); + } else { + $this->info_injector[$k] = $v; + } + } + } + $this->info = $this->manager->getElements(); + $this->info_content_sets = $this->manager->contentSets->lookup; + } + + /** + * Sets up stuff based on config. We need a better way of doing this. + * @param HTMLPurifier_Config $config + */ + protected function setupConfigStuff($config) + { + $block_wrapper = $config->get('HTML.BlockWrapper'); + if (isset($this->info_content_sets['Block'][$block_wrapper])) { + $this->info_block_wrapper = $block_wrapper; + } else { + trigger_error( + 'Cannot use non-block element as block wrapper', + E_USER_ERROR + ); + } + + $parent = $config->get('HTML.Parent'); + $def = $this->manager->getElement($parent, true); + if ($def) { + $this->info_parent = $parent; + $this->info_parent_def = $def; + } else { + trigger_error( + 'Cannot use unrecognized element as parent', + E_USER_ERROR + ); + $this->info_parent_def = $this->manager->getElement($this->info_parent, true); + } + + // support template text + $support = "(for information on implementing this, see the support forums) "; + + // setup allowed elements ----------------------------------------- + + $allowed_elements = $config->get('HTML.AllowedElements'); + $allowed_attributes = $config->get('HTML.AllowedAttributes'); // retrieve early + + if (!is_array($allowed_elements) && !is_array($allowed_attributes)) { + $allowed = $config->get('HTML.Allowed'); + if (is_string($allowed)) { + list($allowed_elements, $allowed_attributes) = $this->parseTinyMCEAllowedList($allowed); + } + } + + if (is_array($allowed_elements)) { + foreach ($this->info as $name => $d) { + if (!isset($allowed_elements[$name])) { + unset($this->info[$name]); + } + unset($allowed_elements[$name]); + } + // emit errors + foreach ($allowed_elements as $element => $d) { + $element = htmlspecialchars($element); // PHP doesn't escape errors, be careful! + trigger_error("Element '$element' is not supported $support", E_USER_WARNING); + } + } + + // setup allowed attributes --------------------------------------- + + $allowed_attributes_mutable = $allowed_attributes; // by copy! + if (is_array($allowed_attributes)) { + // This actually doesn't do anything, since we went away from + // global attributes. It's possible that userland code uses + // it, but HTMLModuleManager doesn't! + foreach ($this->info_global_attr as $attr => $x) { + $keys = array($attr, "*@$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) { + unset($this->info_global_attr[$attr]); + } + } + + foreach ($this->info as $tag => $info) { + foreach ($info->attr as $attr => $x) { + $keys = array("$tag@$attr", $attr, "*@$attr", "$tag.$attr", "*.$attr"); + $delete = true; + foreach ($keys as $key) { + if ($delete && isset($allowed_attributes[$key])) { + $delete = false; + } + if (isset($allowed_attributes_mutable[$key])) { + unset($allowed_attributes_mutable[$key]); + } + } + if ($delete) { + if ($this->info[$tag]->attr[$attr]->required) { + trigger_error( + "Required attribute '$attr' in element '$tag' " . + "was not allowed, which means '$tag' will not be allowed either", + E_USER_WARNING + ); + } + unset($this->info[$tag]->attr[$attr]); + } + } + } + // emit errors + foreach ($allowed_attributes_mutable as $elattr => $d) { + $bits = preg_split('/[.@]/', $elattr, 2); + $c = count($bits); + switch ($c) { + case 2: + if ($bits[0] !== '*') { + $element = htmlspecialchars($bits[0]); + $attribute = htmlspecialchars($bits[1]); + if (!isset($this->info[$element])) { + trigger_error( + "Cannot allow attribute '$attribute' if element " . + "'$element' is not allowed/supported $support" + ); + } else { + trigger_error( + "Attribute '$attribute' in element '$element' not supported $support", + E_USER_WARNING + ); + } + break; + } + // otherwise fall through + case 1: + $attribute = htmlspecialchars($bits[0]); + trigger_error( + "Global attribute '$attribute' is not ". + "supported in any elements $support", + E_USER_WARNING + ); + break; + } + } + } + + // setup forbidden elements --------------------------------------- + + $forbidden_elements = $config->get('HTML.ForbiddenElements'); + $forbidden_attributes = $config->get('HTML.ForbiddenAttributes'); + + foreach ($this->info as $tag => $info) { + if (isset($forbidden_elements[$tag])) { + unset($this->info[$tag]); + continue; + } + foreach ($info->attr as $attr => $x) { + if (isset($forbidden_attributes["$tag@$attr"]) || + isset($forbidden_attributes["*@$attr"]) || + isset($forbidden_attributes[$attr]) + ) { + unset($this->info[$tag]->attr[$attr]); + continue; + } elseif (isset($forbidden_attributes["$tag.$attr"])) { // this segment might get removed eventually + // $tag.$attr are not user supplied, so no worries! + trigger_error( + "Error with $tag.$attr: tag.attr syntax not supported for " . + "HTML.ForbiddenAttributes; use tag@attr instead", + E_USER_WARNING + ); + } + } + } + foreach ($forbidden_attributes as $key => $v) { + if (strlen($key) < 2) { + continue; + } + if ($key[0] != '*') { + continue; + } + if ($key[1] == '.') { + trigger_error( + "Error with $key: *.attr syntax not supported for HTML.ForbiddenAttributes; use attr instead", + E_USER_WARNING + ); + } + } + + // setup injectors ----------------------------------------------------- + foreach ($this->info_injector as $i => $injector) { + if ($injector->checkNeeded($config) !== false) { + // remove injector that does not have it's required + // elements/attributes present, and is thus not needed. + unset($this->info_injector[$i]); + } + } + } + + /** + * Parses a TinyMCE-flavored Allowed Elements and Attributes list into + * separate lists for processing. Format is element[attr1|attr2],element2... + * @warning Although it's largely drawn from TinyMCE's implementation, + * it is different, and you'll probably have to modify your lists + * @param array $list String list to parse + * @return array + * @todo Give this its own class, probably static interface + */ + public function parseTinyMCEAllowedList($list) + { + $list = str_replace(array(' ', "\t"), '', $list); + + $elements = array(); + $attributes = array(); + + $chunks = preg_split('/(,|[\n\r]+)/', $list); + foreach ($chunks as $chunk) { + if (empty($chunk)) { + continue; + } + // remove TinyMCE element control characters + if (!strpos($chunk, '[')) { + $element = $chunk; + $attr = false; + } else { + list($element, $attr) = explode('[', $chunk); + } + if ($element !== '*') { + $elements[$element] = true; + } + if (!$attr) { + continue; + } + $attr = substr($attr, 0, strlen($attr) - 1); // remove trailing ] + $attr = explode('|', $attr); + foreach ($attr as $key) { + $attributes["$element.$key"] = true; + } + } + return array($elements, $attributes); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php new file mode 100644 index 0000000..9dbb987 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php @@ -0,0 +1,285 @@ +info, since the object's data is only info, + * with extra behavior associated with it. + * @type array + */ + public $attr_collections = array(); + + /** + * Associative array of deprecated tag name to HTMLPurifier_TagTransform. + * @type array + */ + public $info_tag_transform = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed before validation. + * @type array + */ + public $info_attr_transform_pre = array(); + + /** + * List of HTMLPurifier_AttrTransform to be performed after validation. + * @type array + */ + public $info_attr_transform_post = array(); + + /** + * List of HTMLPurifier_Injector to be performed during well-formedness fixing. + * An injector will only be invoked if all of it's pre-requisites are met; + * if an injector fails setup, there will be no error; it will simply be + * silently disabled. + * @type array + */ + public $info_injector = array(); + + /** + * Boolean flag that indicates whether or not getChildDef is implemented. + * For optimization reasons: may save a call to a function. Be sure + * to set it if you do implement getChildDef(), otherwise it will have + * no effect! + * @type bool + */ + public $defines_child_def = false; + + /** + * Boolean flag whether or not this module is safe. If it is not safe, all + * of its members are unsafe. Modules are safe by default (this might be + * slightly dangerous, but it doesn't make much sense to force HTML Purifier, + * which is based off of safe HTML, to explicitly say, "This is safe," even + * though there are modules which are "unsafe") + * + * @type bool + * @note Previously, safety could be applied at an element level granularity. + * We've removed this ability, so in order to add "unsafe" elements + * or attributes, a dedicated module with this property set to false + * must be used. + */ + public $safe = true; + + /** + * Retrieves a proper HTMLPurifier_ChildDef subclass based on + * content_model and content_model_type member variables of + * the HTMLPurifier_ElementDef class. There is a similar function + * in HTMLPurifier_HTMLDefinition. + * @param HTMLPurifier_ElementDef $def + * @return HTMLPurifier_ChildDef subclass + */ + public function getChildDef($def) + { + return false; + } + + // -- Convenience ----------------------------------------------------- + + /** + * Convenience function that sets up a new element + * @param string $element Name of element to add + * @param string|bool $type What content set should element be registered to? + * Set as false to skip this step. + * @param string|HTMLPurifier_ChildDef $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @param array|string $attr_includes What attribute collections to register to + * element? + * @param array $attr What unique attributes does the element define? + * @see HTMLPurifier_ElementDef:: for in-depth descriptions of these parameters. + * @return HTMLPurifier_ElementDef Created element definition object, so you + * can set advanced parameters + */ + public function addElement($element, $type, $contents, $attr_includes = array(), $attr = array()) + { + $this->elements[] = $element; + // parse content_model + list($content_model_type, $content_model) = $this->parseContents($contents); + // merge in attribute inclusions + $this->mergeInAttrIncludes($attr, $attr_includes); + // add element to content sets + if ($type) { + $this->addElementToContentSet($element, $type); + } + // create element + $this->info[$element] = HTMLPurifier_ElementDef::create( + $content_model, + $content_model_type, + $attr + ); + // literal object $contents means direct child manipulation + if (!is_string($contents)) { + $this->info[$element]->child = $contents; + } + return $this->info[$element]; + } + + /** + * Convenience function that creates a totally blank, non-standalone + * element. + * @param string $element Name of element to create + * @return HTMLPurifier_ElementDef Created element + */ + public function addBlankElement($element) + { + if (!isset($this->info[$element])) { + $this->elements[] = $element; + $this->info[$element] = new HTMLPurifier_ElementDef(); + $this->info[$element]->standalone = false; + } else { + trigger_error("Definition for $element already exists in module, cannot redefine"); + } + return $this->info[$element]; + } + + /** + * Convenience function that registers an element to a content set + * @param string $element Element to register + * @param string $type Name content set (warning: case sensitive, usually upper-case + * first letter) + */ + public function addElementToContentSet($element, $type) + { + if (!isset($this->content_sets[$type])) { + $this->content_sets[$type] = ''; + } else { + $this->content_sets[$type] .= ' | '; + } + $this->content_sets[$type] .= $element; + } + + /** + * Convenience function that transforms single-string contents + * into separate content model and content model type + * @param string $contents Allowed children in form of: + * "$content_model_type: $content_model" + * @return array + * @note If contents is an object, an array of two nulls will be + * returned, and the callee needs to take the original $contents + * and use it directly. + */ + public function parseContents($contents) + { + if (!is_string($contents)) { + return array(null, null); + } // defer + switch ($contents) { + // check for shorthand content model forms + case 'Empty': + return array('empty', ''); + case 'Inline': + return array('optional', 'Inline | #PCDATA'); + case 'Flow': + return array('optional', 'Flow | #PCDATA'); + } + list($content_model_type, $content_model) = explode(':', $contents); + $content_model_type = strtolower(trim($content_model_type)); + $content_model = trim($content_model); + return array($content_model_type, $content_model); + } + + /** + * Convenience function that merges a list of attribute includes into + * an attribute array. + * @param array $attr Reference to attr array to modify + * @param array $attr_includes Array of includes / string include to merge in + */ + public function mergeInAttrIncludes(&$attr, $attr_includes) + { + if (!is_array($attr_includes)) { + if (empty($attr_includes)) { + $attr_includes = array(); + } else { + $attr_includes = array($attr_includes); + } + } + $attr[0] = $attr_includes; + } + + /** + * Convenience function that generates a lookup table with boolean + * true as value. + * @param string $list List of values to turn into a lookup + * @note You can also pass an arbitrary number of arguments in + * place of the regular argument + * @return array array equivalent of list + */ + public function makeLookup($list) + { + $args = func_get_args(); + if (is_string($list)) { + $list = $args; + } + $ret = array(); + foreach ($list as $value) { + if (is_null($value)) { + continue; + } + $ret[$value] = true; + } + return $ret; + } + + /** + * Lazy load construction of the module after determining whether + * or not it's needed, and also when a finalized configuration object + * is available. + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php new file mode 100644 index 0000000..1e67c79 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php @@ -0,0 +1,44 @@ + array('dir' => false) + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $bdo = $this->addElement( + 'bdo', + 'Inline', + 'Inline', + array('Core', 'Lang'), + array( + 'dir' => 'Enum#ltr,rtl', // required + // The Abstract Module specification has the attribute + // inclusions wrong for bdo: bdo allows Lang + ) + ); + $bdo->attr_transform_post[] = new HTMLPurifier_AttrTransform_BdoDir(); + + $this->attr_collections['I18N']['dir'] = 'Enum#ltr,rtl'; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php new file mode 100644 index 0000000..7220c14 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php @@ -0,0 +1,32 @@ + array( + 0 => array('Style'), + // 'xml:space' => false, + 'class' => 'Class', + 'id' => 'ID', + 'title' => 'CDATA', + 'contenteditable' => 'ContentEditable', + ), + 'Lang' => array(), + 'I18N' => array( + 0 => array('Lang'), // proprietary, for xml:lang/lang + ), + 'Common' => array( + 0 => array('Core', 'I18N') + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php new file mode 100644 index 0000000..a9042a3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php @@ -0,0 +1,55 @@ + 'URI', + // 'datetime' => 'Datetime', // not implemented + ); + $this->addElement('del', 'Inline', $contents, 'Common', $attr); + $this->addElement('ins', 'Inline', $contents, 'Common', $attr); + } + + // HTML 4.01 specifies that ins/del must not contain block + // elements when used in an inline context, chameleon is + // a complicated workaround to acheive this effect + + // Inline context ! Block context (exclamation mark is + // separator, see getChildDef for parsing) + + /** + * @type bool + */ + public $defines_child_def = true; + + /** + * @param HTMLPurifier_ElementDef $def + * @return HTMLPurifier_ChildDef_Chameleon + */ + public function getChildDef($def) + { + if ($def->content_model_type != 'chameleon') { + return false; + } + $value = explode('!', $def->content_model); + return new HTMLPurifier_ChildDef_Chameleon($value[0], $value[1]); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php new file mode 100644 index 0000000..eb0edcf --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php @@ -0,0 +1,194 @@ + 'Form', + 'Inline' => 'Formctrl', + ); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + if ($config->get('HTML.Forms')) { + $this->safe = true; + } + + $form = $this->addElement( + 'form', + 'Form', + 'Required: Heading | List | Block | fieldset', + 'Common', + array( + 'accept' => 'ContentTypes', + 'accept-charset' => 'Charsets', + 'action*' => 'URI', + 'method' => 'Enum#get,post', + // really ContentType, but these two are the only ones used today + 'enctype' => 'Enum#application/x-www-form-urlencoded,multipart/form-data', + ) + ); + $form->excludes = array('form' => true); + + $input = $this->addElement( + 'input', + 'Formctrl', + 'Empty', + 'Common', + array( + 'accept' => 'ContentTypes', + 'accesskey' => 'Character', + 'alt' => 'Text', + 'checked' => 'Bool#checked', + 'disabled' => 'Bool#disabled', + 'maxlength' => 'Number', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'size' => 'Number', + 'src' => 'URI#embedded', + 'tabindex' => 'Number', + 'type' => 'Enum#text,password,checkbox,button,radio,submit,reset,file,hidden,image', + 'value' => 'CDATA', + ) + ); + $input->attr_transform_post[] = new HTMLPurifier_AttrTransform_Input(); + + $this->addElement( + 'select', + 'Formctrl', + 'Required: optgroup | option', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'multiple' => 'Bool#multiple', + 'name' => 'CDATA', + 'size' => 'Number', + 'tabindex' => 'Number', + ) + ); + + $this->addElement( + 'option', + false, + 'Optional: #PCDATA', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'label' => 'Text', + 'selected' => 'Bool#selected', + 'value' => 'CDATA', + ) + ); + // It's illegal for there to be more than one selected, but not + // be multiple. Also, no selected means undefined behavior. This might + // be difficult to implement; perhaps an injector, or a context variable. + + $textarea = $this->addElement( + 'textarea', + 'Formctrl', + 'Optional: #PCDATA', + 'Common', + array( + 'accesskey' => 'Character', + 'cols*' => 'Number', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'readonly' => 'Bool#readonly', + 'rows*' => 'Number', + 'tabindex' => 'Number', + ) + ); + $textarea->attr_transform_pre[] = new HTMLPurifier_AttrTransform_Textarea(); + + $button = $this->addElement( + 'button', + 'Formctrl', + 'Optional: #PCDATA | Heading | List | Block | Inline', + 'Common', + array( + 'accesskey' => 'Character', + 'disabled' => 'Bool#disabled', + 'name' => 'CDATA', + 'tabindex' => 'Number', + 'type' => 'Enum#button,submit,reset', + 'value' => 'CDATA', + ) + ); + + // For exclusions, ideally we'd specify content sets, not literal elements + $button->excludes = $this->makeLookup( + 'form', + 'fieldset', // Form + 'input', + 'select', + 'textarea', + 'label', + 'button', // Formctrl + 'a', // as per HTML 4.01 spec, this is omitted by modularization + 'isindex', + 'iframe' // legacy items + ); + + // Extra exclusion: img usemap="" is not permitted within this element. + // We'll omit this for now, since we don't have any good way of + // indicating it yet. + + // This is HIGHLY user-unfriendly; we need a custom child-def for this + $this->addElement('fieldset', 'Form', 'Custom: (#WS?,legend,(Flow|#PCDATA)*)', 'Common'); + + $label = $this->addElement( + 'label', + 'Formctrl', + 'Optional: #PCDATA | Inline', + 'Common', + array( + 'accesskey' => 'Character', + // 'for' => 'IDREF', // IDREF not implemented, cannot allow + ) + ); + $label->excludes = array('label' => true); + + $this->addElement( + 'legend', + false, + 'Optional: #PCDATA | Inline', + 'Common', + array( + 'accesskey' => 'Character', + ) + ); + + $this->addElement( + 'optgroup', + false, + 'Required: option', + 'Common', + array( + 'disabled' => 'Bool#disabled', + 'label*' => 'Text', + ) + ); + // Don't forget an injector for . This one's a little complex + // because it maps to multiple elements. + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php new file mode 100644 index 0000000..72d7a31 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php @@ -0,0 +1,40 @@ +addElement( + 'a', + 'Inline', + 'Inline', + 'Common', + array( + // 'accesskey' => 'Character', + // 'charset' => 'Charset', + 'href' => 'URI', + // 'hreflang' => 'LanguageCode', + 'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'), + 'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'), + // 'tabindex' => 'Number', + // 'type' => 'ContentType', + ) + ); + $a->formatting = true; + $a->excludes = array('a' => true); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php new file mode 100644 index 0000000..f7e7c91 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php @@ -0,0 +1,51 @@ +get('HTML.SafeIframe')) { + $this->safe = true; + } + $this->addElement( + 'iframe', + 'Inline', + 'Flow', + 'Common', + array( + 'src' => 'URI#embedded', + 'width' => 'Length', + 'height' => 'Length', + 'name' => 'ID', + 'scrolling' => 'Enum#yes,no,auto', + 'frameborder' => 'Enum#0,1', + 'longdesc' => 'URI', + 'marginheight' => 'Pixels', + 'marginwidth' => 'Pixels', + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php new file mode 100644 index 0000000..0f5fdb3 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php @@ -0,0 +1,49 @@ +get('HTML.MaxImgLength'); + $img = $this->addElement( + 'img', + 'Inline', + 'Empty', + 'Common', + array( + 'alt*' => 'Text', + // According to the spec, it's Length, but percents can + // be abused, so we allow only Pixels. + 'height' => 'Pixels#' . $max, + 'width' => 'Pixels#' . $max, + 'longdesc' => 'URI', + 'src*' => new HTMLPurifier_AttrDef_URI(true), // embedded + ) + ); + if ($max === null || $config->get('HTML.Trusted')) { + $img->attr['height'] = + $img->attr['width'] = 'Length'; + } + + // kind of strange, but splitting things up would be inefficient + $img->attr_transform_pre[] = + $img->attr_transform_post[] = + new HTMLPurifier_AttrTransform_ImgRequired(); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php new file mode 100644 index 0000000..86b5299 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php @@ -0,0 +1,186 @@ +addElement( + 'basefont', + 'Inline', + 'Empty', + null, + array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + 'id' => 'ID' + ) + ); + $this->addElement('center', 'Block', 'Flow', 'Common'); + $this->addElement( + 'dir', + 'Block', + 'Required: li', + 'Common', + array( + 'compact' => 'Bool#compact' + ) + ); + $this->addElement( + 'font', + 'Inline', + 'Inline', + array('Core', 'I18N'), + array( + 'color' => 'Color', + 'face' => 'Text', // extremely broad, we should + 'size' => 'Text', // tighten it + ) + ); + $this->addElement( + 'menu', + 'Block', + 'Required: li', + 'Common', + array( + 'compact' => 'Bool#compact' + ) + ); + + $s = $this->addElement('s', 'Inline', 'Inline', 'Common'); + $s->formatting = true; + + $strike = $this->addElement('strike', 'Inline', 'Inline', 'Common'); + $strike->formatting = true; + + $u = $this->addElement('u', 'Inline', 'Inline', 'Common'); + $u->formatting = true; + + // setup modifications to old elements + + $align = 'Enum#left,right,center,justify'; + + $address = $this->addBlankElement('address'); + $address->content_model = 'Inline | #PCDATA | p'; + $address->content_model_type = 'optional'; + $address->child = false; + + $blockquote = $this->addBlankElement('blockquote'); + $blockquote->content_model = 'Flow | #PCDATA'; + $blockquote->content_model_type = 'optional'; + $blockquote->child = false; + + $br = $this->addBlankElement('br'); + $br->attr['clear'] = 'Enum#left,all,right,none'; + + $caption = $this->addBlankElement('caption'); + $caption->attr['align'] = 'Enum#top,bottom,left,right'; + + $div = $this->addBlankElement('div'); + $div->attr['align'] = $align; + + $dl = $this->addBlankElement('dl'); + $dl->attr['compact'] = 'Bool#compact'; + + for ($i = 1; $i <= 6; $i++) { + $h = $this->addBlankElement("h$i"); + $h->attr['align'] = $align; + } + + $hr = $this->addBlankElement('hr'); + $hr->attr['align'] = $align; + $hr->attr['noshade'] = 'Bool#noshade'; + $hr->attr['size'] = 'Pixels'; + $hr->attr['width'] = 'Length'; + + $img = $this->addBlankElement('img'); + $img->attr['align'] = 'IAlign'; + $img->attr['border'] = 'Pixels'; + $img->attr['hspace'] = 'Pixels'; + $img->attr['vspace'] = 'Pixels'; + + // figure out this integer business + + $li = $this->addBlankElement('li'); + $li->attr['value'] = new HTMLPurifier_AttrDef_Integer(); + $li->attr['type'] = 'Enum#s:1,i,I,a,A,disc,square,circle'; + + $ol = $this->addBlankElement('ol'); + $ol->attr['compact'] = 'Bool#compact'; + $ol->attr['start'] = new HTMLPurifier_AttrDef_Integer(); + $ol->attr['type'] = 'Enum#s:1,i,I,a,A'; + + $p = $this->addBlankElement('p'); + $p->attr['align'] = $align; + + $pre = $this->addBlankElement('pre'); + $pre->attr['width'] = 'Number'; + + // script omitted + + $table = $this->addBlankElement('table'); + $table->attr['align'] = 'Enum#left,center,right'; + $table->attr['bgcolor'] = 'Color'; + + $tr = $this->addBlankElement('tr'); + $tr->attr['bgcolor'] = 'Color'; + + $th = $this->addBlankElement('th'); + $th->attr['bgcolor'] = 'Color'; + $th->attr['height'] = 'Length'; + $th->attr['nowrap'] = 'Bool#nowrap'; + $th->attr['width'] = 'Length'; + + $td = $this->addBlankElement('td'); + $td->attr['bgcolor'] = 'Color'; + $td->attr['height'] = 'Length'; + $td->attr['nowrap'] = 'Bool#nowrap'; + $td->attr['width'] = 'Length'; + + $ul = $this->addBlankElement('ul'); + $ul->attr['compact'] = 'Bool#compact'; + $ul->attr['type'] = 'Enum#square,disc,circle'; + + // "safe" modifications to "unsafe" elements + // WARNING: If you want to add support for an unsafe, legacy + // attribute, make a new TrustedLegacy module with the trusted + // bit set appropriately + + $form = $this->addBlankElement('form'); + $form->content_model = 'Flow | #PCDATA'; + $form->content_model_type = 'optional'; + $form->attr['target'] = 'FrameTarget'; + + $input = $this->addBlankElement('input'); + $input->attr['align'] = 'IAlign'; + + $legend = $this->addBlankElement('legend'); + $legend->attr['align'] = 'LAlign'; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php new file mode 100644 index 0000000..7a20ff7 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php @@ -0,0 +1,51 @@ + 'List'); + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $ol = $this->addElement('ol', 'List', new HTMLPurifier_ChildDef_List(), 'Common'); + $ul = $this->addElement('ul', 'List', new HTMLPurifier_ChildDef_List(), 'Common'); + // XXX The wrap attribute is handled by MakeWellFormed. This is all + // quite unsatisfactory, because we generated this + // *specifically* for lists, and now a big chunk of the handling + // is done properly by the List ChildDef. So actually, we just + // want enough information to make autoclosing work properly, + // and then hand off the tricky stuff to the ChildDef. + $ol->wrap = 'li'; + $ul->wrap = 'li'; + $this->addElement('dl', 'List', 'Required: dt | dd', 'Common'); + + $this->addElement('li', false, 'Flow', 'Common'); + + $this->addElement('dd', false, 'Flow', 'Common'); + $this->addElement('dt', false, 'Inline', 'Common'); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php new file mode 100644 index 0000000..60c0545 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php @@ -0,0 +1,26 @@ +addBlankElement($name); + $element->attr['name'] = 'CDATA'; + if (!$config->get('HTML.Attr.Name.UseCDATA')) { + $element->attr_transform_post[] = new HTMLPurifier_AttrTransform_NameSync(); + } + } + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php new file mode 100644 index 0000000..dc9410a --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php @@ -0,0 +1,25 @@ +addBlankElement('a'); + $a->attr_transform_post[] = new HTMLPurifier_AttrTransform_Nofollow(); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php new file mode 100644 index 0000000..da72225 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php @@ -0,0 +1,20 @@ + array( + 'lang' => 'LanguageCode', + ) + ); +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php new file mode 100644 index 0000000..2f9efc5 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php @@ -0,0 +1,62 @@ + to cater to legacy browsers: this + * module does not allow this sort of behavior + */ +class HTMLPurifier_HTMLModule_Object extends HTMLPurifier_HTMLModule +{ + /** + * @type string + */ + public $name = 'Object'; + + /** + * @type bool + */ + public $safe = false; + + /** + * @param HTMLPurifier_Config $config + */ + public function setup($config) + { + $this->addElement( + 'object', + 'Inline', + 'Optional: #PCDATA | Flow | param', + 'Common', + array( + 'archive' => 'URI', + 'classid' => 'URI', + 'codebase' => 'URI', + 'codetype' => 'Text', + 'data' => 'URI', + 'declare' => 'Bool#declare', + 'height' => 'Length', + 'name' => 'CDATA', + 'standby' => 'Text', + 'tabindex' => 'Number', + 'type' => 'ContentType', + 'width' => 'Length' + ) + ); + + $this->addElement( + 'param', + false, + 'Empty', + null, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'type' => 'Text', + 'value' => 'Text', + 'valuetype' => 'Enum#data,ref,object' + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php new file mode 100644 index 0000000..6458ce9 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php @@ -0,0 +1,42 @@ +addElement('hr', 'Block', 'Empty', 'Common'); + $this->addElement('sub', 'Inline', 'Inline', 'Common'); + $this->addElement('sup', 'Inline', 'Inline', 'Common'); + $b = $this->addElement('b', 'Inline', 'Inline', 'Common'); + $b->formatting = true; + $big = $this->addElement('big', 'Inline', 'Inline', 'Common'); + $big->formatting = true; + $i = $this->addElement('i', 'Inline', 'Inline', 'Common'); + $i->formatting = true; + $small = $this->addElement('small', 'Inline', 'Inline', 'Common'); + $small->formatting = true; + $tt = $this->addElement('tt', 'Inline', 'Inline', 'Common'); + $tt->formatting = true; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php new file mode 100644 index 0000000..5ee3c8e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php @@ -0,0 +1,40 @@ +addElement( + 'marquee', + 'Inline', + 'Flow', + 'Common', + array( + 'direction' => 'Enum#left,right,up,down', + 'behavior' => 'Enum#alternate', + 'width' => 'Length', + 'height' => 'Length', + 'scrolldelay' => 'Number', + 'scrollamount' => 'Number', + 'loop' => 'Number', + 'bgcolor' => 'Color', + 'hspace' => 'Pixels', + 'vspace' => 'Pixels', + ) + ); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php new file mode 100644 index 0000000..a0d4892 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php @@ -0,0 +1,36 @@ +addElement( + 'ruby', + 'Inline', + 'Custom: ((rb, (rt | (rp, rt, rp))) | (rbc, rtc, rtc?))', + 'Common' + ); + $this->addElement('rbc', false, 'Required: rb', 'Common'); + $this->addElement('rtc', false, 'Required: rt', 'Common'); + $rb = $this->addElement('rb', false, 'Inline', 'Common'); + $rb->excludes = array('ruby' => true); + $rt = $this->addElement('rt', false, 'Inline', 'Common', array('rbspan' => 'Number')); + $rt->excludes = array('ruby' => true); + $this->addElement('rp', false, 'Optional: #PCDATA', 'Common'); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php new file mode 100644 index 0000000..04e6689 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php @@ -0,0 +1,40 @@ +get('HTML.MaxImgLength'); + $embed = $this->addElement( + 'embed', + 'Inline', + 'Empty', + 'Common', + array( + 'src*' => 'URI#embedded', + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'allowscriptaccess' => 'Enum#never', + 'allownetworking' => 'Enum#internal', + 'flashvars' => 'Text', + 'wmode' => 'Enum#window,transparent,opaque', + 'name' => 'ID', + ) + ); + $embed->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeEmbed(); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php new file mode 100644 index 0000000..1297f80 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php @@ -0,0 +1,62 @@ +get('HTML.MaxImgLength'); + $object = $this->addElement( + 'object', + 'Inline', + 'Optional: param | Flow | #PCDATA', + 'Common', + array( + // While technically not required by the spec, we're forcing + // it to this value. + 'type' => 'Enum#application/x-shockwave-flash', + 'width' => 'Pixels#' . $max, + 'height' => 'Pixels#' . $max, + 'data' => 'URI#embedded', + 'codebase' => new HTMLPurifier_AttrDef_Enum( + array( + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0' + ) + ), + ) + ); + $object->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeObject(); + + $param = $this->addElement( + 'param', + false, + 'Empty', + false, + array( + 'id' => 'ID', + 'name*' => 'Text', + 'value' => 'Text' + ) + ); + $param->attr_transform_post[] = new HTMLPurifier_AttrTransform_SafeParam(); + $this->info_injector[] = 'SafeObject'; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php new file mode 100644 index 0000000..aea7584 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php @@ -0,0 +1,40 @@ +get('HTML.SafeScripting'); + $script = $this->addElement( + 'script', + 'Inline', + 'Optional:', // Not `Empty` to not allow to autoclose the #i', '', $html); + } + + return $html; + } + + /** + * Takes a string of HTML (fragment or document) and returns the content + * @todo Consider making protected + */ + public function extractBody($html) + { + $matches = array(); + $result = preg_match('|(.*?)]*>(.*)|is', $html, $matches); + if ($result) { + // Make sure it's not in a comment + $comment_start = strrpos($matches[1], ''); + if ($comment_start === false || + ($comment_end !== false && $comment_end > $comment_start)) { + return $matches[2]; + } + } + return $html; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php new file mode 100644 index 0000000..5e8104b --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php @@ -0,0 +1,337 @@ +factory = new HTMLPurifier_TokenFactory(); + } + + /** + * @param string $html + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return HTMLPurifier_Token[] + */ + public function tokenizeHTML($html, $config, $context) + { + $html = $this->normalize($html, $config, $context); + + // attempt to armor stray angled brackets that cannot possibly + // form tags and thus are probably being used as emoticons + if ($config->get('Core.AggressivelyFixLt')) { + $char = '[^a-z!\/]'; + $comment = "/|\z)/is"; + $html = preg_replace_callback($comment, array($this, 'callbackArmorCommentEntities'), $html); + do { + $old = $html; + $html = preg_replace("/<($char)/i", '<\\1', $html); + } while ($html !== $old); + $html = preg_replace_callback($comment, array($this, 'callbackUndoCommentSubst'), $html); // fix comments + } + + // preprocess html, essential for UTF-8 + $html = $this->wrapHTML($html, $config, $context); + + $doc = new DOMDocument(); + $doc->encoding = 'UTF-8'; // theoretically, the above has this covered + + $options = 0; + if ($config->get('Core.AllowParseManyTags') && defined('LIBXML_PARSEHUGE')) { + $options |= LIBXML_PARSEHUGE; + } + + set_error_handler(array($this, 'muteErrorHandler')); + // loadHTML() fails on PHP 5.3 when second parameter is given + if ($options) { + $doc->loadHTML($html, $options); + } else { + $doc->loadHTML($html); + } + restore_error_handler(); + + $body = $doc->getElementsByTagName('html')->item(0)-> // + getElementsByTagName('body')->item(0); // + + $div = $body->getElementsByTagName('div')->item(0); //
+ $tokens = array(); + $this->tokenizeDOM($div, $tokens, $config); + // If the div has a sibling, that means we tripped across + // a premature
tag. So remove the div we parsed, + // and then tokenize the rest of body. We can't tokenize + // the sibling directly as we'll lose the tags in that case. + if ($div->nextSibling) { + $body->removeChild($div); + $this->tokenizeDOM($body, $tokens, $config); + } + return $tokens; + } + + /** + * Iterative function that tokenizes a node, putting it into an accumulator. + * To iterate is human, to recurse divine - L. Peter Deutsch + * @param DOMNode $node DOMNode to be tokenized. + * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens. + */ + protected function tokenizeDOM($node, &$tokens, $config) + { + $level = 0; + $nodes = array($level => new HTMLPurifier_Queue(array($node))); + $closingNodes = array(); + do { + while (!$nodes[$level]->isEmpty()) { + $node = $nodes[$level]->shift(); // FIFO + $collect = $level > 0 ? true : false; + $needEndingTag = $this->createStartNode($node, $tokens, $collect, $config); + if ($needEndingTag) { + $closingNodes[$level][] = $node; + } + if ($node->childNodes && $node->childNodes->length) { + $level++; + $nodes[$level] = new HTMLPurifier_Queue(); + foreach ($node->childNodes as $childNode) { + $nodes[$level]->push($childNode); + } + } + } + $level--; + if ($level && isset($closingNodes[$level])) { + while ($node = array_pop($closingNodes[$level])) { + $this->createEndNode($node, $tokens); + } + } + } while ($level > 0); + } + + /** + * Portably retrieve the tag name of a node; deals with older versions + * of libxml like 2.7.6 + * @param DOMNode $node + */ + protected function getTagName($node) + { + if (isset($node->tagName)) { + return $node->tagName; + } else if (isset($node->nodeName)) { + return $node->nodeName; + } else if (isset($node->localName)) { + return $node->localName; + } + return null; + } + + /** + * Portably retrieve the data of a node; deals with older versions + * of libxml like 2.7.6 + * @param DOMNode $node + */ + protected function getData($node) + { + if (isset($node->data)) { + return $node->data; + } else if (isset($node->nodeValue)) { + return $node->nodeValue; + } else if (isset($node->textContent)) { + return $node->textContent; + } + return null; + } + + + /** + * @param DOMNode $node DOMNode to be tokenized. + * @param HTMLPurifier_Token[] $tokens Array-list of already tokenized tokens. + * @param bool $collect Says whether or start and close are collected, set to + * false at first recursion because it's the implicit DIV + * tag you're dealing with. + * @return bool if the token needs an endtoken + * @todo data and tagName properties don't seem to exist in DOMNode? + */ + protected function createStartNode($node, &$tokens, $collect, $config) + { + // intercept non element nodes. WE MUST catch all of them, + // but we're not getting the character reference nodes because + // those should have been preprocessed + if ($node->nodeType === XML_TEXT_NODE) { + $data = $this->getData($node); // Handle variable data property + if ($data !== null) { + $tokens[] = $this->factory->createText($data); + } + return false; + } elseif ($node->nodeType === XML_CDATA_SECTION_NODE) { + // undo libxml's special treatment of )#si', + array($this, 'scriptCallback'), + $html + ); + } + + $html = $this->normalize($html, $config, $context); + + $cursor = 0; // our location in the text + $inside_tag = false; // whether or not we're parsing the inside of a tag + $array = array(); // result array + + // This is also treated to mean maintain *column* numbers too + $maintain_line_numbers = $config->get('Core.MaintainLineNumbers'); + + if ($maintain_line_numbers === null) { + // automatically determine line numbering by checking + // if error collection is on + $maintain_line_numbers = $config->get('Core.CollectErrors'); + } + + if ($maintain_line_numbers) { + $current_line = 1; + $current_col = 0; + $length = strlen($html); + } else { + $current_line = false; + $current_col = false; + $length = false; + } + $context->register('CurrentLine', $current_line); + $context->register('CurrentCol', $current_col); + $nl = "\n"; + // how often to manually recalculate. This will ALWAYS be right, + // but it's pretty wasteful. Set to 0 to turn off + $synchronize_interval = $config->get('Core.DirectLexLineNumberSyncInterval'); + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // for testing synchronization + $loops = 0; + + while (++$loops) { + // $cursor is either at the start of a token, or inside of + // a tag (i.e. there was a < immediately before it), as indicated + // by $inside_tag + + if ($maintain_line_numbers) { + // $rcursor, however, is always at the start of a token. + $rcursor = $cursor - (int)$inside_tag; + + // Column number is cheap, so we calculate it every round. + // We're interested at the *end* of the newline string, so + // we need to add strlen($nl) == 1 to $nl_pos before subtracting it + // from our "rcursor" position. + $nl_pos = strrpos($html, $nl, $rcursor - $length); + $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1); + + // recalculate lines + if ($synchronize_interval && // synchronization is on + $cursor > 0 && // cursor is further than zero + $loops % $synchronize_interval === 0) { // time to synchronize! + $current_line = 1 + $this->substrCount($html, $nl, 0, $cursor); + } + } + + $position_next_lt = strpos($html, '<', $cursor); + $position_next_gt = strpos($html, '>', $cursor); + + // triggers on "asdf" but not "asdf " + // special case to set up context + if ($position_next_lt === $cursor) { + $inside_tag = true; + $cursor++; + } + + if (!$inside_tag && $position_next_lt !== false) { + // We are not inside tag and there still is another tag to parse + $token = new + HTMLPurifier_Token_Text( + $this->parseText( + substr( + $html, + $cursor, + $position_next_lt - $cursor + ), $config + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_lt - $cursor); + } + $array[] = $token; + $cursor = $position_next_lt + 1; + $inside_tag = true; + continue; + } elseif (!$inside_tag) { + // We are not inside tag but there are no more tags + // If we're already at the end, break + if ($cursor === strlen($html)) { + break; + } + // Create Text of rest of string + $token = new + HTMLPurifier_Token_Text( + $this->parseText( + substr( + $html, + $cursor + ), $config + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } + $array[] = $token; + break; + } elseif ($inside_tag && $position_next_gt !== false) { + // We are in tag and it is well formed + // Grab the internals of the tag + $strlen_segment = $position_next_gt - $cursor; + + if ($strlen_segment < 1) { + // there's nothing to process! + $token = new HTMLPurifier_Token_Text('<'); + $cursor++; + continue; + } + + $segment = substr($html, $cursor, $strlen_segment); + + if ($segment === false) { + // somehow, we attempted to access beyond the end of + // the string, defense-in-depth, reported by Nate Abele + break; + } + + // Check if it's a comment + if (substr($segment, 0, 3) === '!--') { + // re-determine segment length, looking for --> + $position_comment_end = strpos($html, '-->', $cursor); + if ($position_comment_end === false) { + // uh oh, we have a comment that extends to + // infinity. Can't be helped: set comment + // end position to end of string + if ($e) { + $e->send(E_WARNING, 'Lexer: Unclosed comment'); + } + $position_comment_end = strlen($html); + $end = true; + } else { + $end = false; + } + $strlen_segment = $position_comment_end - $cursor; + $segment = substr($html, $cursor, $strlen_segment); + $token = new + HTMLPurifier_Token_Comment( + substr( + $segment, + 3, + $strlen_segment - 3 + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $strlen_segment); + } + $array[] = $token; + $cursor = $end ? $position_comment_end : $position_comment_end + 3; + $inside_tag = false; + continue; + } + + // Check if it's an end tag + $is_end_tag = (strpos($segment, '/') === 0); + if ($is_end_tag) { + $type = substr($segment, 1); + $token = new HTMLPurifier_Token_End($type); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Check leading character is alnum, if not, we may + // have accidently grabbed an emoticon. Translate into + // text and go our merry way + if (!ctype_alpha($segment[0])) { + // XML: $segment[0] !== '_' && $segment[0] !== ':' + if ($e) { + $e->send(E_NOTICE, 'Lexer: Unescaped lt'); + } + $token = new HTMLPurifier_Token_Text('<'); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + continue; + } + + // Check if it is explicitly self closing, if so, remove + // trailing slash. Remember, we could have a tag like
, so + // any later token processing scripts must convert improperly + // classified EmptyTags from StartTags. + $is_self_closing = (strrpos($segment, '/') === $strlen_segment - 1); + if ($is_self_closing) { + $strlen_segment--; + $segment = substr($segment, 0, $strlen_segment); + } + + // Check if there are any attributes + $position_first_space = strcspn($segment, $this->_whitespace); + + if ($position_first_space >= $strlen_segment) { + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($segment); + } else { + $token = new HTMLPurifier_Token_Start($segment); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $inside_tag = false; + $cursor = $position_next_gt + 1; + continue; + } + + // Grab out all the data + $type = substr($segment, 0, $position_first_space); + $attribute_string = + trim( + substr( + $segment, + $position_first_space + ) + ); + if ($attribute_string) { + $attr = $this->parseAttributeString( + $attribute_string, + $config, + $context + ); + } else { + $attr = array(); + } + + if ($is_self_closing) { + $token = new HTMLPurifier_Token_Empty($type, $attr); + } else { + $token = new HTMLPurifier_Token_Start($type, $attr); + } + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + $current_line += $this->substrCount($html, $nl, $cursor, $position_next_gt - $cursor); + } + $array[] = $token; + $cursor = $position_next_gt + 1; + $inside_tag = false; + continue; + } else { + // inside tag, but there's no ending > sign + if ($e) { + $e->send(E_WARNING, 'Lexer: Missing gt'); + } + $token = new + HTMLPurifier_Token_Text( + '<' . + $this->parseText( + substr($html, $cursor), $config + ) + ); + if ($maintain_line_numbers) { + $token->rawPosition($current_line, $current_col); + } + // no cursor scroll? Hmm... + $array[] = $token; + break; + } + break; + } + + $context->destroy('CurrentLine'); + $context->destroy('CurrentCol'); + return $array; + } + + /** + * PHP 5.0.x compatible substr_count that implements offset and length + * @param string $haystack + * @param string $needle + * @param int $offset + * @param int $length + * @return int + */ + protected function substrCount($haystack, $needle, $offset, $length) + { + static $oldVersion; + if ($oldVersion === null) { + $oldVersion = version_compare(PHP_VERSION, '5.1', '<'); + } + if ($oldVersion) { + $haystack = substr($haystack, $offset, $length); + return substr_count($haystack, $needle); + } else { + return substr_count($haystack, $needle, $offset, $length); + } + } + + /** + * Takes the inside of an HTML tag and makes an assoc array of attributes. + * + * @param string $string Inside of tag excluding name. + * @param HTMLPurifier_Config $config + * @param HTMLPurifier_Context $context + * @return array Assoc array of attributes. + */ + public function parseAttributeString($string, $config, $context) + { + $string = (string)$string; // quick typecast + + if ($string == '') { + return array(); + } // no attributes + + $e = false; + if ($config->get('Core.CollectErrors')) { + $e =& $context->get('ErrorCollector'); + } + + // let's see if we can abort as quickly as possible + // one equal sign, no spaces => one attribute + $num_equal = substr_count($string, '='); + $has_space = strpos($string, ' '); + if ($num_equal === 0 && !$has_space) { + // bool attribute + return array($string => $string); + } elseif ($num_equal === 1 && !$has_space) { + // only one attribute + list($key, $quoted_value) = explode('=', $string); + $quoted_value = trim($quoted_value); + if (!$key) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + return array(); + } + if (!$quoted_value) { + return array($key => ''); + } + $first_char = @$quoted_value[0]; + $last_char = @$quoted_value[strlen($quoted_value) - 1]; + + $same_quote = ($first_char == $last_char); + $open_quote = ($first_char == '"' || $first_char == "'"); + + if ($same_quote && $open_quote) { + // well behaved + $value = substr($quoted_value, 1, strlen($quoted_value) - 2); + } else { + // not well behaved + if ($open_quote) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing end quote'); + } + $value = substr($quoted_value, 1); + } else { + $value = $quoted_value; + } + } + if ($value === false) { + $value = ''; + } + return array($key => $this->parseAttr($value, $config)); + } + + // setup loop environment + $array = array(); // return assoc array of attributes + $cursor = 0; // current position in string (moves forward) + $size = strlen($string); // size of the string (stays the same) + + // if we have unquoted attributes, the parser expects a terminating + // space, so let's guarantee that there's always a terminating space. + $string .= ' '; + + $old_cursor = -1; + while ($cursor < $size) { + if ($old_cursor >= $cursor) { + throw new Exception("Infinite loop detected"); + } + $old_cursor = $cursor; + + $cursor += ($value = strspn($string, $this->_whitespace, $cursor)); + // grab the key + + $key_begin = $cursor; //we're currently at the start of the key + + // scroll past all characters that are the key (not whitespace or =) + $cursor += strcspn($string, $this->_whitespace . '=', $cursor); + + $key_end = $cursor; // now at the end of the key + + $key = substr($string, $key_begin, $key_end - $key_begin); + + if (!$key) { + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + $cursor += 1 + strcspn($string, $this->_whitespace, $cursor + 1); // prevent infinite loop + continue; // empty key + } + + // scroll past all whitespace + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor >= $size) { + $array[$key] = $key; + break; + } + + // if the next character is an equal sign, we've got a regular + // pair, otherwise, it's a bool attribute + $first_char = @$string[$cursor]; + + if ($first_char == '=') { + // key="value" + + $cursor++; + $cursor += strspn($string, $this->_whitespace, $cursor); + + if ($cursor === false) { + $array[$key] = ''; + break; + } + + // we might be in front of a quote right now + + $char = @$string[$cursor]; + + if ($char == '"' || $char == "'") { + // it's quoted, end bound is $char + $cursor++; + $value_begin = $cursor; + $cursor = strpos($string, $char, $cursor); + $value_end = $cursor; + } else { + // it's not quoted, end bound is whitespace + $value_begin = $cursor; + $cursor += strcspn($string, $this->_whitespace, $cursor); + $value_end = $cursor; + } + + // we reached a premature end + if ($cursor === false) { + $cursor = $size; + $value_end = $cursor; + } + + $value = substr($string, $value_begin, $value_end - $value_begin); + if ($value === false) { + $value = ''; + } + $array[$key] = $this->parseAttr($value, $config); + $cursor++; + } else { + // boolattr + if ($key !== '') { + $array[$key] = $key; + } else { + // purely theoretical + if ($e) { + $e->send(E_ERROR, 'Lexer: Missing attribute key'); + } + } + } + } + return $array; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php new file mode 100644 index 0000000..1564f28 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php @@ -0,0 +1,4788 @@ +normalize($html, $config, $context); + $new_html = $this->wrapHTML($new_html, $config, $context, false /* no div */); + try { + $parser = new HTML5($new_html); + $doc = $parser->save(); + } catch (DOMException $e) { + // Uh oh, it failed. Punt to DirectLex. + $lexer = new HTMLPurifier_Lexer_DirectLex(); + $context->register('PH5PError', $e); // save the error, so we can detect it + return $lexer->tokenizeHTML($html, $config, $context); // use original HTML + } + $tokens = array(); + $this->tokenizeDOM( + $doc->getElementsByTagName('html')->item(0)-> // + getElementsByTagName('body')->item(0) // + , + $tokens, $config + ); + return $tokens; + } +} + +/* + +Copyright 2007 Jeroen van der Meer + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +class HTML5 +{ + private $data; + private $char; + private $EOF; + private $state; + private $tree; + private $token; + private $content_model; + private $escape = false; + private $entities = array( + 'AElig;', + 'AElig', + 'AMP;', + 'AMP', + 'Aacute;', + 'Aacute', + 'Acirc;', + 'Acirc', + 'Agrave;', + 'Agrave', + 'Alpha;', + 'Aring;', + 'Aring', + 'Atilde;', + 'Atilde', + 'Auml;', + 'Auml', + 'Beta;', + 'COPY;', + 'COPY', + 'Ccedil;', + 'Ccedil', + 'Chi;', + 'Dagger;', + 'Delta;', + 'ETH;', + 'ETH', + 'Eacute;', + 'Eacute', + 'Ecirc;', + 'Ecirc', + 'Egrave;', + 'Egrave', + 'Epsilon;', + 'Eta;', + 'Euml;', + 'Euml', + 'GT;', + 'GT', + 'Gamma;', + 'Iacute;', + 'Iacute', + 'Icirc;', + 'Icirc', + 'Igrave;', + 'Igrave', + 'Iota;', + 'Iuml;', + 'Iuml', + 'Kappa;', + 'LT;', + 'LT', + 'Lambda;', + 'Mu;', + 'Ntilde;', + 'Ntilde', + 'Nu;', + 'OElig;', + 'Oacute;', + 'Oacute', + 'Ocirc;', + 'Ocirc', + 'Ograve;', + 'Ograve', + 'Omega;', + 'Omicron;', + 'Oslash;', + 'Oslash', + 'Otilde;', + 'Otilde', + 'Ouml;', + 'Ouml', + 'Phi;', + 'Pi;', + 'Prime;', + 'Psi;', + 'QUOT;', + 'QUOT', + 'REG;', + 'REG', + 'Rho;', + 'Scaron;', + 'Sigma;', + 'THORN;', + 'THORN', + 'TRADE;', + 'Tau;', + 'Theta;', + 'Uacute;', + 'Uacute', + 'Ucirc;', + 'Ucirc', + 'Ugrave;', + 'Ugrave', + 'Upsilon;', + 'Uuml;', + 'Uuml', + 'Xi;', + 'Yacute;', + 'Yacute', + 'Yuml;', + 'Zeta;', + 'aacute;', + 'aacute', + 'acirc;', + 'acirc', + 'acute;', + 'acute', + 'aelig;', + 'aelig', + 'agrave;', + 'agrave', + 'alefsym;', + 'alpha;', + 'amp;', + 'amp', + 'and;', + 'ang;', + 'apos;', + 'aring;', + 'aring', + 'asymp;', + 'atilde;', + 'atilde', + 'auml;', + 'auml', + 'bdquo;', + 'beta;', + 'brvbar;', + 'brvbar', + 'bull;', + 'cap;', + 'ccedil;', + 'ccedil', + 'cedil;', + 'cedil', + 'cent;', + 'cent', + 'chi;', + 'circ;', + 'clubs;', + 'cong;', + 'copy;', + 'copy', + 'crarr;', + 'cup;', + 'curren;', + 'curren', + 'dArr;', + 'dagger;', + 'darr;', + 'deg;', + 'deg', + 'delta;', + 'diams;', + 'divide;', + 'divide', + 'eacute;', + 'eacute', + 'ecirc;', + 'ecirc', + 'egrave;', + 'egrave', + 'empty;', + 'emsp;', + 'ensp;', + 'epsilon;', + 'equiv;', + 'eta;', + 'eth;', + 'eth', + 'euml;', + 'euml', + 'euro;', + 'exist;', + 'fnof;', + 'forall;', + 'frac12;', + 'frac12', + 'frac14;', + 'frac14', + 'frac34;', + 'frac34', + 'frasl;', + 'gamma;', + 'ge;', + 'gt;', + 'gt', + 'hArr;', + 'harr;', + 'hearts;', + 'hellip;', + 'iacute;', + 'iacute', + 'icirc;', + 'icirc', + 'iexcl;', + 'iexcl', + 'igrave;', + 'igrave', + 'image;', + 'infin;', + 'int;', + 'iota;', + 'iquest;', + 'iquest', + 'isin;', + 'iuml;', + 'iuml', + 'kappa;', + 'lArr;', + 'lambda;', + 'lang;', + 'laquo;', + 'laquo', + 'larr;', + 'lceil;', + 'ldquo;', + 'le;', + 'lfloor;', + 'lowast;', + 'loz;', + 'lrm;', + 'lsaquo;', + 'lsquo;', + 'lt;', + 'lt', + 'macr;', + 'macr', + 'mdash;', + 'micro;', + 'micro', + 'middot;', + 'middot', + 'minus;', + 'mu;', + 'nabla;', + 'nbsp;', + 'nbsp', + 'ndash;', + 'ne;', + 'ni;', + 'not;', + 'not', + 'notin;', + 'nsub;', + 'ntilde;', + 'ntilde', + 'nu;', + 'oacute;', + 'oacute', + 'ocirc;', + 'ocirc', + 'oelig;', + 'ograve;', + 'ograve', + 'oline;', + 'omega;', + 'omicron;', + 'oplus;', + 'or;', + 'ordf;', + 'ordf', + 'ordm;', + 'ordm', + 'oslash;', + 'oslash', + 'otilde;', + 'otilde', + 'otimes;', + 'ouml;', + 'ouml', + 'para;', + 'para', + 'part;', + 'permil;', + 'perp;', + 'phi;', + 'pi;', + 'piv;', + 'plusmn;', + 'plusmn', + 'pound;', + 'pound', + 'prime;', + 'prod;', + 'prop;', + 'psi;', + 'quot;', + 'quot', + 'rArr;', + 'radic;', + 'rang;', + 'raquo;', + 'raquo', + 'rarr;', + 'rceil;', + 'rdquo;', + 'real;', + 'reg;', + 'reg', + 'rfloor;', + 'rho;', + 'rlm;', + 'rsaquo;', + 'rsquo;', + 'sbquo;', + 'scaron;', + 'sdot;', + 'sect;', + 'sect', + 'shy;', + 'shy', + 'sigma;', + 'sigmaf;', + 'sim;', + 'spades;', + 'sub;', + 'sube;', + 'sum;', + 'sup1;', + 'sup1', + 'sup2;', + 'sup2', + 'sup3;', + 'sup3', + 'sup;', + 'supe;', + 'szlig;', + 'szlig', + 'tau;', + 'there4;', + 'theta;', + 'thetasym;', + 'thinsp;', + 'thorn;', + 'thorn', + 'tilde;', + 'times;', + 'times', + 'trade;', + 'uArr;', + 'uacute;', + 'uacute', + 'uarr;', + 'ucirc;', + 'ucirc', + 'ugrave;', + 'ugrave', + 'uml;', + 'uml', + 'upsih;', + 'upsilon;', + 'uuml;', + 'uuml', + 'weierp;', + 'xi;', + 'yacute;', + 'yacute', + 'yen;', + 'yen', + 'yuml;', + 'yuml', + 'zeta;', + 'zwj;', + 'zwnj;' + ); + + const PCDATA = 0; + const RCDATA = 1; + const CDATA = 2; + const PLAINTEXT = 3; + + const DOCTYPE = 0; + const STARTTAG = 1; + const ENDTAG = 2; + const COMMENT = 3; + const CHARACTR = 4; + const EOF = 5; + + public function __construct($data) + { + $this->data = $data; + $this->char = -1; + $this->EOF = strlen($data); + $this->tree = new HTML5TreeConstructer; + $this->content_model = self::PCDATA; + + $this->state = 'data'; + + while ($this->state !== null) { + $this->{$this->state . 'State'}(); + } + } + + public function save() + { + return $this->tree->save(); + } + + private function char() + { + return ($this->char < $this->EOF) + ? $this->data[$this->char] + : false; + } + + private function character($s, $l = 0) + { + if ($s + $l < $this->EOF) { + if ($l === 0) { + return $this->data[$s]; + } else { + return substr($this->data, $s, $l); + } + } + } + + private function characters($char_class, $start) + { + return preg_replace('#^([' . $char_class . ']+).*#s', '\\1', substr($this->data, $start)); + } + + private function dataState() + { + // Consume the next input character + $this->char++; + $char = $this->char(); + + if ($char === '&' && ($this->content_model === self::PCDATA || $this->content_model === self::RCDATA)) { + /* U+0026 AMPERSAND (&) + When the content model flag is set to one of the PCDATA or RCDATA + states: switch to the entity data state. Otherwise: treat it as per + the "anything else" entry below. */ + $this->state = 'entityData'; + + } elseif ($char === '-') { + /* If the content model flag is set to either the RCDATA state or + the CDATA state, and the escape flag is false, and there are at + least three characters before this one in the input stream, and the + last four characters in the input stream, including this one, are + U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, + and U+002D HYPHEN-MINUS (""), + set the escape flag to false. */ + if (($this->content_model === self::RCDATA || + $this->content_model === self::CDATA) && $this->escape === true && + $this->character($this->char, 3) === '-->' + ) { + $this->escape = false; + } + + /* In any case, emit the input character as a character token. + Stay in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + } elseif ($this->char === $this->EOF) { + /* EOF + Emit an end-of-file token. */ + $this->EOF(); + + } elseif ($this->content_model === self::PLAINTEXT) { + /* When the content model flag is set to the PLAINTEXT state + THIS DIFFERS GREATLY FROM THE SPEC: Get the remaining characters of + the text and emit it as a character token. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => substr($this->data, $this->char) + ) + ); + + $this->EOF(); + + } else { + /* Anything else + THIS DIFFERS GREATLY FROM THE SPEC: Get as many character that + otherwise would also be treated as a character token and emit it + as a single character token. Stay in the data state. */ + $len = strcspn($this->data, '<&', $this->char); + $char = substr($this->data, $this->char, $len); + $this->char += $len - 1; + + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + $this->state = 'data'; + } + } + + private function entityDataState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, emit a U+0026 AMPERSAND character token. + // Otherwise, emit the character token that was returned. + $char = (!$entity) ? '&' : $entity; + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => $char + ) + ); + + // Finally, switch to the data state. + $this->state = 'data'; + } + + private function tagOpenState() + { + switch ($this->content_model) { + case self::RCDATA: + case self::CDATA: + /* If the next input character is a U+002F SOLIDUS (/) character, + consume it and switch to the close tag open state. If the next + input character is not a U+002F SOLIDUS (/) character, emit a + U+003C LESS-THAN SIGN character token and switch to the data + state to process the next input character. */ + if ($this->character($this->char + 1) === '/') { + $this->char++; + $this->state = 'closeTagOpen'; + + } else { + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->state = 'data'; + } + break; + + case self::PCDATA: + // If the content model flag is set to the PCDATA state + // Consume the next input character: + $this->char++; + $char = $this->char(); + + if ($char === '!') { + /* U+0021 EXCLAMATION MARK (!) + Switch to the markup declaration open state. */ + $this->state = 'markupDeclarationOpen'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Switch to the close tag open state. */ + $this->state = 'closeTagOpen'; + + } elseif (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new start tag token, set its tag name to the lowercase + version of the input character (add 0x0020 to the character's code + point), then switch to the tag name state. (Don't emit the token + yet; further details will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::STARTTAG, + 'attr' => array() + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Emit a U+003C LESS-THAN SIGN character token and a + U+003E GREATER-THAN SIGN character token. Switch to the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<>' + ) + ); + + $this->state = 'data'; + + } elseif ($char === '?') { + /* U+003F QUESTION MARK (?) + Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + + } else { + /* Anything else + Parse error. Emit a U+003C LESS-THAN SIGN character token and + reconsume the current input character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => '<' + ) + ); + + $this->char--; + $this->state = 'data'; + } + break; + } + } + + private function closeTagOpenState() + { + $next_node = strtolower($this->characters('A-Za-z', $this->char + 1)); + $the_same = count($this->tree->stack) > 0 && $next_node === end($this->tree->stack)->nodeName; + + if (($this->content_model === self::RCDATA || $this->content_model === self::CDATA) && + (!$the_same || ($the_same && (!preg_match( + '/[\t\n\x0b\x0c >\/]/', + $this->character($this->char + 1 + strlen($next_node)) + ) || $this->EOF === $this->char))) + ) { + /* If the content model flag is set to the RCDATA or CDATA states then + examine the next few characters. If they do not match the tag name of + the last start tag token emitted (case insensitively), or if they do but + they are not immediately followed by one of the following characters: + * U+0009 CHARACTER TABULATION + * U+000A LINE FEED (LF) + * U+000B LINE TABULATION + * U+000C FORM FEED (FF) + * U+0020 SPACE + * U+003E GREATER-THAN SIGN (>) + * U+002F SOLIDUS (/) + * EOF + ...then there is a parse error. Emit a U+003C LESS-THAN SIGN character + token, a U+002F SOLIDUS character token, and switch to the data state + to process the next input character. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'state = 'data'; + + } else { + /* Otherwise, if the content model flag is set to the PCDATA state, + or if the next few characters do match that tag name, consume the + next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[A-Za-z]$/', $char)) { + /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z + Create a new end tag token, set its tag name to the lowercase version + of the input character (add 0x0020 to the character's code point), then + switch to the tag name state. (Don't emit the token yet; further details + will be filled in before it is emitted.) */ + $this->token = array( + 'name' => strtolower($char), + 'type' => self::ENDTAG + ); + + $this->state = 'tagName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Parse error. Switch to the data state. */ + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F + SOLIDUS character token. Reconsume the EOF character in the data state. */ + $this->emitToken( + array( + 'type' => self::CHARACTR, + 'data' => 'char--; + $this->state = 'data'; + + } else { + /* Parse error. Switch to the bogus comment state. */ + $this->state = 'bogusComment'; + } + } + } + + private function tagNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } else { + /* Anything else + Append the current input character to the current tag token's tag name. + Stay in the tag name state. */ + $this->token['name'] .= strtolower($char); + $this->state = 'tagName'; + } + } + + private function beforeAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Stay in the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function attributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the before + attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's name. + Stay in the attribute name state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['name'] .= strtolower($char); + + $this->state = 'attributeName'; + } + } + + private function afterAttributeNameState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the after attribute name state. */ + $this->state = 'afterAttributeName'; + + } elseif ($char === '=') { + /* U+003D EQUALS SIGN (=) + Switch to the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '/' && $this->character($this->char + 1) !== '>') { + /* U+002F SOLIDUS (/) + Parse error unless this is a permitted slash. Switch to the + before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the EOF + character in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Start a new attribute in the current tag token. Set that attribute's + name to the current input character, and its value to the empty string. + Switch to the attribute name state. */ + $this->token['attr'][] = array( + 'name' => strtolower($char), + 'value' => null + ); + + $this->state = 'attributeName'; + } + } + + private function beforeAttributeValueState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Stay in the before attribute value state. */ + $this->state = 'beforeAttributeValue'; + + } elseif ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the attribute value (double-quoted) state. */ + $this->state = 'attributeValueDoubleQuoted'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the attribute value (unquoted) state and reconsume + this input character. */ + $this->char--; + $this->state = 'attributeValueUnquoted'; + + } elseif ($char === '\'') { + /* U+0027 APOSTROPHE (') + Switch to the attribute value (single-quoted) state. */ + $this->state = 'attributeValueSingleQuoted'; + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Switch to the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function attributeValueDoubleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '"') { + /* U+0022 QUOTATION MARK (") + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('double'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (double-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueDoubleQuoted'; + } + } + + private function attributeValueSingleQuotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if ($char === '\'') { + /* U+0022 QUOTATION MARK (') + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState('single'); + + } elseif ($this->char === $this->EOF) { + /* EOF + Parse error. Emit the current tag token. Reconsume the character + in the data state. */ + $this->emitToken($this->token); + + $this->char--; + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (single-quoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueSingleQuoted'; + } + } + + private function attributeValueUnquotedState() + { + // Consume the next input character: + $this->char++; + $char = $this->character($this->char); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + /* U+0009 CHARACTER TABULATION + U+000A LINE FEED (LF) + U+000B LINE TABULATION + U+000C FORM FEED (FF) + U+0020 SPACE + Switch to the before attribute name state. */ + $this->state = 'beforeAttributeName'; + + } elseif ($char === '&') { + /* U+0026 AMPERSAND (&) + Switch to the entity in attribute value state. */ + $this->entityInAttributeValueState(); + + } elseif ($char === '>') { + /* U+003E GREATER-THAN SIGN (>) + Emit the current tag token. Switch to the data state. */ + $this->emitToken($this->token); + $this->state = 'data'; + + } else { + /* Anything else + Append the current input character to the current attribute's value. + Stay in the attribute value (unquoted) state. */ + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + + $this->state = 'attributeValueUnquoted'; + } + } + + private function entityInAttributeValueState() + { + // Attempt to consume an entity. + $entity = $this->entity(); + + // If nothing is returned, append a U+0026 AMPERSAND character to the + // current attribute's value. Otherwise, emit the character token that + // was returned. + $char = (!$entity) + ? '&' + : $entity; + + $last = count($this->token['attr']) - 1; + $this->token['attr'][$last]['value'] .= $char; + } + + private function bogusCommentState() + { + /* Consume every character up to the first U+003E GREATER-THAN SIGN + character (>) or the end of the file (EOF), whichever comes first. Emit + a comment token whose data is the concatenation of all the characters + starting from and including the character that caused the state machine + to switch into the bogus comment state, up to and including the last + consumed character before the U+003E character, if any, or up to the + end of the file otherwise. (If the comment was started by the end of + the file (EOF), the token is empty.) */ + $data = $this->characters('^>', $this->char); + $this->emitToken( + array( + 'data' => $data, + 'type' => self::COMMENT + ) + ); + + $this->char += strlen($data); + + /* Switch to the data state. */ + $this->state = 'data'; + + /* If the end of the file was reached, reconsume the EOF character. */ + if ($this->char === $this->EOF) { + $this->char = $this->EOF - 1; + } + } + + private function markupDeclarationOpenState() + { + /* If the next two characters are both U+002D HYPHEN-MINUS (-) + characters, consume those two characters, create a comment token whose + data is the empty string, and switch to the comment state. */ + if ($this->character($this->char + 1, 2) === '--') { + $this->char += 2; + $this->state = 'comment'; + $this->token = array( + 'data' => null, + 'type' => self::COMMENT + ); + + /* Otherwise if the next seven chacacters are a case-insensitive match + for the word "DOCTYPE", then consume those characters and switch to the + DOCTYPE state. */ + } elseif (strtolower($this->character($this->char + 1, 7)) === 'doctype') { + $this->char += 7; + $this->state = 'doctype'; + + /* Otherwise, is is a parse error. Switch to the bogus comment state. + The next character that is consumed, if any, is the first character + that will be in the comment. */ + } else { + $this->char++; + $this->state = 'bogusComment'; + } + } + + private function commentState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment dash state */ + $this->state = 'commentDash'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append the input character to the comment token's data. Stay in + the comment state. */ + $this->token['data'] .= $char; + } + } + + private function commentDashState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + /* U+002D HYPHEN-MINUS (-) */ + if ($char === '-') { + /* Switch to the comment end state */ + $this->state = 'commentEnd'; + + /* EOF */ + } elseif ($this->char === $this->EOF) { + /* Parse error. Emit the comment token. Reconsume the EOF character + in the data state. */ + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + /* Anything else */ + } else { + /* Append a U+002D HYPHEN-MINUS (-) character and the input + character to the comment token's data. Switch to the comment state. */ + $this->token['data'] .= '-' . $char; + $this->state = 'comment'; + } + } + + private function commentEndState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($char === '-') { + $this->token['data'] .= '-'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['data'] .= '--' . $char; + $this->state = 'comment'; + } + } + + private function doctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'beforeDoctypeName'; + + } else { + $this->char--; + $this->state = 'beforeDoctypeName'; + } + } + + private function beforeDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the before DOCTYPE name state. + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token = array( + 'name' => strtoupper($char), + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + + } elseif ($char === '>') { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken( + array( + 'name' => null, + 'type' => self::DOCTYPE, + 'error' => true + ) + ); + + $this->char--; + $this->state = 'data'; + + } else { + $this->token = array( + 'name' => $char, + 'type' => self::DOCTYPE, + 'error' => true + ); + + $this->state = 'doctypeName'; + } + } + + private function doctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + $this->state = 'AfterDoctypeName'; + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif (preg_match('/^[a-z]$/', $char)) { + $this->token['name'] .= strtoupper($char); + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['name'] .= $char; + } + + $this->token['error'] = ($this->token['name'] === 'HTML') + ? false + : true; + } + + private function afterDoctypeNameState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if (preg_match('/^[\t\n\x0b\x0c ]$/', $char)) { + // Stay in the DOCTYPE name state. + + } elseif ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + $this->token['error'] = true; + $this->state = 'bogusDoctype'; + } + } + + private function bogusDoctypeState() + { + /* Consume the next input character: */ + $this->char++; + $char = $this->char(); + + if ($char === '>') { + $this->emitToken($this->token); + $this->state = 'data'; + + } elseif ($this->char === $this->EOF) { + $this->emitToken($this->token); + $this->char--; + $this->state = 'data'; + + } else { + // Stay in the bogus DOCTYPE state. + } + } + + private function entity() + { + $start = $this->char; + + // This section defines how to consume an entity. This definition is + // used when parsing entities in text and in attributes. + + // The behaviour depends on the identity of the next character (the + // one immediately after the U+0026 AMPERSAND character): + + switch ($this->character($this->char + 1)) { + // U+0023 NUMBER SIGN (#) + case '#': + + // The behaviour further depends on the character after the + // U+0023 NUMBER SIGN: + switch ($this->character($this->char + 1)) { + // U+0078 LATIN SMALL LETTER X + // U+0058 LATIN CAPITAL LETTER X + case 'x': + case 'X': + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE, U+0061 LATIN SMALL LETTER A through to U+0066 + // LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER + // A, through to U+0046 LATIN CAPITAL LETTER F (in other + // words, 0-9, A-F, a-f). + $char = 1; + $char_class = '0-9A-Fa-f'; + break; + + // Anything else + default: + // Follow the steps below, but using the range of + // characters U+0030 DIGIT ZERO through to U+0039 DIGIT + // NINE (i.e. just 0-9). + $char = 0; + $char_class = '0-9'; + break; + } + + // Consume as many characters as match the range of characters + // given above. + $this->char++; + $e_name = $this->characters($char_class, $this->char + $char + 1); + $entity = $this->character($start, $this->char); + $cond = strlen($e_name) > 0; + + // The rest of the parsing happens below. + break; + + // Anything else + default: + // Consume the maximum number of characters possible, with the + // consumed characters case-sensitively matching one of the + // identifiers in the first column of the entities table. + + $e_name = $this->characters('0-9A-Za-z;', $this->char + 1); + $len = strlen($e_name); + + for ($c = 1; $c <= $len; $c++) { + $id = substr($e_name, 0, $c); + $this->char++; + + if (in_array($id, $this->entities)) { + if ($e_name[$c - 1] !== ';') { + if ($c < $len && $e_name[$c] == ';') { + $this->char++; // consume extra semicolon + } + } + $entity = $id; + break; + } + } + + $cond = isset($entity); + // The rest of the parsing happens below. + break; + } + + if (!$cond) { + // If no match can be made, then this is a parse error. No + // characters are consumed, and nothing is returned. + $this->char = $start; + return false; + } + + // Return a character token for the character corresponding to the + // entity name (as given by the second column of the entities table). + return html_entity_decode('&' . rtrim($entity, ';') . ';', ENT_QUOTES, 'UTF-8'); + } + + private function emitToken($token) + { + $emit = $this->tree->emitToken($token); + + if (is_int($emit)) { + $this->content_model = $emit; + + } elseif ($token['type'] === self::ENDTAG) { + $this->content_model = self::PCDATA; + } + } + + private function EOF() + { + $this->state = null; + $this->tree->emitToken( + array( + 'type' => self::EOF + ) + ); + } +} + +class HTML5TreeConstructer +{ + public $stack = array(); + + private $phase; + private $mode; + private $dom; + private $foster_parent = null; + private $a_formatting = array(); + + private $head_pointer = null; + private $form_pointer = null; + + private $scoping = array('button', 'caption', 'html', 'marquee', 'object', 'table', 'td', 'th'); + private $formatting = array( + 'a', + 'b', + 'big', + 'em', + 'font', + 'i', + 'nobr', + 's', + 'small', + 'strike', + 'strong', + 'tt', + 'u' + ); + private $special = array( + 'address', + 'area', + 'base', + 'basefont', + 'bgsound', + 'blockquote', + 'body', + 'br', + 'center', + 'col', + 'colgroup', + 'dd', + 'dir', + 'div', + 'dl', + 'dt', + 'embed', + 'fieldset', + 'form', + 'frame', + 'frameset', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'head', + 'hr', + 'iframe', + 'image', + 'img', + 'input', + 'isindex', + 'li', + 'link', + 'listing', + 'menu', + 'meta', + 'noembed', + 'noframes', + 'noscript', + 'ol', + 'optgroup', + 'option', + 'p', + 'param', + 'plaintext', + 'pre', + 'script', + 'select', + 'spacer', + 'style', + 'tbody', + 'textarea', + 'tfoot', + 'thead', + 'title', + 'tr', + 'ul', + 'wbr' + ); + + // The different phases. + const INIT_PHASE = 0; + const ROOT_PHASE = 1; + const MAIN_PHASE = 2; + const END_PHASE = 3; + + // The different insertion modes for the main phase. + const BEFOR_HEAD = 0; + const IN_HEAD = 1; + const AFTER_HEAD = 2; + const IN_BODY = 3; + const IN_TABLE = 4; + const IN_CAPTION = 5; + const IN_CGROUP = 6; + const IN_TBODY = 7; + const IN_ROW = 8; + const IN_CELL = 9; + const IN_SELECT = 10; + const AFTER_BODY = 11; + const IN_FRAME = 12; + const AFTR_FRAME = 13; + + // The different types of elements. + const SPECIAL = 0; + const SCOPING = 1; + const FORMATTING = 2; + const PHRASING = 3; + + const MARKER = 0; + + public function __construct() + { + $this->phase = self::INIT_PHASE; + $this->mode = self::BEFOR_HEAD; + $this->dom = new DOMDocument; + + $this->dom->encoding = 'UTF-8'; + $this->dom->preserveWhiteSpace = true; + $this->dom->substituteEntities = true; + $this->dom->strictErrorChecking = false; + } + + // Process tag tokens + public function emitToken($token) + { + switch ($this->phase) { + case self::INIT_PHASE: + return $this->initPhase($token); + break; + case self::ROOT_PHASE: + return $this->rootElementPhase($token); + break; + case self::MAIN_PHASE: + return $this->mainPhase($token); + break; + case self::END_PHASE : + return $this->trailingEndPhase($token); + break; + } + } + + private function initPhase($token) + { + /* Initially, the tree construction stage must handle each token + emitted from the tokenisation stage as follows: */ + + /* A DOCTYPE token that is marked as being in error + A comment token + A start tag token + An end tag token + A character token that is not one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE + An end-of-file token */ + if ((isset($token['error']) && $token['error']) || + $token['type'] === HTML5::COMMENT || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF || + ($token['type'] === HTML5::CHARACTR && isset($token['data']) && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) + ) { + /* This specification does not define how to handle this case. In + particular, user agents may ignore the entirety of this specification + altogether for such documents, and instead invoke special parse modes + with a greater emphasis on backwards compatibility. */ + + $this->phase = self::ROOT_PHASE; + return $this->rootElementPhase($token); + + /* A DOCTYPE token marked as being correct */ + } elseif (isset($token['error']) && !$token['error']) { + /* Append a DocumentType node to the Document node, with the name + attribute set to the name given in the DOCTYPE token (which will be + "HTML"), and the other attributes specific to DocumentType objects + set to null, empty lists, or the empty string as appropriate. */ + $doctype = new DOMDocumentType(null, null, 'HTML'); + + /* Then, switch to the root element phase of the tree construction + stage. */ + $this->phase = self::ROOT_PHASE; + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif (isset($token['data']) && preg_match( + '/^[\t\n\x0b\x0c ]+$/', + $token['data'] + ) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + } + } + + private function rootElementPhase($token) + { + /* After the initial phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append that character to the Document node. */ + $text = $this->dom->createTextNode($token['data']); + $this->dom->appendChild($text); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED + (FF), or U+0020 SPACE + A start tag token + An end tag token + An end-of-file token */ + } elseif (($token['type'] === HTML5::CHARACTR && + !preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || + $token['type'] === HTML5::ENDTAG || + $token['type'] === HTML5::EOF + ) { + /* Create an HTMLElement node with the tag name html, in the HTML + namespace. Append it to the Document object. Switch to the main + phase and reprocess the current token. */ + $html = $this->dom->createElement('html'); + $this->dom->appendChild($html); + $this->stack[] = $html; + + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + } + } + + private function mainPhase($token) + { + /* Tokens in the main phase must be handled as follows: */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A start tag token with the tag name "html" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'html') { + /* If this start tag token was not the first start tag token, then + it is a parse error. */ + + /* For each attribute on the token, check to see if the attribute + is already present on the top element of the stack of open elements. + If it is not, add the attribute and its corresponding value to that + element. */ + foreach ($token['attr'] as $attr) { + if (!$this->stack[0]->hasAttribute($attr['name'])) { + $this->stack[0]->setAttribute($attr['name'], $attr['value']); + } + } + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Anything else. */ + } else { + /* Depends on the insertion mode: */ + switch ($this->mode) { + case self::BEFOR_HEAD: + return $this->beforeHead($token); + break; + case self::IN_HEAD: + return $this->inHead($token); + break; + case self::AFTER_HEAD: + return $this->afterHead($token); + break; + case self::IN_BODY: + return $this->inBody($token); + break; + case self::IN_TABLE: + return $this->inTable($token); + break; + case self::IN_CAPTION: + return $this->inCaption($token); + break; + case self::IN_CGROUP: + return $this->inColumnGroup($token); + break; + case self::IN_TBODY: + return $this->inTableBody($token); + break; + case self::IN_ROW: + return $this->inRow($token); + break; + case self::IN_CELL: + return $this->inCell($token); + break; + case self::IN_SELECT: + return $this->inSelect($token); + break; + case self::AFTER_BODY: + return $this->afterBody($token); + break; + case self::IN_FRAME: + return $this->inFrameset($token); + break; + case self::AFTR_FRAME: + return $this->afterFrameset($token); + break; + case self::END_PHASE: + return $this->trailingEndPhase($token); + break; + } + } + } + + private function beforeHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "head" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') { + /* Create an element for the token, append the new element to the + current node and push it onto the stack of open elements. */ + $element = $this->insertElement($token); + + /* Set the head element pointer to this new element node. */ + $this->head_pointer = $element; + + /* Change the insertion mode to "in head". */ + $this->mode = self::IN_HEAD; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title". Or an end tag with the tag name "html". + Or a character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or any other start tag token */ + } elseif ($token['type'] === HTML5::STARTTAG || + ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') || + ($token['type'] === HTML5::CHARACTR && !preg_match( + '/^[\t\n\x0b\x0c ]$/', + $token['data'] + )) + ) { + /* Act as if a start tag token with the tag name "head" and no + attributes had been seen, then reprocess the current token. */ + $this->beforeHead( + array( + 'name' => 'head', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inHead($token); + + /* Any other end tag */ + } elseif ($token['type'] === HTML5::ENDTAG) { + /* Parse error. Ignore the token. */ + } + } + + private function inHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. + + THIS DIFFERS FROM THE SPEC: If the current node is either a title, style + or script element, append the character to the current node regardless + of its content. */ + if (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || ( + $token['type'] === HTML5::CHARACTR && in_array( + end($this->stack)->nodeName, + array('title', 'style', 'script') + )) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('title', 'style', 'script')) + ) { + array_pop($this->stack); + return HTML5::PCDATA; + + /* A start tag with the tag name "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'title') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $element = $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the RCDATA state. */ + return HTML5::RCDATA; + + /* A start tag with the tag name "style" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'style') { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + } else { + $this->insertElement($token); + } + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "script" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'script') { + /* Create an element for the token. */ + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + + /* A start tag with the tag name "base", "link", or "meta" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta') + ) + ) { + /* Create an element for the token and append the new element to the + node pointed to by the head element pointer, or, if that is null + (innerHTML case), to the current node. */ + if ($this->head_pointer !== null) { + $element = $this->insertElement($token, false); + $this->head_pointer->appendChild($element); + array_pop($this->stack); + + } else { + $this->insertElement($token); + } + + /* An end tag with the tag name "head" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'head') { + /* If the current node is a head element, pop the current node off + the stack of open elements. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + array_pop($this->stack); + + /* Otherwise, this is a parse error. */ + } else { + // k + } + + /* Change the insertion mode to "after head". */ + $this->mode = self::AFTER_HEAD; + + /* A start tag with the tag name "head" or an end tag except "html". */ + } elseif (($token['type'] === HTML5::STARTTAG && $token['name'] === 'head') || + ($token['type'] === HTML5::ENDTAG && $token['name'] !== 'html') + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* If the current node is a head element, act as if an end tag + token with the tag name "head" had been seen. */ + if ($this->head_pointer->isSameNode(end($this->stack))) { + $this->inHead( + array( + 'name' => 'head', + 'type' => HTML5::ENDTAG + ) + ); + + /* Otherwise, change the insertion mode to "after head". */ + } else { + $this->mode = self::AFTER_HEAD; + } + + /* Then, reprocess the current token. */ + return $this->afterHead($token); + } + } + + private function afterHead($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data attribute + set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token with the tag name "body" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'body') { + /* Insert a body element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in body". */ + $this->mode = self::IN_BODY; + + /* A start tag token with the tag name "frameset" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'frameset') { + /* Insert a frameset element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in frameset". */ + $this->mode = self::IN_FRAME; + + /* A start tag token whose tag name is one of: "base", "link", "meta", + "script", "style", "title" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('base', 'link', 'meta', 'script', 'style', 'title') + ) + ) { + /* Parse error. Switch the insertion mode back to "in head" and + reprocess the token. */ + $this->mode = self::IN_HEAD; + return $this->inHead($token); + + /* Anything else */ + } else { + /* Act as if a start tag token with the tag name "body" and no + attributes had been seen, and then reprocess the current token. */ + $this->afterHead( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inBody($token); + } + } + + private function inBody($token) + { + /* Handle the token as follows: */ + + switch ($token['type']) { + /* A character token */ + case HTML5::CHARACTR: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + break; + + /* A comment token */ + case HTML5::COMMENT: + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + break; + + case HTML5::STARTTAG: + switch ($token['name']) { + /* A start tag token whose tag name is one of: "script", + "style" */ + case 'script': + case 'style': + /* Process the token as if the insertion mode had been "in + head". */ + return $this->inHead($token); + break; + + /* A start tag token whose tag name is one of: "base", "link", + "meta", "title" */ + case 'base': + case 'link': + case 'meta': + case 'title': + /* Parse error. Process the token as if the insertion mode + had been "in head". */ + return $this->inHead($token); + break; + + /* A start tag token with the tag name "body" */ + case 'body': + /* Parse error. If the second element on the stack of open + elements is not a body element, or, if the stack of open + elements has only one node on it, then ignore the token. + (innerHTML case) */ + if (count($this->stack) === 1 || $this->stack[1]->nodeName !== 'body') { + // Ignore + + /* Otherwise, for each attribute on the token, check to see + if the attribute is already present on the body element (the + second element) on the stack of open elements. If it is not, + add the attribute and its corresponding value to that + element. */ + } else { + foreach ($token['attr'] as $attr) { + if (!$this->stack[1]->hasAttribute($attr['name'])) { + $this->stack[1]->setAttribute($attr['name'], $attr['value']); + } + } + } + break; + + /* A start tag whose tag name is one of: "address", + "blockquote", "center", "dir", "div", "dl", "fieldset", + "listing", "menu", "ol", "p", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'p': + case 'ul': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "form" */ + case 'form': + /* If the form element pointer is not null, ignore the + token with a parse error. */ + if ($this->form_pointer !== null) { + // Ignore. + + /* Otherwise: */ + } else { + /* If the stack of open elements has a p element in + scope, then act as if an end tag with the tag name p + had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token, and set the + form element pointer to point to the element created. */ + $element = $this->insertElement($token); + $this->form_pointer = $element; + } + break; + + /* A start tag whose tag name is "li", "dd" or "dt" */ + case 'li': + case 'dd': + case 'dt': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + $stack_length = count($this->stack) - 1; + + for ($n = $stack_length; 0 <= $n; $n--) { + /* 1. Initialise node to be the current node (the + bottommost node of the stack). */ + $stop = false; + $node = $this->stack[$n]; + $cat = $this->getElementCategory($node->tagName); + + /* 2. If node is an li, dd or dt element, then pop all + the nodes from the current node up to node, including + node, then stop this algorithm. */ + if ($token['name'] === $node->tagName || ($token['name'] !== 'li' + && ($node->tagName === 'dd' || $node->tagName === 'dt')) + ) { + for ($x = $stack_length; $x >= $n; $x--) { + array_pop($this->stack); + } + + break; + } + + /* 3. If node is not in the formatting category, and is + not in the phrasing category, and is not an address or + div element, then stop this algorithm. */ + if ($cat !== self::FORMATTING && $cat !== self::PHRASING && + $node->tagName !== 'address' && $node->tagName !== 'div' + ) { + break; + } + } + + /* Finally, insert an HTML element with the same tag + name as the token's. */ + $this->insertElement($token); + break; + + /* A start tag token whose tag name is "plaintext" */ + case 'plaintext': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been + seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + return HTML5::PLAINTEXT; + break; + + /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + this is a parse error; pop elements from the stack until an + element with one of those tag names has been popped from the + stack. */ + while ($this->elementInScope(array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'))) { + array_pop($this->stack); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + break; + + /* A start tag whose tag name is "a" */ + case 'a': + /* If the list of active formatting elements contains + an element whose tag name is "a" between the end of the + list and the last marker on the list (or the start of + the list if there is no marker on the list), then this + is a parse error; act as if an end tag with the tag name + "a" had been seen, then remove that element from the list + of active formatting elements and the stack of open + elements if the end tag didn't already remove it (it + might not have if the element is not in table scope). */ + $leng = count($this->a_formatting); + + for ($n = $leng - 1; $n >= 0; $n--) { + if ($this->a_formatting[$n] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$n]->nodeName === 'a') { + $this->emitToken( + array( + 'name' => 'a', + 'type' => HTML5::ENDTAG + ) + ); + break; + } + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag whose tag name is one of: "b", "big", "em", "font", + "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $el = $this->insertElement($token); + + /* Add that element to the list of active formatting + elements. */ + $this->a_formatting[] = $el; + break; + + /* A start tag token whose tag name is "button" */ + case 'button': + /* If the stack of open elements has a button element in scope, + then this is a parse error; act as if an end tag with the tag + name "button" had been seen, then reprocess the token. (We don't + do that. Unnecessary.) */ + if ($this->elementInScope('button')) { + $this->inBody( + array( + 'name' => 'button', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is one of: "marquee", "object" */ + case 'marquee': + case 'object': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + break; + + /* A start tag token whose tag name is "xmp" */ + case 'xmp': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Switch the content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "table" */ + case 'table': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + break; + + /* A start tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'img': + case 'param': + case 'spacer': + case 'wbr': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "hr" */ + case 'hr': + /* If the stack of open elements has a p element in scope, + then act as if an end tag with the tag name p had been seen. */ + if ($this->elementInScope('p')) { + $this->emitToken( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "image" */ + case 'image': + /* Parse error. Change the token's tag name to "img" and + reprocess it. (Don't ask.) */ + $token['name'] = 'img'; + return $this->inBody($token); + break; + + /* A start tag whose tag name is "input" */ + case 'input': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an input element for the token. */ + $element = $this->insertElement($token, false); + + /* If the form element pointer is not null, then associate the + input element with the form element pointed to by the form + element pointer. */ + $this->form_pointer !== null + ? $this->form_pointer->appendChild($element) + : end($this->stack)->appendChild($element); + + /* Pop that input element off the stack of open elements. */ + array_pop($this->stack); + break; + + /* A start tag whose tag name is "isindex" */ + case 'isindex': + /* Parse error. */ + // w/e + + /* If the form element pointer is not null, + then ignore the token. */ + if ($this->form_pointer === null) { + /* Act as if a start tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a start tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + /* Act as if a stream of character tokens had been seen. */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if a start tag token with the tag name "input" + had been seen, with all the attributes from the "isindex" + token, except with the "name" attribute set to the value + "isindex" (ignoring any explicit "name" attribute). */ + $attr = $token['attr']; + $attr[] = array('name' => 'name', 'value' => 'isindex'); + + $this->inBody( + array( + 'name' => 'input', + 'type' => HTML5::STARTTAG, + 'attr' => $attr + ) + ); + + /* Act as if a stream of character tokens had been seen + (see below for what they should say). */ + $this->insertText( + 'This is a searchable index. ' . + 'Insert your search keywords here: ' + ); + + /* Act as if an end tag token with the tag name "label" + had been seen. */ + $this->inBody( + array( + 'name' => 'label', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "p" had + been seen. */ + $this->inBody( + array( + 'name' => 'p', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if a start tag token with the tag name "hr" had + been seen. */ + $this->inBody( + array( + 'name' => 'hr', + 'type' => HTML5::ENDTAG + ) + ); + + /* Act as if an end tag token with the tag name "form" had + been seen. */ + $this->inBody( + array( + 'name' => 'form', + 'type' => HTML5::ENDTAG + ) + ); + } + break; + + /* A start tag whose tag name is "textarea" */ + case 'textarea': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the + RCDATA state. */ + return HTML5::RCDATA; + break; + + /* A start tag whose tag name is one of: "iframe", "noembed", + "noframes" */ + case 'iframe': + case 'noembed': + case 'noframes': + $this->insertElement($token); + + /* Switch the tokeniser's content model flag to the CDATA state. */ + return HTML5::CDATA; + break; + + /* A start tag whose tag name is "select" */ + case 'select': + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Change the insertion mode to "in select". */ + $this->mode = self::IN_SELECT; + break; + + /* A start or end tag whose tag name is one of: "caption", "col", + "colgroup", "frame", "frameset", "head", "option", "optgroup", + "tbody", "td", "tfoot", "th", "thead", "tr". */ + case 'caption': + case 'col': + case 'colgroup': + case 'frame': + case 'frameset': + case 'head': + case 'option': + case 'optgroup': + case 'tbody': + case 'td': + case 'tfoot': + case 'th': + case 'thead': + case 'tr': + // Parse error. Ignore the token. + break; + + /* A start or end tag whose tag name is one of: "event-source", + "section", "nav", "article", "aside", "header", "footer", + "datagrid", "command" */ + case 'event-source': + case 'section': + case 'nav': + case 'article': + case 'aside': + case 'header': + case 'footer': + case 'datagrid': + case 'command': + // Work in progress! + break; + + /* A start tag token not covered by the previous entries */ + default: + /* Reconstruct the active formatting elements, if any. */ + $this->reconstructActiveFormattingElements(); + + $this->insertElement($token, true, true); + break; + } + break; + + case HTML5::ENDTAG: + switch ($token['name']) { + /* An end tag with the tag name "body" */ + case 'body': + /* If the second element in the stack of open elements is + not a body element, this is a parse error. Ignore the token. + (innerHTML case) */ + if (count($this->stack) < 2 || $this->stack[1]->nodeName !== 'body') { + // Ignore. + + /* If the current node is not the body element, then this + is a parse error. */ + } elseif (end($this->stack)->nodeName !== 'body') { + // Parse error. + } + + /* Change the insertion mode to "after body". */ + $this->mode = self::AFTER_BODY; + break; + + /* An end tag with the tag name "html" */ + case 'html': + /* Act as if an end tag with tag name "body" had been seen, + then, if that token wasn't ignored, reprocess the current + token. */ + $this->inBody( + array( + 'name' => 'body', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->afterBody($token); + break; + + /* An end tag whose tag name is one of: "address", "blockquote", + "center", "dir", "div", "dl", "fieldset", "listing", "menu", + "ol", "pre", "ul" */ + case 'address': + case 'blockquote': + case 'center': + case 'dir': + case 'div': + case 'dl': + case 'fieldset': + case 'listing': + case 'menu': + case 'ol': + case 'pre': + case 'ul': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with + the same tag name as that of the token, then this + is a parse error. */ + // w/e + + /* If the stack of open elements has an element in + scope with the same tag name as that of the token, + then pop elements from this stack until an element + with that tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is "form" */ + case 'form': + /* If the stack of open elements has an element in scope + with the same tag name as that of the token, then generate + implied end tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + } + + if (end($this->stack)->nodeName !== $token['name']) { + /* Now, if the current node is not an element with the + same tag name as that of the token, then this is a parse + error. */ + // w/e + + } else { + /* Otherwise, if the current node is an element with + the same tag name as that of the token pop that element + from the stack. */ + array_pop($this->stack); + } + + /* In any case, set the form element pointer to null. */ + $this->form_pointer = null; + break; + + /* An end tag whose tag name is "p" */ + case 'p': + /* If the stack of open elements has a p element in scope, + then generate implied end tags, except for p elements. */ + if ($this->elementInScope('p')) { + $this->generateImpliedEndTags(array('p')); + + /* If the current node is not a p element, then this is + a parse error. */ + // k + + /* If the stack of open elements has a p element in + scope, then pop elements from this stack until the stack + no longer has a p element in scope. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->elementInScope('p')) { + array_pop($this->stack); + + } else { + break; + } + } + } + break; + + /* An end tag whose tag name is "dd", "dt", or "li" */ + case 'dd': + case 'dt': + case 'li': + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + generate implied end tags, except for elements with the + same tag name as the token. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(array($token['name'])); + + /* If the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then + pop elements from this stack until an element with that + tag name has been popped from the stack. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4", + "h5", "h6" */ + case 'h1': + case 'h2': + case 'h3': + case 'h4': + case 'h5': + case 'h6': + $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6'); + + /* If the stack of open elements has in scope an element whose + tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then + generate implied end tags. */ + if ($this->elementInScope($elements)) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as that of the token, then this is a parse error. */ + // w/e + + /* If the stack of open elements has in scope an element + whose tag name is one of "h1", "h2", "h3", "h4", "h5", or + "h6", then pop elements from the stack until an element + with one of those tag names has been popped from the stack. */ + while ($this->elementInScope($elements)) { + array_pop($this->stack); + } + } + break; + + /* An end tag whose tag name is one of: "a", "b", "big", "em", + "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */ + case 'a': + case 'b': + case 'big': + case 'em': + case 'font': + case 'i': + case 'nobr': + case 's': + case 'small': + case 'strike': + case 'strong': + case 'tt': + case 'u': + /* 1. Let the formatting element be the last element in + the list of active formatting elements that: + * is between the end of the list and the last scope + marker in the list, if any, or the start of the list + otherwise, and + * has the same tag name as the token. + */ + while (true) { + for ($a = count($this->a_formatting) - 1; $a >= 0; $a--) { + if ($this->a_formatting[$a] === self::MARKER) { + break; + + } elseif ($this->a_formatting[$a]->tagName === $token['name']) { + $formatting_element = $this->a_formatting[$a]; + $in_stack = in_array($formatting_element, $this->stack, true); + $fe_af_pos = $a; + break; + } + } + + /* If there is no such node, or, if that node is + also in the stack of open elements but the element + is not in scope, then this is a parse error. Abort + these steps. The token is ignored. */ + if (!isset($formatting_element) || ($in_stack && + !$this->elementInScope($token['name'])) + ) { + break; + + /* Otherwise, if there is such a node, but that node + is not in the stack of open elements, then this is a + parse error; remove the element from the list, and + abort these steps. */ + } elseif (isset($formatting_element) && !$in_stack) { + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 2. Let the furthest block be the topmost node in the + stack of open elements that is lower in the stack + than the formatting element, and is not an element in + the phrasing or formatting categories. There might + not be one. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $length = count($this->stack); + + for ($s = $fe_s_pos + 1; $s < $length; $s++) { + $category = $this->getElementCategory($this->stack[$s]->nodeName); + + if ($category !== self::PHRASING && $category !== self::FORMATTING) { + $furthest_block = $this->stack[$s]; + } + } + + /* 3. If there is no furthest block, then the UA must + skip the subsequent steps and instead just pop all + the nodes from the bottom of the stack of open + elements, from the current node up to the formatting + element, and remove the formatting element from the + list of active formatting elements. */ + if (!isset($furthest_block)) { + for ($n = $length - 1; $n >= $fe_s_pos; $n--) { + array_pop($this->stack); + } + + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + break; + } + + /* 4. Let the common ancestor be the element + immediately above the formatting element in the stack + of open elements. */ + $common_ancestor = $this->stack[$fe_s_pos - 1]; + + /* 5. If the furthest block has a parent node, then + remove the furthest block from its parent node. */ + if ($furthest_block->parentNode !== null) { + $furthest_block->parentNode->removeChild($furthest_block); + } + + /* 6. Let a bookmark note the position of the + formatting element in the list of active formatting + elements relative to the elements on either side + of it in the list. */ + $bookmark = $fe_af_pos; + + /* 7. Let node and last node be the furthest block. + Follow these steps: */ + $node = $furthest_block; + $last_node = $furthest_block; + + while (true) { + for ($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) { + /* 7.1 Let node be the element immediately + prior to node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 7.2 If node is not in the list of active + formatting elements, then remove node from + the stack of open elements and then go back + to step 1. */ + if (!in_array($node, $this->a_formatting, true)) { + unset($this->stack[$n]); + $this->stack = array_merge($this->stack); + + } else { + break; + } + } + + /* 7.3 Otherwise, if node is the formatting + element, then go to the next step in the overall + algorithm. */ + if ($node === $formatting_element) { + break; + + /* 7.4 Otherwise, if last node is the furthest + block, then move the aforementioned bookmark to + be immediately after the node in the list of + active formatting elements. */ + } elseif ($last_node === $furthest_block) { + $bookmark = array_search($node, $this->a_formatting, true) + 1; + } + + /* 7.5 If node has any children, perform a + shallow clone of node, replace the entry for + node in the list of active formatting elements + with an entry for the clone, replace the entry + for node in the stack of open elements with an + entry for the clone, and let node be the clone. */ + if ($node->hasChildNodes()) { + $clone = $node->cloneNode(); + $s_pos = array_search($node, $this->stack, true); + $a_pos = array_search($node, $this->a_formatting, true); + + $this->stack[$s_pos] = $clone; + $this->a_formatting[$a_pos] = $clone; + $node = $clone; + } + + /* 7.6 Insert last node into node, first removing + it from its previous parent node if any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $node->appendChild($last_node); + + /* 7.7 Let last node be node. */ + $last_node = $node; + } + + /* 8. Insert whatever last node ended up being in + the previous step into the common ancestor node, + first removing it from its previous parent node if + any. */ + if ($last_node->parentNode !== null) { + $last_node->parentNode->removeChild($last_node); + } + + $common_ancestor->appendChild($last_node); + + /* 9. Perform a shallow clone of the formatting + element. */ + $clone = $formatting_element->cloneNode(); + + /* 10. Take all of the child nodes of the furthest + block and append them to the clone created in the + last step. */ + while ($furthest_block->hasChildNodes()) { + $child = $furthest_block->firstChild; + $furthest_block->removeChild($child); + $clone->appendChild($child); + } + + /* 11. Append that clone to the furthest block. */ + $furthest_block->appendChild($clone); + + /* 12. Remove the formatting element from the list + of active formatting elements, and insert the clone + into the list of active formatting elements at the + position of the aforementioned bookmark. */ + $fe_af_pos = array_search($formatting_element, $this->a_formatting, true); + unset($this->a_formatting[$fe_af_pos]); + $this->a_formatting = array_merge($this->a_formatting); + + $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1); + $af_part2 = array_slice($this->a_formatting, $bookmark, count($this->a_formatting)); + $this->a_formatting = array_merge($af_part1, array($clone), $af_part2); + + /* 13. Remove the formatting element from the stack + of open elements, and insert the clone into the stack + of open elements immediately after (i.e. in a more + deeply nested position than) the position of the + furthest block in that stack. */ + $fe_s_pos = array_search($formatting_element, $this->stack, true); + $fb_s_pos = array_search($furthest_block, $this->stack, true); + unset($this->stack[$fe_s_pos]); + + $s_part1 = array_slice($this->stack, 0, $fb_s_pos); + $s_part2 = array_slice($this->stack, $fb_s_pos + 1, count($this->stack)); + $this->stack = array_merge($s_part1, array($clone), $s_part2); + + /* 14. Jump back to step 1 in this series of steps. */ + unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block); + } + break; + + /* An end tag token whose tag name is one of: "button", + "marquee", "object" */ + case 'button': + case 'marquee': + case 'object': + /* If the stack of open elements has an element in scope whose + tag name matches the tag name of the token, then generate implied + tags. */ + if ($this->elementInScope($token['name'])) { + $this->generateImpliedEndTags(); + + /* Now, if the current node is not an element with the same + tag name as the token, then this is a parse error. */ + // k + + /* Now, if the stack of open elements has an element in scope + whose tag name matches the tag name of the token, then pop + elements from the stack until that element has been popped from + the stack, and clear the list of active formatting elements up + to the last marker. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === $token['name']) { + $n = -1; + } + + array_pop($this->stack); + } + + $marker = end(array_keys($this->a_formatting, self::MARKER, true)); + + for ($n = count($this->a_formatting) - 1; $n > $marker; $n--) { + array_pop($this->a_formatting); + } + } + break; + + /* Or an end tag whose tag name is one of: "area", "basefont", + "bgsound", "br", "embed", "hr", "iframe", "image", "img", + "input", "isindex", "noembed", "noframes", "param", "select", + "spacer", "table", "textarea", "wbr" */ + case 'area': + case 'basefont': + case 'bgsound': + case 'br': + case 'embed': + case 'hr': + case 'iframe': + case 'image': + case 'img': + case 'input': + case 'isindex': + case 'noembed': + case 'noframes': + case 'param': + case 'select': + case 'spacer': + case 'table': + case 'textarea': + case 'wbr': + // Parse error. Ignore the token. + break; + + /* An end tag token not covered by the previous entries */ + default: + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + /* Initialise node to be the current node (the bottommost + node of the stack). */ + $node = end($this->stack); + + /* If node has the same tag name as the end tag token, + then: */ + if ($token['name'] === $node->nodeName) { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* If the tag name of the end tag token does not + match the tag name of the current node, this is a + parse error. */ + // k + + /* Pop all the nodes from the current node up to + node, including node, then stop this algorithm. */ + for ($x = count($this->stack) - $n; $x >= $n; $x--) { + array_pop($this->stack); + } + + } else { + $category = $this->getElementCategory($node); + + if ($category !== self::SPECIAL && $category !== self::SCOPING) { + /* Otherwise, if node is in neither the formatting + category nor the phrasing category, then this is a + parse error. Stop this algorithm. The end tag token + is ignored. */ + return false; + } + } + } + break; + } + break; + } + } + + private function inTable($token) + { + $clear = array('html', 'table'); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "caption" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'caption' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert a marker at the end of the list of active + formatting elements. */ + $this->a_formatting[] = self::MARKER; + + /* Insert an HTML element for the token, then switch the + insertion mode to "in caption". */ + $this->insertElement($token); + $this->mode = self::IN_CAPTION; + + /* A start tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'colgroup' + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the + insertion mode to "in column group". */ + $this->insertElement($token); + $this->mode = self::IN_CGROUP; + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'col' + ) { + $this->inTable( + array( + 'name' => 'colgroup', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + $this->inColumnGroup($token); + + /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('tbody', 'tfoot', 'thead') + ) + ) { + /* Clear the stack back to a table context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in table body". */ + $this->insertElement($token); + $this->mode = self::IN_TBODY; + + /* A start tag whose tag name is one of: "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && + in_array($token['name'], array('td', 'th', 'tr')) + ) { + /* Act as if a start tag token with the tag name "tbody" had been + seen, then reprocess the current token. */ + $this->inTable( + array( + 'name' => 'tbody', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inTableBody($token); + + /* A start tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'table' + ) { + /* Parse error. Act as if an end tag token with the tag name "table" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inTable( + array( + 'name' => 'table', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + + /* An end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + return false; + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a table element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a table element has been + popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'table') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'caption', + 'col', + 'colgroup', + 'html', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Parse error. Process the token as if the insertion mode was "in + body", with the following exception: */ + + /* If the current node is a table, tbody, tfoot, thead, or tr + element, then, whenever a node would be inserted into the current + node, it must instead be inserted into the foster parent element. */ + if (in_array( + end($this->stack)->nodeName, + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* The foster parent element is the parent element of the last + table element in the stack of open elements, if there is a + table element and it has such a parent element. If there is no + table element in the stack of open elements (innerHTML case), + then the foster parent element is the first element in the + stack of open elements (the html element). Otherwise, if there + is a table element in the stack of open elements, but the last + table element in the stack of open elements has no parent, or + its parent node is not an element, then the foster parent + element is the element before the last table element in the + stack of open elements. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table') { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $table->parentNode !== null) { + $this->foster_parent = $table->parentNode; + + } elseif (!isset($table)) { + $this->foster_parent = $this->stack[0]; + + } elseif (isset($table) && ($table->parentNode === null || + $table->parentNode->nodeType !== XML_ELEMENT_NODE) + ) { + $this->foster_parent = $this->stack[$n - 1]; + } + } + + $this->inBody($token); + } + } + + private function inCaption($token) + { + /* An end tag whose tag name is "caption" */ + if ($token['type'] === HTML5::ENDTAG && $token['name'] === 'caption') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Generate implied end tags. */ + $this->generateImpliedEndTags(); + + /* Now, if the current node is not a caption element, then this + is a parse error. */ + // w/e + + /* Pop elements from this stack until a caption element has + been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === 'caption') { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in table". */ + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag + name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + )) || ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'table') + ) { + /* Parse error. Act as if an end tag with the tag name "caption" + had been seen, then, if that token wasn't ignored, reprocess the + current token. */ + $this->inCaption( + array( + 'name' => 'caption', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + + /* An end tag whose tag name is one of: "body", "col", "colgroup", + "html", "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array( + 'body', + 'col', + 'colgroup', + 'html', + 'tbody', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + // Parse error. Ignore the token. + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inColumnGroup($token) + { + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $text = $this->dom->createTextNode($token['data']); + end($this->stack)->appendChild($text); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + end($this->stack)->appendChild($comment); + + /* A start tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::STARTTAG && $token['name'] === 'col') { + /* Insert a col element for the token. Immediately pop the current + node off the stack of open elements. */ + $this->insertElement($token); + array_pop($this->stack); + + /* An end tag whose tag name is "colgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'colgroup' + ) { + /* If the current node is the root html element, then this is a + parse error, ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + /* Otherwise, pop the current node (which will be a colgroup + element) from the stack of open elements. Switch the insertion + mode to "in table". */ + } else { + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* An end tag whose tag name is "col" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'col') { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Act as if an end tag with the tag name "colgroup" had been seen, + and then, if that token wasn't ignored, reprocess the current token. */ + $this->inColumnGroup( + array( + 'name' => 'colgroup', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inTable($token); + } + } + + private function inTableBody($token) + { + $clear = array('tbody', 'tfoot', 'thead', 'html'); + + /* A start tag whose tag name is "tr" */ + if ($token['type'] === HTML5::STARTTAG && $token['name'] === 'tr') { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Insert a tr element for the token, then switch the insertion + mode to "in row". */ + $this->insertElement($token); + $this->mode = self::IN_ROW; + + /* A start tag whose tag name is one of: "th", "td" */ + } elseif ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Parse error. Act as if a start tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inTableBody( + array( + 'name' => 'tr', + 'type' => HTML5::STARTTAG, + 'attr' => array() + ) + ); + + return $this->inRow($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node from the stack of open elements. Switch + the insertion mode to "in table". */ + array_pop($this->stack); + $this->mode = self::IN_TABLE; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */ + } elseif (($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoor', 'thead') + )) || + ($token['type'] === HTML5::STARTTAG && $token['name'] === 'table') + ) { + /* If the stack of open elements does not have a tbody, thead, or + tfoot element in table scope, this is a parse error. Ignore the + token. (innerHTML case) */ + if (!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table body context. */ + $this->clearStackToTableContext($clear); + + /* Act as if an end tag with the same tag name as the current + node ("tbody", "tfoot", or "thead") had been seen, then + reprocess the current token. */ + $this->inTableBody( + array( + 'name' => end($this->stack)->nodeName, + 'type' => HTML5::ENDTAG + ) + ); + + return $this->mainPhase($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inRow($token) + { + $clear = array('tr', 'html'); + + /* A start tag whose tag name is one of: "th", "td" */ + if ($token['type'] === HTML5::STARTTAG && + ($token['name'] === 'th' || $token['name'] === 'td') + ) { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Insert an HTML element for the token, then switch the insertion + mode to "in cell". */ + $this->insertElement($token); + $this->mode = self::IN_CELL; + + /* Insert a marker at the end of the list of active formatting + elements. */ + $this->a_formatting[] = self::MARKER; + + /* An end tag whose tag name is "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'tr') { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Clear the stack back to a table row context. */ + $this->clearStackToTableContext($clear); + + /* Pop the current node (which will be a tr element) from the + stack of open elements. Switch the insertion mode to "in table + body". */ + array_pop($this->stack); + $this->mode = self::IN_TBODY; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* Act as if an end tag with the tag name "tr" had been seen, then, + if that token wasn't ignored, reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + + /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */ + } elseif ($token['type'] === HTML5::ENDTAG && + in_array($token['name'], array('tbody', 'tfoot', 'thead')) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Otherwise, act as if an end tag with the tag name "tr" had + been seen, then reprocess the current token. */ + $this->inRow( + array( + 'name' => 'tr', + 'type' => HTML5::ENDTAG + ) + ); + + return $this->inCell($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html", "td", "th" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr') + ) + ) { + /* Parse error. Ignore the token. */ + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in table". */ + $this->inTable($token); + } + } + + private function inCell($token) + { + /* An end tag whose tag name is one of: "td", "th" */ + if ($token['type'] === HTML5::ENDTAG && + ($token['name'] === 'td' || $token['name'] === 'th') + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token, then this is a + parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise: */ + } else { + /* Generate implied end tags, except for elements with the same + tag name as the token. */ + $this->generateImpliedEndTags(array($token['name'])); + + /* Now, if the current node is not an element with the same tag + name as the token, then this is a parse error. */ + // k + + /* Pop elements from this stack until an element with the same + tag name as the token has been popped from the stack. */ + while (true) { + $node = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($node === $token['name']) { + break; + } + } + + /* Clear the list of active formatting elements up to the last + marker. */ + $this->clearTheActiveFormattingElementsUpToTheLastMarker(); + + /* Switch the insertion mode to "in row". (The current node + will be a tr element at this point.) */ + $this->mode = self::IN_ROW; + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* A start tag whose tag name is one of: "caption", "col", "colgroup", + "tbody", "td", "tfoot", "th", "thead", "tr" */ + } elseif ($token['type'] === HTML5::STARTTAG && in_array( + $token['name'], + array( + 'caption', + 'col', + 'colgroup', + 'tbody', + 'td', + 'tfoot', + 'th', + 'thead', + 'tr' + ) + ) + ) { + /* If the stack of open elements does not have a td or th element + in table scope, then this is a parse error; ignore the token. + (innerHTML case) */ + if (!$this->elementInScope(array('td', 'th'), true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* An end tag whose tag name is one of: "body", "caption", "col", + "colgroup", "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('body', 'caption', 'col', 'colgroup', 'html') + ) + ) { + /* Parse error. Ignore the token. */ + + /* An end tag whose tag name is one of: "table", "tbody", "tfoot", + "thead", "tr" */ + } elseif ($token['type'] === HTML5::ENDTAG && in_array( + $token['name'], + array('table', 'tbody', 'tfoot', 'thead', 'tr') + ) + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as that of the token (which can only + happen for "tbody", "tfoot" and "thead", or, in the innerHTML case), + then this is a parse error and the token must be ignored. */ + if (!$this->elementInScope($token['name'], true)) { + // Ignore. + + /* Otherwise, close the cell (see below) and reprocess the current + token. */ + } else { + $this->closeCell(); + return $this->inRow($token); + } + + /* Anything else */ + } else { + /* Process the token as if the insertion mode was "in body". */ + $this->inBody($token); + } + } + + private function inSelect($token) + { + /* Handle the token as follows: */ + + /* A character token */ + if ($token['type'] === HTML5::CHARACTR) { + /* Append the token's character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* A start tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::STARTTAG && + $token['name'] === 'optgroup' + ) { + /* If the current node is an option element, act as if an end tag + with the tag name "option" had been seen. */ + if (end($this->stack)->nodeName === 'option') { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, act as if an end tag + with the tag name "optgroup" had been seen. */ + if (end($this->stack)->nodeName === 'optgroup') { + $this->inSelect( + array( + 'name' => 'optgroup', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* An end tag token whose tag name is "optgroup" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'optgroup' + ) { + /* First, if the current node is an option element, and the node + immediately before it in the stack of open elements is an optgroup + element, then act as if an end tag with the tag name "option" had + been seen. */ + $elements_in_stack = count($this->stack); + + if ($this->stack[$elements_in_stack - 1]->nodeName === 'option' && + $this->stack[$elements_in_stack - 2]->nodeName === 'optgroup' + ) { + $this->inSelect( + array( + 'name' => 'option', + 'type' => HTML5::ENDTAG + ) + ); + } + + /* If the current node is an optgroup element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if ($this->stack[$elements_in_stack - 1] === 'optgroup') { + array_pop($this->stack); + } + + /* An end tag token whose tag name is "option" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'option' + ) { + /* If the current node is an option element, then pop that node + from the stack of open elements. Otherwise, this is a parse error, + ignore the token. */ + if (end($this->stack)->nodeName === 'option') { + array_pop($this->stack); + } + + /* An end tag whose tag name is "select" */ + } elseif ($token['type'] === HTML5::ENDTAG && + $token['name'] === 'select' + ) { + /* If the stack of open elements does not have an element in table + scope with the same tag name as the token, this is a parse error. + Ignore the token. (innerHTML case) */ + if (!$this->elementInScope($token['name'], true)) { + // w/e + + /* Otherwise: */ + } else { + /* Pop elements from the stack of open elements until a select + element has been popped from the stack. */ + while (true) { + $current = end($this->stack)->nodeName; + array_pop($this->stack); + + if ($current === 'select') { + break; + } + } + + /* Reset the insertion mode appropriately. */ + $this->resetInsertionMode(); + } + + /* A start tag whose tag name is "select" */ + } elseif ($token['name'] === 'select' && + $token['type'] === HTML5::STARTTAG + ) { + /* Parse error. Act as if the token had been an end tag with the + tag name "select" instead. */ + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + /* An end tag whose tag name is one of: "caption", "table", "tbody", + "tfoot", "thead", "tr", "td", "th" */ + } elseif (in_array( + $token['name'], + array( + 'caption', + 'table', + 'tbody', + 'tfoot', + 'thead', + 'tr', + 'td', + 'th' + ) + ) && $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. */ + // w/e + + /* If the stack of open elements has an element in table scope with + the same tag name as that of the token, then act as if an end tag + with the tag name "select" had been seen, and reprocess the token. + Otherwise, ignore the token. */ + if ($this->elementInScope($token['name'], true)) { + $this->inSelect( + array( + 'name' => 'select', + 'type' => HTML5::ENDTAG + ) + ); + + $this->mainPhase($token); + } + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterBody($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed if the insertion mode + was "in body". */ + $this->inBody($token); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the first element in the stack of open + elements (the html element), with the data attribute set to the + data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->stack[0]->appendChild($comment); + + /* An end tag with the tag name "html" */ + } elseif ($token['type'] === HTML5::ENDTAG && $token['name'] === 'html') { + /* If the parser was originally created in order to handle the + setting of an element's innerHTML attribute, this is a parse error; + ignore the token. (The element will be an html element in this + case.) (innerHTML case) */ + + /* Otherwise, switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* Anything else */ + } else { + /* Parse error. Set the insertion mode to "in body" and reprocess + the token. */ + $this->mode = self::IN_BODY; + return $this->inBody($token); + } + } + + private function inFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* A start tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::STARTTAG + ) { + $this->insertElement($token); + + /* An end tag with the tag name "frameset" */ + } elseif ($token['name'] === 'frameset' && + $token['type'] === HTML5::ENDTAG + ) { + /* If the current node is the root html element, then this is a + parse error; ignore the token. (innerHTML case) */ + if (end($this->stack)->nodeName === 'html') { + // Ignore + + } else { + /* Otherwise, pop the current node from the stack of open + elements. */ + array_pop($this->stack); + + /* If the parser was not originally created in order to handle + the setting of an element's innerHTML attribute (innerHTML case), + and the current node is no longer a frameset element, then change + the insertion mode to "after frameset". */ + $this->mode = self::AFTR_FRAME; + } + + /* A start tag with the tag name "frame" */ + } elseif ($token['name'] === 'frame' && + $token['type'] === HTML5::STARTTAG + ) { + /* Insert an HTML element for the token. */ + $this->insertElement($token); + + /* Immediately pop the current node off the stack of open elements. */ + array_pop($this->stack); + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function afterFrameset($token) + { + /* Handle the token as follows: */ + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */ + if ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Append the character to the current node. */ + $this->insertText($token['data']); + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the current node with the data + attribute set to the data given in the comment token. */ + $this->insertComment($token['data']); + + /* An end tag with the tag name "html" */ + } elseif ($token['name'] === 'html' && + $token['type'] === HTML5::ENDTAG + ) { + /* Switch to the trailing end phase. */ + $this->phase = self::END_PHASE; + + /* A start tag with the tag name "noframes" */ + } elseif ($token['name'] === 'noframes' && + $token['type'] === HTML5::STARTTAG + ) { + /* Process the token as if the insertion mode had been "in body". */ + $this->inBody($token); + + /* Anything else */ + } else { + /* Parse error. Ignore the token. */ + } + } + + private function trailingEndPhase($token) + { + /* After the main phase, as each token is emitted from the tokenisation + stage, it must be processed as described in this section. */ + + /* A DOCTYPE token */ + if ($token['type'] === HTML5::DOCTYPE) { + // Parse error. Ignore the token. + + /* A comment token */ + } elseif ($token['type'] === HTML5::COMMENT) { + /* Append a Comment node to the Document object with the data + attribute set to the data given in the comment token. */ + $comment = $this->dom->createComment($token['data']); + $this->dom->appendChild($comment); + + /* A character token that is one of one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE */ + } elseif ($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data']) + ) { + /* Process the token as it would be processed in the main phase. */ + $this->mainPhase($token); + + /* A character token that is not one of U+0009 CHARACTER TABULATION, + U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), + or U+0020 SPACE. Or a start tag token. Or an end tag token. */ + } elseif (($token['type'] === HTML5::CHARACTR && + preg_match('/^[\t\n\x0b\x0c ]+$/', $token['data'])) || + $token['type'] === HTML5::STARTTAG || $token['type'] === HTML5::ENDTAG + ) { + /* Parse error. Switch back to the main phase and reprocess the + token. */ + $this->phase = self::MAIN_PHASE; + return $this->mainPhase($token); + + /* An end-of-file token */ + } elseif ($token['type'] === HTML5::EOF) { + /* OMG DONE!! */ + } + } + + private function insertElement($token, $append = true, $check = false) + { + // Proprietary workaround for libxml2's limitations with tag names + if ($check) { + // Slightly modified HTML5 tag-name modification, + // removing anything that's not an ASCII letter, digit, or hyphen + $token['name'] = preg_replace('/[^a-z0-9-]/i', '', $token['name']); + // Remove leading hyphens and numbers + $token['name'] = ltrim($token['name'], '-0..9'); + // In theory, this should ever be needed, but just in case + if ($token['name'] === '') { + $token['name'] = 'span'; + } // arbitrary generic choice + } + + $el = $this->dom->createElement($token['name']); + + foreach ($token['attr'] as $attr) { + if (!$el->hasAttribute($attr['name'])) { + $el->setAttribute($attr['name'], (string)$attr['value']); + } + } + + $this->appendToRealParent($el); + $this->stack[] = $el; + + return $el; + } + + private function insertText($data) + { + $text = $this->dom->createTextNode($data); + $this->appendToRealParent($text); + } + + private function insertComment($data) + { + $comment = $this->dom->createComment($data); + $this->appendToRealParent($comment); + } + + private function appendToRealParent($node) + { + if ($this->foster_parent === null) { + end($this->stack)->appendChild($node); + + } elseif ($this->foster_parent !== null) { + /* If the foster parent element is the parent element of the + last table element in the stack of open elements, then the new + node must be inserted immediately before the last table element + in the stack of open elements in the foster parent element; + otherwise, the new node must be appended to the foster parent + element. */ + for ($n = count($this->stack) - 1; $n >= 0; $n--) { + if ($this->stack[$n]->nodeName === 'table' && + $this->stack[$n]->parentNode !== null + ) { + $table = $this->stack[$n]; + break; + } + } + + if (isset($table) && $this->foster_parent->isSameNode($table->parentNode)) { + $this->foster_parent->insertBefore($node, $table); + } else { + $this->foster_parent->appendChild($node); + } + + $this->foster_parent = null; + } + } + + private function elementInScope($el, $table = false) + { + if (is_array($el)) { + foreach ($el as $element) { + if ($this->elementInScope($element, $table)) { + return true; + } + } + + return false; + } + + $leng = count($this->stack); + + for ($n = 0; $n < $leng; $n++) { + /* 1. Initialise node to be the current node (the bottommost node of + the stack). */ + $node = $this->stack[$leng - 1 - $n]; + + if ($node->tagName === $el) { + /* 2. If node is the target node, terminate in a match state. */ + return true; + + } elseif ($node->tagName === 'table') { + /* 3. Otherwise, if node is a table element, terminate in a failure + state. */ + return false; + + } elseif ($table === true && in_array( + $node->tagName, + array( + 'caption', + 'td', + 'th', + 'button', + 'marquee', + 'object' + ) + ) + ) { + /* 4. Otherwise, if the algorithm is the "has an element in scope" + variant (rather than the "has an element in table scope" variant), + and node is one of the following, terminate in a failure state. */ + return false; + + } elseif ($node === $node->ownerDocument->documentElement) { + /* 5. Otherwise, if node is an html element (root element), terminate + in a failure state. (This can only happen if the node is the topmost + node of the stack of open elements, and prevents the next step from + being invoked if there are no more elements in the stack.) */ + return false; + } + + /* Otherwise, set node to the previous entry in the stack of open + elements and return to step 2. (This will never fail, since the loop + will always terminate in the previous step if the top of the stack + is reached.) */ + } + } + + private function reconstructActiveFormattingElements() + { + /* 1. If there are no entries in the list of active formatting elements, + then there is nothing to reconstruct; stop this algorithm. */ + $formatting_elements = count($this->a_formatting); + + if ($formatting_elements === 0) { + return false; + } + + /* 3. Let entry be the last (most recently added) element in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. If the last (most recently added) entry in the list of active + formatting elements is a marker, or if it is an element that is in the + stack of open elements, then there is nothing to reconstruct; stop this + algorithm. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + return false; + } + + for ($a = $formatting_elements - 1; $a >= 0; true) { + /* 4. If there are no entries before entry in the list of active + formatting elements, then jump to step 8. */ + if ($a === 0) { + $step_seven = false; + break; + } + + /* 5. Let entry be the entry one earlier than entry in the list of + active formatting elements. */ + $a--; + $entry = $this->a_formatting[$a]; + + /* 6. If entry is neither a marker nor an element that is also in + thetack of open elements, go to step 4. */ + if ($entry === self::MARKER || in_array($entry, $this->stack, true)) { + break; + } + } + + while (true) { + /* 7. Let entry be the element one later than entry in the list of + active formatting elements. */ + if (isset($step_seven) && $step_seven === true) { + $a++; + $entry = $this->a_formatting[$a]; + } + + /* 8. Perform a shallow clone of the element entry to obtain clone. */ + $clone = $entry->cloneNode(); + + /* 9. Append clone to the current node and push it onto the stack + of open elements so that it is the new current node. */ + end($this->stack)->appendChild($clone); + $this->stack[] = $clone; + + /* 10. Replace the entry for entry in the list with an entry for + clone. */ + $this->a_formatting[$a] = $clone; + + /* 11. If the entry for clone in the list of active formatting + elements is not the last entry in the list, return to step 7. */ + if (end($this->a_formatting) !== $clone) { + $step_seven = true; + } else { + break; + } + } + } + + private function clearTheActiveFormattingElementsUpToTheLastMarker() + { + /* When the steps below require the UA to clear the list of active + formatting elements up to the last marker, the UA must perform the + following steps: */ + + while (true) { + /* 1. Let entry be the last (most recently added) entry in the list + of active formatting elements. */ + $entry = end($this->a_formatting); + + /* 2. Remove entry from the list of active formatting elements. */ + array_pop($this->a_formatting); + + /* 3. If entry was a marker, then stop the algorithm at this point. + The list has been cleared up to the last marker. */ + if ($entry === self::MARKER) { + break; + } + } + } + + private function generateImpliedEndTags($exclude = array()) + { + /* When the steps below require the UA to generate implied end tags, + then, if the current node is a dd element, a dt element, an li element, + a p element, a td element, a th element, or a tr element, the UA must + act as if an end tag with the respective tag name had been seen and + then generate implied end tags again. */ + $node = end($this->stack); + $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude); + + while (in_array(end($this->stack)->nodeName, $elements)) { + array_pop($this->stack); + } + } + + private function getElementCategory($node) + { + $name = $node->tagName; + if (in_array($name, $this->special)) { + return self::SPECIAL; + } elseif (in_array($name, $this->scoping)) { + return self::SCOPING; + } elseif (in_array($name, $this->formatting)) { + return self::FORMATTING; + } else { + return self::PHRASING; + } + } + + private function clearStackToTableContext($elements) + { + /* When the steps above require the UA to clear the stack back to a + table context, it means that the UA must, while the current node is not + a table element or an html element, pop elements from the stack of open + elements. If this causes any elements to be popped from the stack, then + this is a parse error. */ + while (true) { + $node = end($this->stack)->nodeName; + + if (in_array($node, $elements)) { + break; + } else { + array_pop($this->stack); + } + } + } + + private function resetInsertionMode() + { + /* 1. Let last be false. */ + $last = false; + $leng = count($this->stack); + + for ($n = $leng - 1; $n >= 0; $n--) { + /* 2. Let node be the last node in the stack of open elements. */ + $node = $this->stack[$n]; + + /* 3. If node is the first node in the stack of open elements, then + set last to true. If the element whose innerHTML attribute is being + set is neither a td element nor a th element, then set node to the + element whose innerHTML attribute is being set. (innerHTML case) */ + if ($this->stack[0]->isSameNode($node)) { + $last = true; + } + + /* 4. If node is a select element, then switch the insertion mode to + "in select" and abort these steps. (innerHTML case) */ + if ($node->nodeName === 'select') { + $this->mode = self::IN_SELECT; + break; + + /* 5. If node is a td or th element, then switch the insertion mode + to "in cell" and abort these steps. */ + } elseif ($node->nodeName === 'td' || $node->nodeName === 'th') { + $this->mode = self::IN_CELL; + break; + + /* 6. If node is a tr element, then switch the insertion mode to + "in row" and abort these steps. */ + } elseif ($node->nodeName === 'tr') { + $this->mode = self::IN_ROW; + break; + + /* 7. If node is a tbody, thead, or tfoot element, then switch the + insertion mode to "in table body" and abort these steps. */ + } elseif (in_array($node->nodeName, array('tbody', 'thead', 'tfoot'))) { + $this->mode = self::IN_TBODY; + break; + + /* 8. If node is a caption element, then switch the insertion mode + to "in caption" and abort these steps. */ + } elseif ($node->nodeName === 'caption') { + $this->mode = self::IN_CAPTION; + break; + + /* 9. If node is a colgroup element, then switch the insertion mode + to "in column group" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'colgroup') { + $this->mode = self::IN_CGROUP; + break; + + /* 10. If node is a table element, then switch the insertion mode + to "in table" and abort these steps. */ + } elseif ($node->nodeName === 'table') { + $this->mode = self::IN_TABLE; + break; + + /* 11. If node is a head element, then switch the insertion mode + to "in body" ("in body"! not "in head"!) and abort these steps. + (innerHTML case) */ + } elseif ($node->nodeName === 'head') { + $this->mode = self::IN_BODY; + break; + + /* 12. If node is a body element, then switch the insertion mode to + "in body" and abort these steps. */ + } elseif ($node->nodeName === 'body') { + $this->mode = self::IN_BODY; + break; + + /* 13. If node is a frameset element, then switch the insertion + mode to "in frameset" and abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'frameset') { + $this->mode = self::IN_FRAME; + break; + + /* 14. If node is an html element, then: if the head element + pointer is null, switch the insertion mode to "before head", + otherwise, switch the insertion mode to "after head". In either + case, abort these steps. (innerHTML case) */ + } elseif ($node->nodeName === 'html') { + $this->mode = ($this->head_pointer === null) + ? self::BEFOR_HEAD + : self::AFTER_HEAD; + + break; + + /* 15. If last is true, then set the insertion mode to "in body" + and abort these steps. (innerHTML case) */ + } elseif ($last) { + $this->mode = self::IN_BODY; + break; + } + } + } + + private function closeCell() + { + /* If the stack of open elements has a td or th element in table scope, + then act as if an end tag token with that tag name had been seen. */ + foreach (array('td', 'th') as $cell) { + if ($this->elementInScope($cell, true)) { + $this->inCell( + array( + 'name' => $cell, + 'type' => HTML5::ENDTAG + ) + ); + + break; + } + } + } + + public function save() + { + return $this->dom; + } +} diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php new file mode 100644 index 0000000..3995fec --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php @@ -0,0 +1,49 @@ +data = $data; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Comment($this->data, $this->line, $this->col), null); + } +} diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php new file mode 100644 index 0000000..6cbf56d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php @@ -0,0 +1,59 @@ + form or the form, i.e. + * is it a pair of start/end tokens or an empty token. + * @bool + */ + public $empty = false; + + public $endCol = null, $endLine = null, $endArmor = array(); + + public function __construct($name, $attr = array(), $line = null, $col = null, $armor = array()) { + $this->name = $name; + $this->attr = $attr; + $this->line = $line; + $this->col = $col; + $this->armor = $armor; + } + + public function toTokenPair() { + // XXX inefficiency here, normalization is not necessary + if ($this->empty) { + return array(new HTMLPurifier_Token_Empty($this->name, $this->attr, $this->line, $this->col, $this->armor), null); + } else { + $start = new HTMLPurifier_Token_Start($this->name, $this->attr, $this->line, $this->col, $this->armor); + $end = new HTMLPurifier_Token_End($this->name, array(), $this->endLine, $this->endCol, $this->endArmor); + //$end->start = $start; + return array($start, $end); + } + } +} + diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php new file mode 100644 index 0000000..aec9166 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php @@ -0,0 +1,54 @@ +data = $data; + $this->is_whitespace = $is_whitespace; + $this->line = $line; + $this->col = $col; + } + + public function toTokenPair() { + return array(new HTMLPurifier_Token_Text($this->data, $this->line, $this->col), null); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php new file mode 100644 index 0000000..18c8bbb --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php @@ -0,0 +1,111 @@ +preserve[$i] = true; + } + for ($i = 65; $i <= 90; $i++) { // upper-case + $this->preserve[$i] = true; + } + for ($i = 97; $i <= 122; $i++) { // lower-case + $this->preserve[$i] = true; + } + $this->preserve[45] = true; // Dash - + $this->preserve[46] = true; // Period . + $this->preserve[95] = true; // Underscore _ + $this->preserve[126]= true; // Tilde ~ + + // extra letters not to escape + if ($preserve !== false) { + for ($i = 0, $c = strlen($preserve); $i < $c; $i++) { + $this->preserve[ord($preserve[$i])] = true; + } + } + } + + /** + * Our replacement for urlencode, it encodes all non-reserved characters, + * as well as any extra characters that were instructed to be preserved. + * @note + * Assumes that the string has already been normalized, making any + * and all percent escape sequences valid. Percents will not be + * re-escaped, regardless of their status in $preserve + * @param string $string String to be encoded + * @return string Encoded string. + */ + public function encode($string) + { + $ret = ''; + for ($i = 0, $c = strlen($string); $i < $c; $i++) { + if ($string[$i] !== '%' && !isset($this->preserve[$int = ord($string[$i])])) { + $ret .= '%' . sprintf('%02X', $int); + } else { + $ret .= $string[$i]; + } + } + return $ret; + } + + /** + * Fix up percent-encoding by decoding unreserved characters and normalizing. + * @warning This function is affected by $preserve, even though the + * usual desired behavior is for this not to preserve those + * characters. Be careful when reusing instances of PercentEncoder! + * @param string $string String to normalize + * @return string + */ + public function normalize($string) + { + if ($string == '') { + return ''; + } + $parts = explode('%', $string); + $ret = array_shift($parts); + foreach ($parts as $part) { + $length = strlen($part); + if ($length < 2) { + $ret .= '%25' . $part; + continue; + } + $encoding = substr($part, 0, 2); + $text = substr($part, 2); + if (!ctype_xdigit($encoding)) { + $ret .= '%25' . $part; + continue; + } + $int = hexdec($encoding); + if (isset($this->preserve[$int])) { + $ret .= chr($int) . $text; + continue; + } + $encoding = strtoupper($encoding); + $ret .= '%' . $encoding . $text; + } + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php new file mode 100644 index 0000000..549e4ce --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php @@ -0,0 +1,218 @@ +getAll(); + $context = new HTMLPurifier_Context(); + $this->generator = new HTMLPurifier_Generator($config, $context); + } + + /** + * Main function that renders object or aspect of that object + * @note Parameters vary depending on printer + */ + // function render() {} + + /** + * Returns a start tag + * @param string $tag Tag name + * @param array $attr Attribute array + * @return string + */ + protected function start($tag, $attr = array()) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Start($tag, $attr ? $attr : array()) + ); + } + + /** + * Returns an end tag + * @param string $tag Tag name + * @return string + */ + protected function end($tag) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_End($tag) + ); + } + + /** + * Prints a complete element with content inside + * @param string $tag Tag name + * @param string $contents Element contents + * @param array $attr Tag attributes + * @param bool $escape whether or not to escape contents + * @return string + */ + protected function element($tag, $contents, $attr = array(), $escape = true) + { + return $this->start($tag, $attr) . + ($escape ? $this->escape($contents) : $contents) . + $this->end($tag); + } + + /** + * @param string $tag + * @param array $attr + * @return string + */ + protected function elementEmpty($tag, $attr = array()) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Empty($tag, $attr) + ); + } + + /** + * @param string $text + * @return string + */ + protected function text($text) + { + return $this->generator->generateFromToken( + new HTMLPurifier_Token_Text($text) + ); + } + + /** + * Prints a simple key/value row in a table. + * @param string $name Key + * @param mixed $value Value + * @return string + */ + protected function row($name, $value) + { + if (is_bool($value)) { + $value = $value ? 'On' : 'Off'; + } + return + $this->start('tr') . "\n" . + $this->element('th', $name) . "\n" . + $this->element('td', $value) . "\n" . + $this->end('tr'); + } + + /** + * Escapes a string for HTML output. + * @param string $string String to escape + * @return string + */ + protected function escape($string) + { + $string = HTMLPurifier_Encoder::cleanUTF8($string); + $string = htmlspecialchars($string, ENT_COMPAT, 'UTF-8'); + return $string; + } + + /** + * Takes a list of strings and turns them into a single list + * @param string[] $array List of strings + * @param bool $polite Bool whether or not to add an end before the last + * @return string + */ + protected function listify($array, $polite = false) + { + if (empty($array)) { + return 'None'; + } + $ret = ''; + $i = count($array); + foreach ($array as $value) { + $i--; + $ret .= $value; + if ($i > 0 && !($polite && $i == 1)) { + $ret .= ', '; + } + if ($polite && $i == 1) { + $ret .= 'and '; + } + } + return $ret; + } + + /** + * Retrieves the class of an object without prefixes, as well as metadata + * @param object $obj Object to determine class of + * @param string $sec_prefix Further prefix to remove + * @return string + */ + protected function getClass($obj, $sec_prefix = '') + { + static $five = null; + if ($five === null) { + $five = version_compare(PHP_VERSION, '5', '>='); + } + $prefix = 'HTMLPurifier_' . $sec_prefix; + if (!$five) { + $prefix = strtolower($prefix); + } + $class = str_replace($prefix, '', get_class($obj)); + $lclass = strtolower($class); + $class .= '('; + switch ($lclass) { + case 'enum': + $values = array(); + foreach ($obj->valid_values as $value => $bool) { + $values[] = $value; + } + $class .= implode(', ', $values); + break; + case 'css_composite': + $values = array(); + foreach ($obj->defs as $def) { + $values[] = $this->getClass($def, $sec_prefix); + } + $class .= implode(', ', $values); + break; + case 'css_multiple': + $class .= $this->getClass($obj->single, $sec_prefix) . ', '; + $class .= $obj->max; + break; + case 'css_denyelementdecorator': + $class .= $this->getClass($obj->def, $sec_prefix) . ', '; + $class .= $obj->element; + break; + case 'css_importantdecorator': + $class .= $this->getClass($obj->def, $sec_prefix); + if ($obj->allow) { + $class .= ', !important'; + } + break; + } + $class .= ')'; + return $class; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php new file mode 100644 index 0000000..29505fe --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php @@ -0,0 +1,44 @@ +def = $config->getCSSDefinition(); + $ret = ''; + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + $ret .= $this->start('table'); + + $ret .= $this->element('caption', 'Properties ($info)'); + + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Property', array('class' => 'heavy')); + $ret .= $this->element('th', 'Definition', array('class' => 'heavy', 'style' => 'width:auto;')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + + ksort($this->def->info); + foreach ($this->def->info as $property => $obj) { + $name = $this->getClass($obj, 'AttrDef_'); + $ret .= $this->row($property, $name); + } + + $ret .= $this->end('table'); + $ret .= $this->end('div'); + + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css new file mode 100644 index 0000000..3ff1a88 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css @@ -0,0 +1,10 @@ + +.hp-config {} + +.hp-config tbody th {text-align:right; padding-right:0.5em;} +.hp-config thead, .hp-config .namespace {background:#3C578C; color:#FFF;} +.hp-config .namespace th {text-align:center;} +.hp-config .verbose {display:none;} +.hp-config .controls {text-align:center;} + +/* vim: et sw=4 sts=4 */ diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js new file mode 100644 index 0000000..cba00c9 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js @@ -0,0 +1,5 @@ +function toggleWriteability(id_of_patient, checked) { + document.getElementById(id_of_patient).disabled = checked; +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php new file mode 100644 index 0000000..4c3ce17 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php @@ -0,0 +1,456 @@ +docURL = $doc_url; + $this->name = $name; + $this->compress = $compress; + // initialize sub-printers + $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); + $this->fields[HTMLPurifier_VarParser::C_BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); + } + + /** + * Sets default column and row size for textareas in sub-printers + * @param $cols Integer columns of textarea, null to use default + * @param $rows Integer rows of textarea, null to use default + */ + public function setTextareaDimensions($cols = null, $rows = null) + { + if ($cols) { + $this->fields['default']->cols = $cols; + } + if ($rows) { + $this->fields['default']->rows = $rows; + } + } + + /** + * Retrieves styling, in case it is not accessible by webserver + */ + public static function getCSS() + { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); + } + + /** + * Retrieves JavaScript, in case it is not accessible by webserver + */ + public static function getJavaScript() + { + return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); + } + + /** + * Returns HTML output for a configuration form + * @param HTMLPurifier_Config|array $config Configuration object of current form state, or an array + * where [0] has an HTML namespace and [1] is being rendered. + * @param array|bool $allowed Optional namespace(s) and directives to restrict form to. + * @param bool $render_controls + * @return string + */ + public function render($config, $allowed = true, $render_controls = true) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + + $this->config = $config; + $this->genConfig = $gen_config; + $this->prepareGenerator($gen_config); + + $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $config->def); + $all = array(); + foreach ($allowed as $key) { + list($ns, $directive) = $key; + $all[$ns][$directive] = $config->get($ns . '.' . $directive); + } + + $ret = ''; + $ret .= $this->start('table', array('class' => 'hp-config')); + $ret .= $this->start('thead'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); + $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); + $ret .= $this->end('tr'); + $ret .= $this->end('thead'); + foreach ($all as $ns => $directives) { + $ret .= $this->renderNamespace($ns, $directives); + } + if ($render_controls) { + $ret .= $this->start('tbody'); + $ret .= $this->start('tr'); + $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); + $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); + $ret .= '[Reset]'; + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a single namespace + * @param $ns String namespace name + * @param array $directives array of directives to values + * @return string + */ + protected function renderNamespace($ns, $directives) + { + $ret = ''; + $ret .= $this->start('tbody', array('class' => 'namespace')); + $ret .= $this->start('tr'); + $ret .= $this->element('th', $ns, array('colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->end('tbody'); + $ret .= $this->start('tbody'); + foreach ($directives as $directive => $value) { + $ret .= $this->start('tr'); + $ret .= $this->start('th'); + if ($this->docURL) { + $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); + $ret .= $this->start('a', array('href' => $url)); + } + $attr = array('for' => "{$this->name}:$ns.$directive"); + + // crop directive name if it's too long + if (!$this->compress || (strlen($directive) < $this->compress)) { + $directive_disp = $directive; + } else { + $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; + $attr['title'] = $directive; + } + + $ret .= $this->element( + 'label', + $directive_disp, + // component printers must create an element with this id + $attr + ); + if ($this->docURL) { + $ret .= $this->end('a'); + } + $ret .= $this->end('th'); + + $ret .= $this->start('td'); + $def = $this->config->def->info["$ns.$directive"]; + if (is_int($def)) { + $allow_null = $def < 0; + $type = abs($def); + } else { + $type = $def->type; + $allow_null = isset($def->allow_null); + } + if (!isset($this->fields[$type])) { + $type = 0; + } // default + $type_obj = $this->fields[$type]; + if ($allow_null) { + $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); + } + $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); + $ret .= $this->end('td'); + $ret .= $this->end('tr'); + } + $ret .= $this->end('tbody'); + return $ret; + } + +} + +/** + * Printer decorator for directives that accept null + */ +class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer +{ + /** + * Printer being decorated + * @type HTMLPurifier_Printer + */ + protected $obj; + + /** + * @param HTMLPurifier_Printer $obj Printer to decorate + */ + public function __construct($obj) + { + parent::__construct(); + $this->obj = $obj; + } + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + + $ret = ''; + $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Null/Disabled'); + $ret .= $this->end('label'); + $attr = array( + 'type' => 'checkbox', + 'value' => '1', + 'class' => 'null-toggle', + 'name' => "$name" . "[Null_$ns.$directive]", + 'id' => "$name:Null_$ns.$directive", + 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! + ); + if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { + // modify inline javascript slightly + $attr['onclick'] = + "toggleWriteability('$name:Yes_$ns.$directive',checked);" . + "toggleWriteability('$name:No_$ns.$directive',checked)"; + } + if ($value === null) { + $attr['checked'] = 'checked'; + } + $ret .= $this->elementEmpty('input', $attr); + $ret .= $this->text(' or '); + $ret .= $this->elementEmpty('br'); + $ret .= $this->obj->render($ns, $directive, $value, $name, array($gen_config, $config)); + return $ret; + } +} + +/** + * Swiss-army knife configuration form field printer + */ +class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer +{ + /** + * @type int + */ + public $cols = 18; + + /** + * @type int + */ + public $rows = 5; + + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + // this should probably be split up a little + $ret = ''; + $def = $config->def->info["$ns.$directive"]; + if (is_int($def)) { + $type = abs($def); + } else { + $type = $def->type; + } + if (is_array($value)) { + switch ($type) { + case HTMLPurifier_VarParser::LOOKUP: + $array = $value; + $value = array(); + foreach ($array as $val => $b) { + $value[] = $val; + } + //TODO does this need a break? + case HTMLPurifier_VarParser::ALIST: + $value = implode(PHP_EOL, $value); + break; + case HTMLPurifier_VarParser::HASH: + $nvalue = ''; + foreach ($value as $i => $v) { + if (is_array($v)) { + // HACK + $v = implode(";", $v); + } + $nvalue .= "$i:$v" . PHP_EOL; + } + $value = $nvalue; + break; + default: + $value = ''; + } + } + if ($type === HTMLPurifier_VarParser::C_MIXED) { + return 'Not supported'; + $value = serialize($value); + } + $attr = array( + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:$ns.$directive" + ); + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + if (isset($def->allowed)) { + $ret .= $this->start('select', $attr); + foreach ($def->allowed as $val => $b) { + $attr = array(); + if ($value == $val) { + $attr['selected'] = 'selected'; + } + $ret .= $this->element('option', $val, $attr); + } + $ret .= $this->end('select'); + } elseif ($type === HTMLPurifier_VarParser::TEXT || + $type === HTMLPurifier_VarParser::ITEXT || + $type === HTMLPurifier_VarParser::ALIST || + $type === HTMLPurifier_VarParser::HASH || + $type === HTMLPurifier_VarParser::LOOKUP) { + $attr['cols'] = $this->cols; + $attr['rows'] = $this->rows; + $ret .= $this->start('textarea', $attr); + $ret .= $this->text($value); + $ret .= $this->end('textarea'); + } else { + $attr['value'] = $value; + $attr['type'] = 'text'; + $ret .= $this->elementEmpty('input', $attr); + } + return $ret; + } +} + +/** + * Bool form field printer + */ +class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer +{ + /** + * @param string $ns + * @param string $directive + * @param string $value + * @param string $name + * @param HTMLPurifier_Config|array $config + * @return string + */ + public function render($ns, $directive, $value, $name, $config) + { + if (is_array($config) && isset($config[0])) { + $gen_config = $config[0]; + $config = $config[1]; + } else { + $gen_config = $config; + } + $this->prepareGenerator($gen_config); + $ret = ''; + $ret .= $this->start('div', array('id' => "$name:$ns.$directive")); + + $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' Yes'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:Yes_$ns.$directive", + 'value' => '1' + ); + if ($value === true) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); + $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); + $ret .= $this->text(' No'); + $ret .= $this->end('label'); + + $attr = array( + 'type' => 'radio', + 'name' => "$name" . "[$ns.$directive]", + 'id' => "$name:No_$ns.$directive", + 'value' => '0' + ); + if ($value === false) { + $attr['checked'] = 'checked'; + } + if ($value === null) { + $attr['disabled'] = 'disabled'; + } + $ret .= $this->elementEmpty('input', $attr); + + $ret .= $this->end('div'); + + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php new file mode 100644 index 0000000..ae86391 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php @@ -0,0 +1,324 @@ +config =& $config; + + $this->def = $config->getHTMLDefinition(); + + $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer')); + + $ret .= $this->renderDoctype(); + $ret .= $this->renderEnvironment(); + $ret .= $this->renderContentSets(); + $ret .= $this->renderInfo(); + + $ret .= $this->end('div'); + + return $ret; + } + + /** + * Renders the Doctype table + * @return string + */ + protected function renderDoctype() + { + $doctype = $this->def->doctype; + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Doctype'); + $ret .= $this->row('Name', $doctype->name); + $ret .= $this->row('XML', $doctype->xml ? 'Yes' : 'No'); + $ret .= $this->row('Default Modules', implode(', ', $doctype->modules)); + $ret .= $this->row('Default Tidy Modules', implode(', ', $doctype->tidyModules)); + $ret .= $this->end('table'); + return $ret; + } + + + /** + * Renders environment table, which is miscellaneous info + * @return string + */ + protected function renderEnvironment() + { + $def = $this->def; + + $ret = ''; + + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Environment'); + + $ret .= $this->row('Parent of fragment', $def->info_parent); + $ret .= $this->renderChildren($def->info_parent_def->child); + $ret .= $this->row('Block wrap name', $def->info_block_wrapper); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Global attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr), null, 0); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Tag transforms'); + $list = array(); + foreach ($def->info_tag_transform as $old => $new) { + $new = $this->getClass($new, 'TagTransform_'); + $list[] = "<$old> with $new"; + } + $ret .= $this->element('td', $this->listify($list)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre)); + $ret .= $this->end('tr'); + + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post)); + $ret .= $this->end('tr'); + + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Content Sets table + * @return string + */ + protected function renderContentSets() + { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Content Sets'); + foreach ($this->def->info_content_sets as $name => $lookup) { + $ret .= $this->heavyHeader($name); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($lookup)); + $ret .= $this->end('tr'); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders the Elements ($info) table + * @return string + */ + protected function renderInfo() + { + $ret = ''; + $ret .= $this->start('table'); + $ret .= $this->element('caption', 'Elements ($info)'); + ksort($this->def->info); + $ret .= $this->heavyHeader('Allowed tags', 2); + $ret .= $this->start('tr'); + $ret .= $this->element('td', $this->listifyTagLookup($this->def->info), array('colspan' => 2)); + $ret .= $this->end('tr'); + foreach ($this->def->info as $name => $def) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', "<$name>", array('class' => 'heavy', 'colspan' => 2)); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Inline content'); + $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No'); + $ret .= $this->end('tr'); + if (!empty($def->excludes)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Excludes'); + $ret .= $this->element('td', $this->listifyTagLookup($def->excludes)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_pre)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Pre-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre)); + $ret .= $this->end('tr'); + } + if (!empty($def->attr_transform_post)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Post-AttrTransform'); + $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post)); + $ret .= $this->end('tr'); + } + if (!empty($def->auto_close)) { + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Auto closed by'); + $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close)); + $ret .= $this->end('tr'); + } + $ret .= $this->start('tr'); + $ret .= $this->element('th', 'Allowed attributes'); + $ret .= $this->element('td', $this->listifyAttr($def->attr), array(), 0); + $ret .= $this->end('tr'); + + if (!empty($def->required_attr)) { + $ret .= $this->row('Required attributes', $this->listify($def->required_attr)); + } + + $ret .= $this->renderChildren($def->child); + } + $ret .= $this->end('table'); + return $ret; + } + + /** + * Renders a row describing the allowed children of an element + * @param HTMLPurifier_ChildDef $def HTMLPurifier_ChildDef of pertinent element + * @return string + */ + protected function renderChildren($def) + { + $context = new HTMLPurifier_Context(); + $ret = ''; + $ret .= $this->start('tr'); + $elements = array(); + $attr = array(); + if (isset($def->elements)) { + if ($def->type == 'strictblockquote') { + $def->validateChildren(array(), $this->config, $context); + } + $elements = $def->elements; + } + if ($def->type == 'chameleon') { + $attr['rowspan'] = 2; + } elseif ($def->type == 'empty') { + $elements = array(); + } elseif ($def->type == 'table') { + $elements = array_flip( + array( + 'col', + 'caption', + 'colgroup', + 'thead', + 'tfoot', + 'tbody', + 'tr' + ) + ); + } + $ret .= $this->element('th', 'Allowed children', $attr); + + if ($def->type == 'chameleon') { + + $ret .= $this->element( + 'td', + 'Block: ' . + $this->escape($this->listifyTagLookup($def->block->elements)), + null, + 0 + ); + $ret .= $this->end('tr'); + $ret .= $this->start('tr'); + $ret .= $this->element( + 'td', + 'Inline: ' . + $this->escape($this->listifyTagLookup($def->inline->elements)), + null, + 0 + ); + + } elseif ($def->type == 'custom') { + + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $def->dtd_regex + ); + + } else { + $ret .= $this->element( + 'td', + '' . ucfirst($def->type) . ': ' . + $this->escape($this->listifyTagLookup($elements)), + null, + 0 + ); + } + $ret .= $this->end('tr'); + return $ret; + } + + /** + * Listifies a tag lookup table. + * @param array $array Tag lookup array in form of array('tagname' => true) + * @return string + */ + protected function listifyTagLookup($array) + { + ksort($array); + $list = array(); + foreach ($array as $name => $discard) { + if ($name !== '#PCDATA' && !isset($this->def->info[$name])) { + continue; + } + $list[] = $name; + } + return $this->listify($list); + } + + /** + * Listifies a list of objects by retrieving class names and internal state + * @param array $array List of objects + * @return string + * @todo Also add information about internal state + */ + protected function listifyObjectList($array) + { + ksort($array); + $list = array(); + foreach ($array as $obj) { + $list[] = $this->getClass($obj, 'AttrTransform_'); + } + return $this->listify($list); + } + + /** + * Listifies a hash of attributes to AttrDef classes + * @param array $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef) + * @return string + */ + protected function listifyAttr($array) + { + ksort($array); + $list = array(); + foreach ($array as $name => $obj) { + if ($obj === false) { + continue; + } + $list[] = "$name = " . $this->getClass($obj, 'AttrDef_') . ''; + } + return $this->listify($list); + } + + /** + * Creates a heavy header row + * @param string $text + * @param int $num + * @return string + */ + protected function heavyHeader($text, $num = 1) + { + $ret = ''; + $ret .= $this->start('tr'); + $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy')); + $ret .= $this->end('tr'); + return $ret; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php new file mode 100644 index 0000000..189348f --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php @@ -0,0 +1,122 @@ +parent = $parent; + } + + /** + * Recursively retrieves the value for a key + * @param string $name + * @throws HTMLPurifier_Exception + */ + public function get($name) + { + if ($this->has($name)) { + return $this->data[$name]; + } + // possible performance bottleneck, convert to iterative if necessary + if ($this->parent) { + return $this->parent->get($name); + } + throw new HTMLPurifier_Exception("Key '$name' not found"); + } + + /** + * Sets the value of a key, for this plist + * @param string $name + * @param mixed $value + */ + public function set($name, $value) + { + $this->data[$name] = $value; + } + + /** + * Returns true if a given key exists + * @param string $name + * @return bool + */ + public function has($name) + { + return array_key_exists($name, $this->data); + } + + /** + * Resets a value to the value of it's parent, usually the default. If + * no value is specified, the entire plist is reset. + * @param string $name + */ + public function reset($name = null) + { + if ($name == null) { + $this->data = array(); + } else { + unset($this->data[$name]); + } + } + + /** + * Squashes this property list and all of its property lists into a single + * array, and returns the array. This value is cached by default. + * @param bool $force If true, ignores the cache and regenerates the array. + * @return array + */ + public function squash($force = false) + { + if ($this->cache !== null && !$force) { + return $this->cache; + } + if ($this->parent) { + return $this->cache = array_merge($this->parent->squash($force), $this->data); + } else { + return $this->cache = $this->data; + } + } + + /** + * Returns the parent plist. + * @return HTMLPurifier_PropertyList + */ + public function getParent() + { + return $this->parent; + } + + /** + * Sets the parent plist. + * @param HTMLPurifier_PropertyList $plist Parent plist + */ + public function setParent($plist) + { + $this->parent = $plist; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php new file mode 100644 index 0000000..f68fc8c --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php @@ -0,0 +1,43 @@ +l = strlen($filter); + $this->filter = $filter; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function accept() + { + $key = $this->getInnerIterator()->key(); + if (strncmp($key, $this->filter, $this->l) !== 0) { + return false; + } + return true; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php new file mode 100644 index 0000000..f58db90 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php @@ -0,0 +1,56 @@ +input = $input; + $this->output = array(); + } + + /** + * Shifts an element off the front of the queue. + */ + public function shift() { + if (empty($this->output)) { + $this->output = array_reverse($this->input); + $this->input = array(); + } + if (empty($this->output)) { + return NULL; + } + return array_pop($this->output); + } + + /** + * Pushes an element onto the front of the queue. + */ + public function push($x) { + array_push($this->input, $x); + } + + /** + * Checks if it's empty. + */ + public function isEmpty() { + return empty($this->input) && empty($this->output); + } +} diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php new file mode 100644 index 0000000..e1ff3b7 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php @@ -0,0 +1,26 @@ +strategies as $strategy) { + $tokens = $strategy->execute($tokens, $config, $context); + } + return $tokens; + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php new file mode 100644 index 0000000..4414c17 --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php @@ -0,0 +1,17 @@ +strategies[] = new HTMLPurifier_Strategy_RemoveForeignElements(); + $this->strategies[] = new HTMLPurifier_Strategy_MakeWellFormed(); + $this->strategies[] = new HTMLPurifier_Strategy_FixNesting(); + $this->strategies[] = new HTMLPurifier_Strategy_ValidateAttributes(); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php new file mode 100644 index 0000000..6fa673d --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php @@ -0,0 +1,181 @@ +getHTMLDefinition(); + + $excludes_enabled = !$config->get('Core.DisableExcludes'); + + // setup the context variable 'IsInline', for chameleon processing + // is 'false' when we are not inline, 'true' when it must always + // be inline, and an integer when it is inline for a certain + // branch of the document tree + $is_inline = $definition->info_parent_def->descendants_are_inline; + $context->register('IsInline', $is_inline); + + // setup error collector + $e =& $context->get('ErrorCollector', true); + + //####################################################################// + // Loop initialization + + // stack that contains all elements that are excluded + // it is organized by parent elements, similar to $stack, + // but it is only populated when an element with exclusions is + // processed, i.e. there won't be empty exclusions. + $exclude_stack = array($definition->info_parent_def->excludes); + + // variable that contains the start token while we are processing + // nodes. This enables error reporting to do its job + $node = $top_node; + // dummy token + list($token, $d) = $node->toTokenPair(); + $context->register('CurrentNode', $node); + $context->register('CurrentToken', $token); + + //####################################################################// + // Loop + + // We need to implement a post-order traversal iteratively, to + // avoid running into stack space limits. This is pretty tricky + // to reason about, so we just manually stack-ify the recursive + // variant: + // + // function f($node) { + // foreach ($node->children as $child) { + // f($child); + // } + // validate($node); + // } + // + // Thus, we will represent a stack frame as array($node, + // $is_inline, stack of children) + // e.g. array_reverse($node->children) - already processed + // children. + + $parent_def = $definition->info_parent_def; + $stack = array( + array($top_node, + $parent_def->descendants_are_inline, + $parent_def->excludes, // exclusions + 0) + ); + + while (!empty($stack)) { + list($node, $is_inline, $excludes, $ix) = array_pop($stack); + // recursive call + $go = false; + $def = empty($stack) ? $definition->info_parent_def : $definition->info[$node->name]; + while (isset($node->children[$ix])) { + $child = $node->children[$ix++]; + if ($child instanceof HTMLPurifier_Node_Element) { + $go = true; + $stack[] = array($node, $is_inline, $excludes, $ix); + $stack[] = array($child, + // ToDo: I don't think it matters if it's def or + // child_def, but double check this... + $is_inline || $def->descendants_are_inline, + empty($def->excludes) ? $excludes + : array_merge($excludes, $def->excludes), + 0); + break; + } + }; + if ($go) continue; + list($token, $d) = $node->toTokenPair(); + // base case + if ($excludes_enabled && isset($excludes[$node->name])) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node excluded'); + } else { + // XXX I suppose it would be slightly more efficient to + // avoid the allocation here and have children + // strategies handle it + $children = array(); + foreach ($node->children as $child) { + if (!$child->dead) $children[] = $child; + } + $result = $def->child->validateChildren($children, $config, $context); + if ($result === true) { + // nop + $node->children = $children; + } elseif ($result === false) { + $node->dead = true; + if ($e) $e->send(E_ERROR, 'Strategy_FixNesting: Node removed'); + } else { + $node->children = $result; + if ($e) { + // XXX This will miss mutations of internal nodes. Perhaps defer to the child validators + if (empty($result) && !empty($children)) { + $e->send(E_ERROR, 'Strategy_FixNesting: Node contents removed'); + } else if ($result != $children) { + $e->send(E_WARNING, 'Strategy_FixNesting: Node reorganized'); + } + } + } + } + } + + //####################################################################// + // Post-processing + + // remove context variables + $context->destroy('IsInline'); + $context->destroy('CurrentNode'); + $context->destroy('CurrentToken'); + + //####################################################################// + // Return + + return HTMLPurifier_Arborize::flatten($node, $config, $context); + } +} + +// vim: et sw=4 sts=4 diff --git a/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php new file mode 100644 index 0000000..a6eb09e --- /dev/null +++ b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php @@ -0,0 +1,659 @@ +getHTMLDefinition(); + + // local variables + $generator = new HTMLPurifier_Generator($config, $context); + $escape_invalid_tags = $config->get('Core.EscapeInvalidTags'); + // used for autoclose early abortion + $global_parent_allowed_elements = $definition->info_parent_def->child->getAllowedElements($config); + $e = $context->get('ErrorCollector', true); + $i = false; // injector index + list($zipper, $token) = HTMLPurifier_Zipper::fromArray($tokens); + if ($token === NULL) { + return array(); + } + $reprocess = false; // whether or not to reprocess the same token + $stack = array(); + + // member variables + $this->stack =& $stack; + $this->tokens =& $tokens; + $this->token =& $token; + $this->zipper =& $zipper; + $this->config = $config; + $this->context = $context; + + // context variables + $context->register('CurrentNesting', $stack); + $context->register('InputZipper', $zipper); + $context->register('CurrentToken', $token); + + // -- begin INJECTOR -- + + $this->injectors = array(); + + $injectors = $config->getBatch('AutoFormat'); + $def_injectors = $definition->info_injector; + $custom_injectors = $injectors['Custom']; + unset($injectors['Custom']); // special case + foreach ($injectors as $injector => $b) { + // XXX: Fix with a legitimate lookup table of enabled filters + if (strpos($injector, '.') !== false) { + continue; + } + $injector = "HTMLPurifier_Injector_$injector"; + if (!$b) { + continue; + } + $this->injectors[] = new $injector; + } + foreach ($def_injectors as $injector) { + // assumed to be objects + $this->injectors[] = $injector; + } + foreach ($custom_injectors as $injector) { + if (!$injector) { + continue; + } + if (is_string($injector)) { + $injector = "HTMLPurifier_Injector_$injector"; + $injector = new $injector; + } + $this->injectors[] = $injector; + } + + // give the injectors references to the definition and context + // variables for performance reasons + foreach ($this->injectors as $ix => $injector) { + $error = $injector->prepare($config, $context); + if (!$error) { + continue; + } + array_splice($this->injectors, $ix, 1); // rm the injector + trigger_error("Cannot enable {$injector->name} injector because $error is not allowed", E_USER_WARNING); + } + + // -- end INJECTOR -- + + // a note on reprocessing: + // In order to reduce code duplication, whenever some code needs + // to make HTML changes in order to make things "correct", the + // new HTML gets sent through the purifier, regardless of its + // status. This means that if we add a start token, because it + // was totally necessary, we don't have to update nesting; we just + // punt ($reprocess = true; continue;) and it does that for us. + + // isset is in loop because $tokens size changes during loop exec + for (;; + // only increment if we don't need to reprocess + $reprocess ? $reprocess = false : $token = $zipper->next($token)) { + + // check for a rewind + if (is_int($i)) { + // possibility: disable rewinding if the current token has a + // rewind set on it already. This would offer protection from + // infinite loop, but might hinder some advanced rewinding. + $rewind_offset = $this->injectors[$i]->getRewindOffset(); + if (is_int($rewind_offset)) { + for ($j = 0; $j < $rewind_offset; $j++) { + if (empty($zipper->front)) break; + $token = $zipper->prev($token); + // indicate that other injectors should not process this token, + // but we need to reprocess it. See Note [Injector skips] + unset($token->skip[$i]); + $token->rewind = $i; + if ($token instanceof HTMLPurifier_Token_Start) { + array_pop($this->stack); + } elseif ($token instanceof HTMLPurifier_Token_End) { + $this->stack[] = $token->start; + } + } + } + $i = false; + } + + // handle case of document end + if ($token === NULL) { + // kill processing if stack is empty + if (empty($this->stack)) { + break; + } + + // peek + $top_nesting = array_pop($this->stack); + $this->stack[] = $top_nesting; + + // send error [TagClosedSuppress] + if ($e && !isset($top_nesting->armor['MakeWellFormed_TagClosedError'])) { + $e->send(E_NOTICE, 'Strategy_MakeWellFormed: Tag closed by document end', $top_nesting); + } + + // append, don't splice, since this is the end + $token = new HTMLPurifier_Token_End($top_nesting->name); + + // punt! + $reprocess = true; + continue; + } + + //echo '
'; printZipper($zipper, $token);//printTokens($this->stack); + //flush(); + + // quick-check: if it's not a tag, no need to process + if (empty($token->is_tag)) { + if ($token instanceof HTMLPurifier_Token_Text) { + foreach ($this->injectors as $i => $injector) { + if (isset($token->skip[$i])) { + // See Note [Injector skips] + continue; + } + if ($token->rewind !== null && $token->rewind !== $i) { + continue; + } + // XXX fuckup + $r = $token; + $injector->handleText($r); + $token = $this->processToken($r, $i); + $reprocess = true; + break; + } + } + // another possibility is a comment + continue; + } + + if (isset($definition->info[$token->name])) { + $type = $definition->info[$token->name]->child->type; + } else { + $type = false; // Type is unknown, treat accordingly + } + + // quick tag checks: anything that's *not* an end tag + $ok = false; + if ($type === 'empty' && $token instanceof HTMLPurifier_Token_Start) { + // claims to be a start tag but is empty + $token = new HTMLPurifier_Token_Empty( + $token->name, + $token->attr, + $token->line, + $token->col, + $token->armor + ); + $ok = true; + } elseif ($type && $type !== 'empty' && $token instanceof HTMLPurifier_Token_Empty) { + // claims to be empty but really is a start tag + // NB: this assignment is required + $old_token = $token; + $token = new HTMLPurifier_Token_End($token->name); + $token = $this->insertBefore( + new HTMLPurifier_Token_Start($old_token->name, $old_token->attr, $old_token->line, $old_token->col, $old_token->armor) + ); + // punt (since we had to modify the input stream in a non-trivial way) + $reprocess = true; + continue; + } elseif ($token instanceof HTMLPurifier_Token_Empty) { + // real empty token + $ok = true; + } elseif ($token instanceof HTMLPurifier_Token_Start) { + // start tag + + // ...unless they also have to close their parent + if (!empty($this->stack)) { + + // Performance note: you might think that it's rather + // inefficient, recalculating the autoclose information + // for every tag that a token closes (since when we + // do an autoclose, we push a new token into the + // stream and then /process/ that, before + // re-processing this token.) But this is + // necessary, because an injector can make an + // arbitrary transformations to the autoclosing + // tokens we introduce, so things may have changed + // in the meantime. Also, doing the inefficient thing is + // "easy" to reason about (for certain perverse definitions + // of "easy") + + $parent = array_pop($this->stack); + $this->stack[] = $parent; + + $parent_def = null; + $parent_elements = null; + $autoclose = false; + if (isset($definition->info[$parent->name])) { + $parent_def = $definition->info[$parent->name]; + $parent_elements = $parent_def->child->getAllowedElements($config); + $autoclose = !isset($parent_elements[$token->name]); + } + + if ($autoclose && $definition->info[$token->name]->wrap) { + // Check if an element can be wrapped by another + // element to make it valid in a context (for + // example,