guzzle = new Client(); } /** * 订单回调处理 * * @param $orderId * @return bool * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException */ public function callBackToCp($orderId) { $where = []; $where['orderid'] = $orderId; $where['status'] = 0; $where['payflag'] = 1; $payCpInfoModel = model('PayCpinfo'); $cpInfo = $payCpInfoModel->where($where)->find(); if (!$cpInfo) { $this->setError('订单不存在,或订单已通知成功'); return false; } $callback_url = $cpInfo['fcallbackurl']; // 回调地址 $callback_params = $cpInfo['params']; // 通知参数 // php自身做回调通知 $result = $this->_doCallback($callback_url, $callback_params); $msg = 'orderid:' . $orderId . ' - url:' . $callback_url . ' - params:' . json_encode($callback_params).' - result: '.$result; if (!$result) { //发起异步通知 $this->_asyncNotify($callback_url, $callback_params, $orderId); $log_msg = "[CP同步回调-ERROR] " . $msg; log_message($log_msg, 'error', LOG_PATH . 'callBacklog/'); $this->setError('同步回调通知失败'); $template = "厂商回调失败,订单号:" . $orderId; $ddurl = Env::get('dingtalk.warning_url'); curlDD($template, $ddurl, true); return false; } $log_msg = "[CP同步回调-SUCCESS] " . $msg; log_message($log_msg, 'log', LOG_PATH . 'callBacklog/'); if (!$res = $payCpInfoModel->save(['status' => 1, 'update_time' => time()], ['id' => $cpInfo['id']])) { return false; } // $this->specialCallback($callback_params); return true; } private function _doCallback($callback_url, $callback_params, $retry_times = 1, $sleep = 5) { $times = 0; // 将字符串参数转为数组形式 if (!is_array($callback_params)) { parse_str($callback_params, $callback_params); } while ($times < $retry_times) { $callback_result = $this->_doPost($callback_url, $callback_params); if (0 == strcasecmp($callback_result, 'success')) { return true; } $times++; //sleep($sleep); } } private function _doPost($url, $param) { try { $result = $this->guzzle->request('post', $url, ['form_params' => $param, 'timeout' => 20]); } catch (GuzzleException $exception) { //todo 错误信息记录 $msg = 'GuzzleExceptiont同步回调通知CP,url地址为:' . $url . '参数:' . json_encode($param) . ' exception:' . $exception->getMessage(); //Log::info($msg); log_message($msg, 'log', LOG_PATH . 'callBacklog/'); return false; } return $result->getBody(); } public function setError($msg) { $this->_error = $msg; } public function getError() { return $this->_error; } /** * 异步通知 * @param $callback_url string * @param $post_data 要post的数据 */ private function _asyncNotify($callback_url, $post_data, $orderId) { $task = []; $task['url'] = $callback_url; $task['http_method'] = 'post'; $task['content_type'] = 'query_string'; $task['params'] = $post_data; $task['orderid'] = $orderId; $task['success_flag'] = 'success'; // 回调CP,收到什么样的结果,视为成功 // 1.当前任务将由哪个类来负责处理。 // 当轮到该任务时,系统将生成一个该类的实例,并调用其 fire 方法 $jobHandlerClassName = 'app\crontab\controller\asyncCallback'; // 2.当前任务归属的队列名称,如果为新队列,会自动创建 $jobQueueName = "asyncCallback"; // 3.当前任务所需的业务数据 . 不能为 resource 类型,其他类型最终将转化为json形式的字符串 // ( jobData 为对象时,需要在先在此处手动序列化,否则只存储其public属性的键值对) // 4.将该任务推送到消息队列,等待对应的消费者去执行 $isPushed = Queue::push($jobHandlerClassName, $task, $jobQueueName); // database 驱动时,返回值为 1|false ; redis 驱动时,返回值为 随机字符串|false if ($isPushed !== false) { //Log::info(date('Y-m-d H:i:s') . " a new _asyncNotify Job is Pushed to the MQ"); log_message(date('Y-m-d H:i:s') . " a new _asyncNotify Job is Pushed to the MQ", 'log', LOG_PATH . 'callBacklog/'); } else { $msg = 'orderid:' . $orderId . '回调通知CP,url地址为:' . $callback_url . '参数:' . $post_data; //Log::info('CP回调redis入队失败' . $msg); log_message(" CP回调redis入队失败", 'log', LOG_PATH . 'callBacklog/'); } } /** * 特殊回调接口 * @param $callback_params * @return bool */ public function specialCallback($callback_params) { try { // 将字符串参数转为数组形式 if (!is_array($callback_params)) { parse_str($callback_params, $callback_params); } (new SpecialService())->welfare($callback_params); if (in_array($callback_params['gameid'], [157, 158])) { $param = [ 'ctype' => 'yiyou', 'applyId' => $callback_params['orderid'], 'userId' => $callback_params['username'], 'roleId' => $callback_params['roleid'], 'serverId' => $callback_params['serverid'], 'money' => $callback_params['amount'], 'time' => time(), ]; $param['sign'] = $this->_setGitemSign($param, 'd377f720058237y8c69g9062bff251d6'); $callback_url = 'https://api.gamedreamsky.com/gitem_channel_pay/welfare'; $result = curl($callback_url,$param,true); if ($result['code']!=1) { $template = '推送异常:https://api.gamedreamsky.com/gitem_channel_pay/welfare?' . http_build_query($param) . ' ' . $result['msg']; $ddurl = Env::get('dingtalk.warning_url'); curlDD($template, $ddurl, true); }else{ $msg = '推送成功:https://api.gamedreamsky.com/gitem_channel_pay/welfare?' . http_build_query($param); log_message($msg, 'log', LOG_PATH . 'callBacklog/specialCallback/'); } } } catch (Exception $e) { $template = '推送异常' . $e->getMessage() . $callback_params; $ddurl = Env::get('dingtalk.warning_url'); curlDD($template, $ddurl, true); } return true; } private function _setGitemSign($_srcData, $_key) { // step 1.1 ksort($_srcData); $signStr = ""; foreach ($_srcData as $k => $v) { if ("sign" != $k && !empty($v)) { $signStr .= $k . "=" . $v . "&"; } } // step 2.2 $signStr .= "key=" . $_key; $sign = md5($signStr); return $sign; } }