| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- <?php
- namespace app\common\logic;
- use app\api\service\SpecialService;
- use GuzzleHttp\Client;
- use GuzzleHttp\Exception\GuzzleException;
- use think\Env;
- use think\Exception;
- use think\Log;
- use think\Queue;
- class PayCallback
- {
- public $guzzle;
- private $_error;
- public function __construct()
- {
- $this->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;
- }
- }
|