getGateUrl().'/v1/api/pay/order'; $return = request()->all(); $re_type = 'json'; if (isset($return['re_type'])) { $re_type = $return['re_type']; } //商户号 $accountId = $this->pay_config['mch_id']; //商户秘钥 $key = $this->pay_config['token']; $payData = [ 'merchantId' => $accountId,//商户 'merchantNo' => strval($this->order['order_sn']),//订单号 'currency' => 'USDT',//类型 'amount' => $pay_data['total_amount'], //支付金额为ustd个数 'address' => $this->order['usdt_addr'], //支付收款地址 'nonce' => strval(mt_rand(10000,99999)),//随机数 'notifyUrl' => strval($this->pay_config['notify_url']),//异步回调地址 'timestamp' => time()*1000,// ]; $this->debugLog('请求的数据接口配置信息' . strval(json_encode($this->pay_config)), []); $sign= $this->sign($payData,$key,[]); $payData['sign'] = $sign; // $res=$this->ddcurl($createUrl,json_encode($payData,256),false); $res = Curl::to($createUrl)->withData($payData)->post(); $this->debugLog('下单接口请求内容' . json_encode($payData, 256), []); $this->debugLog('返回内容' . json_encode($res, 256), []); $res = is_array($res) ? $res : json_decode($res, true); if (is_array($res) && isset($res['code']) && $res['code'] == 0) { $msg = $res['msg'] ?? '未知错误'; $url = $this->order['usdt_addr']; return $this->returnPayRes($re_type, '', 1, $url); } else { $msg = $res['msg'] ?? '未知错误'; $this->debugLog('错误' . $msg, []); return $this->returnPayRes($re_type, $msg, 0); } } protected function returnPayRes($re_type,$msg,$code,$url=''){ if ($code == 1) { if ($re_type == 'json') { return json_encode(['code' => 1, 'usdt_addr' => $url], 256); } else { return redirect()->away($url); } } else { if ($re_type == 'json') { return json_encode(['code' => 0, 'msg' => $msg], 256); } else { return $msg; } } } public function sign($tempArr, $signKey,$filter=[]): string { $keyVal = ''; if (isset($tempArr['sign'])) { unset($tempArr['sign']); } ksort($tempArr); $data = []; foreach ($tempArr as $key => $value) { if(!in_array($key,$filter)){ array_push($data, "{$key}={$value}"); } } $keyVal = implode('&', $data); if (!empty($signKey) && is_string($signKey)) { $keyVal .= $signKey; } return md5($keyVal); } /** * 检查订单 * @param $orderid * @return bool|string */ private function checkOrder($orderid) { // $url = $this->getGateUrl() . '/getpay'; // $payData = [ // 'id' => $orderid // ]; //// $key = $this->pay_config['token']; //// $sign = $this->sign($payData, $key); //// $payData['sign'] = $sign; // Log::channel('pay_order')->info('查询接口请求', $payData); // $responseRaw = Curl::to($url)->withData($payData)->get(); //// $responseRaw = $this->ddcurl($url, $payData, false); // $response = is_array($responseRaw) ? $responseRaw : json_decode($responseRaw, 256); //// $this->debugLog('查询接口返回' . is_array($res) ? json_encode($res, true) : json_encode(json_decode($res, 256), true)); // Log::channel('pay_order')->info('查询接口返回', $response); // if (is_array($response) // && isset($response['code']) && $response['code'] == 1 // ) { // $data=json_decode($response['data'],true); // if($data['state']==4){ // return true; // } // } return false; } //返回给支付商的成功 public function success() { echo 'success'; exit; } //统一回调处理 /** * 回调第一部,如果是同步,直接回传 * @param $return * @param $pay_type * @param $request * @return bool|\Illuminate\Http\RedirectResponse */ public function notify($return, $pay_type, $request) { // $request = json_decode(file_get_contents('php://input'), true); $allData = $request->all(); $this->setLogName($pay_type); $this->debugLog('回调原始数据'.json_encode($allData), $allData ); if (!is_array($allData)) { $this->debugLog('参数异常'); return '参数异常'; } $this->pay_type = $pay_type; $this->request = $request; //取得订单,是否有此订单,如果没有直接返回空 $order_sn = $allData['merchantNo']; $status = $allData['status']; if ($status != 'SUCCESS') { return '未支付成功'; } //取得订单 $this->getOrder($order_sn); $return = ($return) ? 1 : 0; if ($return) { //判断是否是商户id if ($this->order->merchant_id == 0) { return redirect()->route('web.user.index'); } // return $this->merchantReturnSend(); } //取得通道id $this->gateway = $this->pay_gateway = config('gateway.config')[$this->gateway_id]; //dd($this->gateway); $checkresult = $this->checkWhiteIP($this->gateway);//检查回调IP if (!$checkresult) { $this->debugLog('ip 不合法'); return 'ip 不合法'; } //取得支付配置 $this->payConfig($this->pay_type); $this->result_data = $allData; // $this->debugLog('回调原始数据', $this->result_data); //检查三方的订单 if($allData['amount'] != $this->order['order_money']){ $this->debugLog('金额不正确'); return '金额不正确'; } if($allData['toAddress'] != $this->order['usdt_addr']){ $this->debugLog('数字货币地址不正确'); return '数字货币地址不正确'; } // $out_trade_no=strval($allData['id']); // $checkorder = $this->checkOrder($out_trade_no); // if (!$checkorder) { // $this->debugLog('查询三方订单未支付成功'); // return '查询三方订单未支付成功'; // } // dump($this->result_data); //进行验证签名 if (!$this->verify()) { $this->debugLog('签名以及支付状态验证失败'); return '签名以及支付状态验证失败'; } return $this->payNotify(); } //统一验证签名 public function verify() { $params = $this->result_data; $key = $this->pay_config['token']; $sign=$this->sign($params,$key,['sign']); if (isset($params['sign']) && $sign == $params['sign']) { return true; } else { return false; } } /** * 同步回调 * @return \Illuminate\Http\RedirectResponse */ public function returnPay() { //判断是否是商户id if ($this->order->merchant_id == 0) { return redirect()->route('web.user.index'); } // return $this->merchantReturnSend(); } //异步回调 /** * 获得通道信息,取得支付配置模型,验证签名, * @return bool|void */ private function payNotify() { //取得通道信息内容 $data = $this->result_data; $this->pay_data = $this->result_data; //如果应答状态不是01/A6表示支付失败 $this->debugLog(json_encode($data, true)); $this->debugLog('-------------' . $this->order->order_sn . '--选择----' . $this->pay_type . '----' . $this->pay_method . '----开始回调处理-------------------------'); if (empty($data)) { return $this->debugLog('验证签名失败', $data); } try { $pay_cn_name = ''; //统一格式化 $this->unionHandle($data); //支付返回信息 $this->pay_data = $data; $this->debugLog('验证签名成功,数据', $data); //更新订单 $this->updateOrder(); $this->debugLog('updateOrder Ok'); } catch (\Exception $exception) { $this->debugLog('失败异常内容:' . $exception->getMessage()); $this->order->notify_status = 1;//支付回调成功 $this->order->pay_status = 1;//支付状态 $this->order->pay_ok_at = date('Y-m-d H:i:s'); $this->order->save();//保存 Log::channel('pay_success')->info($pay_cn_name . '支付成功,但处理订单失败', ['data' => json_encode($data)]); } } /** * 统一格式化 */ public function unionHandle($data) { $result = [ 'order_sn' => $data['merchantNo'],//我方订单号 'pay_order_sn' => $data['orderNo'],//三方的订单号 'pay_money' => $data['amount'], //支付金额, // 'pay_money' => $data['real_fee'], //支付金额, 'money' => $data['amount'], 'pay_type' => $this->pay_type, 'ewm_name' => $data['fromAddress'], 'account' => '' ]; $this->setResult($result); Log::channel('pay_success')->info('支付成功', [ 'pay_type' => $result['pay_type'], 'pay_money' => $result['pay_money'], 'account' => $result['money'], 'order_sn' => $result['order_sn'], 'pay_order_sn' => $result['pay_order_sn']]); } /** * 这个调试需要配置在config/logging.php * @param $pay_type */ public function setLogName($pay_type) { $this->log_name = $pay_type; } /** * 模拟post提交 json数据 请求接口 * @param string $url * @param bool|true $https * @param string $method * @param string $param * @return mixed */ private function ddcurl($url = '', $param = '', $https = true, $method = 'post') { $param = json_encode($param, 320); $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); #判断是否为https请求 if ($https === true) { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } #判断是否为post请求 if ($method == 'post') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $param); } curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type:application/json')); $str = curl_exec($ch); curl_close($ch); return $str; } public function beforeCreateOrder(&$orderData,&$orderInfo){ //需要增加订单表的usdt_addr $ret = $this->getUstdAddr(); if(empty($ret)){ $this->addError(['msg' => '没有可用的usdt地址']); return false; } $orderData['usdt_addr'] = $ret; $this->debugLog("usdt_add_getis".$ret); } private function getUstdAddr(){ DB::beginTransaction(); $addr = UsdtAddr::where('is_checked',1)->orderby('updated_at','asc')->first(); if (!$addr){ $addr['is_checked'] = 0; $ret = $addr['addr']; $r = $addr->save(); if ($r) { DB::commit(); return $ret; } else { DB::rollBack(); return false; } }else{ DB::rollBack(); return false; } } }