公司要整一个扫码支付然后有个后台能查看交易记录,然后百度搜寻,决定使用laytp2.0框架搭后台。
参考了以下文档:
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_1.shtml
https://github.com/wechatpay-apiv3/wechatpay-php
https://www.laytp.com/doc/laytp/1.html
配置啥的不阐述了,代码大致流程:获取code,code获取openid,jsapi下单获取prepay_id,然后配置支付参数组装验签,调用微信支付,支付成功后回调,成功跳转页面。
前端代码:
form.on('submit(pay)', function (data) { var buttonAnim = layui.button.load({elem: '.pay'}); //判断有没有code var code = GetQueryString('code'); //有code if (code !== undefined && code !== '' && code !== null) { var openid = GetQueryString('openid'); data.field.openid = openid; $.ajax({ url: '/payment.wechat/jsApiPay', type: 'post', dataType: 'json', contentType: "application/json", data: JSON.stringify(data.field), success: function (inf) { if (inf.code === 0) { let order = inf.data $.get('/payment.wechat/payConfig', {prepay_id: inf.data.prepay_id}, function (sign) { WeixinJSBridge.invoke('getBrandWCPayRequest', sign, function(res){if (res.err_msg == "get_brand_wcpay_request:ok") { window.location.href='xxxxxxxx/wechatSuccess.html?amount='+order.amount+'&out_trade_no='+order.order_sn+'&success_time='+order.create_time;} else if (res.err_msg == 'get_brand_wcpay_request:cancel') { alert('支付已取消');} else { alert(JSON.stringify(res));} }); }) } else { console.log(res.code) console.log(res.msg) } } }) } else { //没有code //微信获取code $.ajax({ url: '/payment.wechat/getCode', type: 'get', dataType: 'json', contentType: "application/json", crossDomain: true, success: function (res) { console.log(res) } }); } buttonAnim.stop(); return false;});//截取当前路径的参数function GetQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if (r != null) { //解决中文乱码 return decodeURI(r[2]); } return null;}
后端代码:
//获取codepublic function getCode(){ $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . $this->appid.'&redirect_uri='.urlencode('xxxxxx/payment.wechat/index').'&response_type=code&scope=snsapi_base&state=syno' . time() . '#wechat_redirect'; return redirect($url);}//获取openidpublic function index(){ //判断有没有code $code = $this->request->param('code'); if (isset($code) && $code !== '') { $wechatConfig = Config::get('wechat'); $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $this->appid . '&secret=' . $this->secret. '&code=' . $code . '&grant_type=authorization_code'; $res = curl($url); //正常返回 access_token、openid等参数 if (isset($res['openid'])) { return redirect('/payment/wechat/?openid=' . $res['openid'] . '&code=' . $code); } else { return redirect('/payment/wechat/'); } } else { return redirect('/payment/wechat/'); }}//构造 APIv3 客户端实例public function APIv3(){ $merchantId = $this->mchid; // 商户号 // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名 $merchantPrivateKeyFilePath = $this->keyCert; $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE); // 「商户API证书」的「证书序列号」 $merchantCertificateSerial = $this->serialNo; // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名 $platformCertificateFilePath = $this->wechatpayCert; $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC); // 从「微信支付平台证书」中获取「证书序列号」 $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath); // 构造一个 APIv3 客户端实例 $instance = Builder::factory([ 'mchid' => $merchantId, 'serial' => $merchantCertificateSerial, 'privateKey' => $merchantPrivateKeyInstance, 'certs' => [$platformCertificateSerial => $platformPublicKeyInstance], ]); return $instance;}//JSAPI下单获取prepay_idpublic function jsApiPay(){ Db::startTrans(); try { $parameter = request()->post(); //下单 $order = new Order(); $orderSn = "订单号"; $data = [ 'appid' => $this->appid, //公众号的服务号APPID 'mchid' => $this->mchid, //商户号 'description' => $parameter['product_name'], //商品描述 'out_trade_no' => $orderSn, //商户订单号 'attach' => 'ceshi_'.time(), //附加数据,在查询API和支付通知中原样返回 'notify_url' => 'xxxxx/payment.wechat/notifyUrl', //异步接收微信支付结果通知的回调地址 'amount' => ['total' => $parameter['amount'] * 100], //订单总金额,单位为分 'payer' => ['openid' => $parameter['openid']] //用户标识,用户在直连商户appid下的唯一标识 ]; $instance = $this->APIv3(); $resp = $instance->chain('v3/pay/transactions/jsapi')->post(['json' => $data]); $prepay_id = json_decode($resp->getBody(), true)['prepay_id']; if (isset($prepay_id)) { $arr = []; $arr['prepay_id'] = $prepay_id; $arr['order_sn'] = $orderSn; $arr['amount'] = $parameter['amount']; $orderInfo = $order->where('order_sn',$orderSn)->find(); $arr['create_time'] = $orderInfo['create_time']; Db::commit(); return $this->success('成功获取prepay_id', $arr); } else { throw new \Exception('获取prepay_id失败'); } } catch (\Exception $e) { Db::rollback(); // 进行错误处理 }//获取支付参数public function payConfig(){ $config = $this->sign(request()->get('prepay_id')); return json($config);}//签名public function sign($prepay_id){ $merchantPrivateKeyFilePath = $this->keyCert; $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath); $params = [ 'appId' => $this->appid, 'timeStamp' => (string)Formatter::timestamp(), 'nonceStr' => Formatter::nonce(), 'package' => 'prepay_id=' . $prepay_id, ]; $params += ['paySign' => Rsa::sign( Formatter::joinedByLineFeed(...array_values($params)), $merchantPrivateKeyInstance ), 'signType' => 'RSA']; return $params;}//支付成功回调处理public function notifyUrl(){ $inBody = file_get_contents('php://input');// 请根据实际情况获取,例如: file_get_contents('php://input'); $apiv3Key = 'xxxxxx';// 在商户平台上设置的APIv3密钥 // 转换通知的JSON文本消息为PHP Array数组 $inBodyArray = (array)json_decode($inBody, true); // 加密文本消息解密 $inBodyResource = AesGcm::decrypt($inBodyArray['resource']['ciphertext'], $apiv3Key, $inBodyArray['resource']['nonce'], $inBodyArray['resource']['associated_data']); // 把解密后的文本转换为PHP Array数组 $inBodyResourceArray = (array)json_decode($inBodyResource, true); if ($inBodyResourceArray['trade_state'] == 'SUCCESS') { Db::startTrans(); try { //操作付款状态 $order = new Order(); $order->update(['pay_status' => 1, 'pay_time' => date('Y-m-d H:i:s')], ['order_sn' => $inBodyResourceArray['out_trade_no']]); //交易明细记录 $tradeRecord = new TradeRecord(); $tradeRecord->insertGetId([ 'order_sn' => $inBodyResourceArray['out_trade_no'], 'trade_no' => $inBodyResourceArray['transaction_id'], 'total_amount' => $inBodyResourceArray['amount']['total'] / 100, 'type' => 1, //0支出 1收入 'pay_type' => 1, //0支付宝 1微信 'content' => $inBodyResource, 'trade_state' => $inBodyResourceArray['trade_state'], 'create_time' => date('Y-m-d H:i:s') ]); $wechatTrade = new WechatTrade(); $wechatTrade->insertGetId([ 'order_sn' => $inBodyResourceArray['out_trade_no'], 'transaction_id' => $inBodyResourceArray['transaction_id'], 'trade_state' => $inBodyResourceArray['trade_state'], 'openid' => $inBodyResourceArray['payer']['openid'], 'trade_type' => $inBodyResourceArray['trade_type'], 'total_amount' => $inBodyResourceArray['amount']['total'] / 100, 'create_time' => date('Y-m-d H:i:s') ]); Db::commit(); //返回成功 echo ' '; } catch (\Exception $e) { Db::rollback(); // 进行错误处理 echo $e->getMessage(), PHP_EOL; } } }