'ok', # 快手错误代码 '4013001' => 'appKey参数缺失', '4013022' => '黑名单', '4012004' => '查询不到该手机号信息', '4013017' => '商品售价参数错误', '4013008' => 'Param参数缺失', '4013007' => '签名校验失败', # 小于0为失败 -1 => 'appid为空', -2 => '产品错误', -3 => 'appid无效', -4 => '余额不足或者没有传入价格', -5 => 'signature不能为空', -6 => 'nonce不能为空', -7 => 'time不能为空', -8 => 'signature已失效', -9 => 'signature验证失败', -100 => '请求错误', -101 => '订单不存在', -102 => '订单号重复', -1000 => '系统维护中', ); public function initialize(): void { parent::initialize(); $this->sign_type = sysconf('sign_type'); if ($this->check) { $this->check(); } } # 获取输入的信息 public function input(): void { $this->input = input(); Log::write('openapi', 'kuaishou_request', $this->input);#写入到日志里 if (isset($this->input['test'])) { $this->testtrue = 1; } else { $this->testtrue = 2; } # $this->agentId = input('appkey'); if (!$this->agentId) { $this->noKS(4013001); } if (is_string($this->input['param'])) { $this->input['param'] = json_decode($this->input['param'], true); } // var_dump($this->input['param']);die; $this->input = $inputData = $this->input['param']; $this->bizType = $inputData['bizType']; if ($inputData['bizType'] == '10') { $this->agentId = $this->agentId . '_KC'; } if (isset($inputData['sellerId']) && $inputData['sellerId']){ $this->agentId = $this->agentId . '_S_'.$inputData['sellerId']; } if (!$this->input) { $this->noKS(4013008); } $this->mappingid = $inputData['relItemId']; // $this->product = 'dhcz'; if ($this->mappingid) { # 根据产品id 获取信息 $pinfo = MerchantMappingProductService::instance()->getOne($this->mappingid); // $pinfo = MerchatMappingProductService::instance()->getOne($this->mappingid); $this->pinfo = $pinfo; // if($pinfo) if (!$pinfo) { $this->product = 'dhcz'; } else { $this->product = $pinfo['key']; } } else { $this->product = 'dhcz'; } // $this->product = 'dhcz'; $this->order = $inputData['orderId']; $this->ksorder = $inputData['ksOrderId']; $this->salePrice = $inputData['price']; $this->cash = $inputData['amount'] / 100; $this->input['cash'] = $this->cash; $this->input['order'] = $this->order; $this->encryptAccount = $inputData['encryptAccount']; $this->input['getMobile_num'] = 0; unset($this->input['orderId']); # 从数据库中或者缓存中取出商户的信息,并验证是否有效 $this->getMerchant(); $this->card = $this->getMobile(); $this->input['card'] = $this->card; $this->input['mobile'] = $this->input['card']; if ($this->product == 'dhcz') { $this->getNewProduct(); } if (isset($this->input['ksOrderId'])) { $this->input['parent_order_id'] = $this->input['ksOrderId']; } } public function getNewProduct(): void { if (is_string($this->merchant['other_param'])) { $array = json_decode($this->merchant['other_param'], true); if (is_array($array)) { if (isset($array['phone_global_sub_product']) && $array['phone_global_sub_product'] == 1) { $isp = Service::instance()->isp($this->input['mobile']); if ($isp == 1) { $this->product = 'ydcz'; } elseif ($isp == 2) { $this->product = 'ltcz'; } elseif ($isp == 3) { $this->product = 'dxcz'; } } } } } /** * 检测输入信息是否合法 */ protected function check() { } # 检测开放或者维护时间 protected function checkOpenTime($opentime): void { if ($opentime && strstr($opentime, ':')) { $opentime = str_replace(':', '', $opentime); if (str_contains($opentime, '-')) { $value = explode('-', $opentime); $cur = intval(date('Hi')); $value[0] = intval($value[0]); $value[1] = intval($value[1]); if ($value[1] < $value[0]) { if ($cur >= $value[0] || $cur < $value[1]) { $this->noKS(-1000); } } else { if ($cur >= $value[0] && $cur < $value[1]) { $this->noKS(-1000); } } } } } /** * 对输入的信息进行加密 */ protected function getSignature() { $this->input(); $input = $this->input; if ($this->proid) { unset($input['cash']); } return AuthService::get($input, $this->key, $this->sign_type); } public function test1($notify_url, $post_data): mixed { // $postdata = http_build_query($post_data); $options = array( 'http' => array( 'method' => 'POST', 'header' => 'Content-type:application/x-www-form-urlencoded', 'timeout' => 15 * 60 // 超时时间(单位:s) ) ); $context = stream_context_create($options, $post_data); $result = file_get_contents($notify_url, false, $context); return $result; } public static function get_curl_post($geturl): mixed { $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => $geturl, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_HTTPHEADER => array( 'User-Agent: Apifox/1.0.0 (https://apifox.com)', 'Accept: */*', 'Host: openapi.kwaixiaodian.com', 'Connection: keep-alive', 'Content-Type: application/x-www-form-urlencoded' ), )); $response = curl_exec($curl); curl_close($curl); return $response; } # 获取商户信息 protected function getMobile() { // $getUrl = 'https://openapi.kwaixiaodian.com/open/industry/virtual/order/decrypt?'; $param = array(); $param['decryptList'][0] = array( 'encryptedData' => $this->encryptAccount, 'sceneType' => '1' ); $param['orderId'] = $this->ksorder; $param = json_encode($param); $post_data = array( 'appkey' => $this->agentId, 'method' => 'open.industry.virtual.order.decrypt', 'param' => urlencode($param), 'version' => 1, 'signMethod' => 'MD5', 'timestamp' => time() ); if (isset($this->access_token) && $this->access_token_time > time() && $this->testtrue != 1) { $post_data['access_token'] = $this->access_token; } else { $post_data['access_token'] = $this->getKuaishouToken(); // var_dump($this->input);die; if ($post_data['access_token'] == 'error') { return $this->noKS('4012004'); } } $post_data['sign'] = $this->sign($post_data, $param); $getUrl = 'https://open.kwaixiaodian.com/open/industry/virtual/order/decrypt?access_token=' . $post_data['access_token'] . '&method=open.industry.virtual.order.decrypt¶m=' . $post_data['param'] . '&sign=' . $post_data['sign'] . '&appkey=' . $post_data['appkey'] . '&version=1&signMethod=MD5×tamp=' . $post_data['timestamp']; $result = $this->get_curl_post($getUrl); $result = json_decode($result, true); $num = $this->input['getMobile_num']; $num++; if ($result['result'] == 1) { $result = $result['data'][0]['decryptedData']; } elseif ($num < 3) { $this->input['getMobile_num'] = $num; $this->getMobile(); } return $result; } #sing签名 public function sign($post_data, $paramJson): string { // $keys = '16fb1715cc284e2653a13f40e2e813f9'; $signData = 'access_token=' . $post_data['access_token'] . '&appkey=' . $post_data['appkey'] . '&method=open.industry.virtual.order.decrypt¶m=' . $paramJson . '&signMethod=MD5×tamp=' . $post_data['timestamp'] . '&version=1&signSecret=' . $this->signkey; return (md5($signData)); } //发送回调 public function send_post($notify_url, $post_data, $type): mixed { $postdate = http_build_query($post_data); $options = array( 'http' => array( 'method' => $type, 'header' => 'Content-type:application/x-www-form-urlencoded', 'content' => $postdate, 'timeout' => 15 * 60 // 超时时间(单位:s) ) ); $context = stream_context_create($options); return file_get_contents($notify_url, false, $context); } #测试 /** * @param $url * @return bool */ public function send_get($url): bool { $curl = curl_init(); //初始化 curl_setopt($curl, CURLOPT_URL, $url); //设置抓取的url curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //设置获取的信息以文件流的形式返回,而不是直接输出。 $output = curl_exec($curl); //执行命令 curl_close($curl); //关闭URL请求 return $output; } protected function getMerchant(): void { $this->merchant = MerchantService::instance()->get('PT_' . $this->agentId); if (str_contains($this->agentId, "_S_")) { $agentId = explode('_S_',$this->agentId); $this->agentId = $agentId[0]; } if (str_ends_with($this->agentId, "_KC")) { $this->agentId = substr($this->agentId, 0, -3); } $this->mid = $this->merchant['id']; // $this->agentId = $this->merchant['agentId']; $this->agentkey = $this->merchant['agentkey']; $this->refresh_token = $this->merchant['refresh_token']; $this->access_token_time = $this->merchant['access_token_time']; $this->access_token = $this->merchant['access_token']; $this->callnotify = $this->merchant['notify_url']; $this->signkey = $this->merchant['other_key']; } # 查找订单 protected function getOrder($order_id, $merchant_order_id = false) { $orderService = OrderService::instance(); $order = $orderService->get($order_id, $merchant_order_id, $this->mid); if (!$order) { $orderLastweekHistoryService = OrderLastweekHistoryService::instance(); $order = $orderLastweekHistoryService->get($order_id, $merchant_order_id, $this->mid); } if (!$order) { $orderLastHistoryService = OrderLastHistoryService::instance(); $order = $orderLastHistoryService->get($order_id, $merchant_order_id, $this->mid); } if (!$order) { $orderTwoHistoryService = OrderTwoHistoryService::instance(); $order = $orderTwoHistoryService->get($order_id, $merchant_order_id, $this->mid); } if (!$order) { $orderHistoryService = OrderHistoryService::instance(); $order = $orderHistoryService->get($order_id, $merchant_order_id, $this->mid); } return $order; } # 通用签名方法,如果有渠道不同的签名方式,需要单独实现 # 调取服务 protected function channel($merchant, $product, $async = false, $param = false, $order = '') { if (!$param) { $param = $this->input; } return ChannelService::instance()->use($merchant, $product, $param, $async, $order); } /** * 返回快手下单失败的消息 * @param integer $code * @param string $ksOrderNo * @param string $error_msg * @param string $qudao */ protected function noKS($code = 0, $ksOrderNo = '', $error_msg = '', $qudao = '') { $msg = $this->code[$code] ?? 'error'; if ($error_msg) { $error_msg = $msg . ':' . $error_msg; } elseif ($msg != 'error') { $error_msg = $msg; } $data = array( 'createTime' => date('c'), 'orderNo' => 'E' . $ksOrderNo, 'orederId' => $ksOrderNo, 'status' => 'FAILED' ); $msg = array( 'result' => $code, 'error_msg' => $error_msg, 'data' => $data ); throw new HttpResponseException(json($msg)); // $this->error($msg, $data, $code); } /** * 返回成功的消息 * @param string $data * @param string $qudao * @param string $OrderNo * @param mixed $info * @return mixed */ protected function yesks($data = '{-null-}', $qudao = '', $OrderNo = '', $info = false) { if (is_string($data) && $data != 'ok') { if ($data == '订单号重复') { $data = $this->getOrder('', $OrderNo); $ksdata = array( 'createTime' => date('c'), 'orderNo' => $OrderNo, 'orederId' => $data['order_id'], 'status' => 'ACCEPTED' ); $ksmsg = array( 'result' => '1', 'data' => $ksdata ); throw new HttpResponseException(json($ksmsg)); } elseif (str_contains($data, '已被列入黑名单')) { $this->blackks($OrderNo); } return $this->noKS('JDI_00001', $OrderNo); } switch ($qudao) { case 'submit': $data = $this->getOrder('', $OrderNo); $ksdata = array( 'createTime' => date('c'), 'orderNo' => $OrderNo, 'orederId' => $data['order_id'], 'status' => 'ACCEPTED' ); $ksmsg = array( 'result' => '1', 'data' => $ksdata ); break; case '': break; default: } throw new HttpResponseException(json($ksmsg)); } /** * 返回并拉黑的消息 * @param mixed $info * @param string $data * @param integer $code */ protected function blackks($OrderNo = '') { $ksdata = array( 'createTime' => date('c'), 'orderNo' => $OrderNo, 'orederId' => 'E' . $OrderNo, 'status' => 'ACCEPTED' ); $ksmsg = array( 'result' => '1', 'data' => $ksdata ); $setData = array( 'mid' => $this->mid, 'orderNo' => $OrderNo, 'agentkey' => $this->agentkey, 'notify_url' => $this->callnotify, 'agentId' => $this->agentId, 'access_token' => $this->access_token, ); try { #推送到redis队列 $this->queue('blackcall', $setData); } catch (Exception $e) { Log::write('gateway', 'redis_kuaishou_black', $setData); Log::write('errorTip', 'redis', $e->getMessage()); } throw new HttpResponseException(json($ksmsg)); //TODO 需要处理redis } #获取解密接口 protected function decrypt($merchant, $product, $async = false, $param = false, $order = '') { if (!$param) { $param = $this->input; } if ($product == 'cardbuy') { $async = false; } return ChannelService::instance()->use($merchant, $product, $param, $async, $order); } # 记录日志 protected function log($data) { Log::write('gateway', 'callback', $data); } # 队列 protected function queue($key, $value = false) { $redis = RedisService::getInstance(); if (!$value) { return $redis->pop($key); } else { return $redis->push($key, $value); } } #获取快手token public function getKuaishouToken() { $tokenurl = 'https://openapi.kwaixiaodian.com/oauth2/refresh_token'; $token_data = array( 'grant_type' => 'refresh_token', 'refresh_token' => $this->refresh_token, 'app_id' => $this->agentId, 'app_secret' => $this->agentkey ); try { $resulttoken = $this->send_post($tokenurl, $token_data, 'POST'); $tokenresult = json_decode($resulttoken, true); if ($tokenresult['result'] != 1) { #判断未获取数据 Log::write('errorTip', 'getKSToken_error', $resulttoken); return 'error'; } } catch (Exception $e) { Log::write('errorTip', 'getKSToken_error', $e->getMessage()); return 'error'; } // var_dump($resulttoken);die; #更新refresh_token $updaterefresh_token = array( 'refresh_token' => $tokenresult['refresh_token'], 'access_token' => $tokenresult['access_token'], 'access_token_time' => time() + $tokenresult['expires_in'] ); // MerchantService::instance()->db() //// ->where(array('id' => $this->mid)) // ->whereLike('agentId', "%" . $this->agentId . '%')->update($updaterefresh_token); MerchantService::instance()->db()->where(['id'=>$this->mid])->update($updaterefresh_token); Log::write('gateway', 'token', $tokenresult); return $tokenresult['access_token']; } }