首先下载微信支付SDK ,将整个目录的文件放在 /application/extend/WxPay 目录下
在使用SDK之前我们需要对 WxPay.Config.php 进行配置
<?php namespace app\api\service; use app\api\model\Order as OrderModel; use app\lib\exception\OrderException; use app\lib\exception\TokenException; use think\Exception; use think\Loader; use think\Log; require_once ‘/extend/WxPay/WxPay.Api.php‘; class Pay { private $orderNo; private $orderID; //实例化时传入订单ID 此ID由第三方服务器自己定义 function __construct($orderID) { if (!$orderID) { throw new Exception(‘订单号不允许为NULL‘); } $this->orderID = $orderID; } public function pay() { // 根据订单ID 查到订单下对应商品 // 对商品库存检测等操作 // Todo ... return $this->makeWxPreOrder($status[‘orderPrice‘]); } // 构建微信支付订单信息 private function makeWxPreOrder($totalPrice) { //获得当前用户 openid $openid = Token::getCurrentTokenVar(‘openid‘); if (!$openid) { throw new TokenException(); } //创建订单信息 $wxOrderData = new \WxPayUnifiedOrder(); //需要引入微信提供的SDK $wxOrderData->SetOut_trade_no($this->orderNo); //订单编号,第三方自定义 $wxOrderData->SetTrade_type(‘JSAPI‘); //交易类型,一般是JSAPI $wxOrderData->SetTotal_fee($totalPrice * 100); //设置总金额,单位为0.01元 $wxOrderData->SetBody(‘零食商贩‘); //设置展示信息 $wxOrderData->SetOpenid($openid); //openid $wxOrderData->SetNotify_url(config(‘wx.pay_back_url‘)); //回调地址 return $this->getPaySignature($wxOrderData); } /** * 向微信请求订单号并生成签名 */ private function getPaySignature($wxOrderData) { $wxOrder = \WxPayApi::unifiedOrder($wxOrderData); //返回结果中包含 prepay_id ,此ID作为用户拉起支付时凭证, //同时此ID作为将来服务器向客户端推送消息的标识,因此需要保存在数据库订单表中 // 失败时不会返回result_code if($wxOrder[‘return_code‘] != ‘SUCCESS‘ || $wxOrder[‘result_code‘] !=‘SUCCESS‘){ Log::record($wxOrder,‘error‘); Log::record(‘获取预支付订单失败‘,‘error‘); } // $this->recordPreOrder($wxOrder); $signature = $this->sign($wxOrder); return $signature; } private function recordPreOrder($wxOrder){ // 将 prepay_id 保存在数据库中 OrderModel::where(‘id‘, ‘=‘, $this->orderID) ->update([‘prepay_id‘ => $wxOrder[‘prepay_id‘]]); } /** * 签名 * @return [array] [返回数组中要包含小程序发起支付请求的所有参数 包含:小程序ID、时间戳、随机串、数据包(prepay_id)、签名方式、签名 6个参数] * */ private function sign($wxOrder) { //调用SDK 生成签名 $jsApiPayData = new \WxPayJsApiPay(); //Appid $jsApiPayData->SetAppid(config(‘wx.app_id‘)); //timeStamp $jsApiPayData->SetTimeStamp((string)time()); //nonceStr $rand = md5(time() . mt_rand(0, 1000)); $jsApiPayData->SetNonceStr($rand); //package $jsApiPayData->SetPackage(‘prepay_id=‘ . $wxOrder[‘prepay_id‘]); //signType $jsApiPayData->SetSignType(‘md5‘); //生成签名 $sign = $jsApiPayData->MakeSign(); //获取数组 $rawValues = $jsApiPayData->GetValues(); $rawValues[‘paySign‘] = $sign; return $rawValues; } }
接着在控制器中调用该类下的 pay 方法 ,并创建回调函数
当用户支付完成后,微信服务器会以POST请求到指定回调地址,改地址微信服务器会默认屏蔽掉?后面字符串部分,数据通过XML形式放在body中,格式:
<xml><appid><![CDATA[wxaaf1c852597e365b]]></appid> <bank_type><![CDATA[CFT]]></bank_type> <cash_fee><![CDATA[1]]></cash_fee> <fee_type><![CDATA[CNY]]></fee_type> <is_subscribe><![CDATA[N]]></is_subscribe> <mch_id><![CDATA[1392378802]]></mch_id> <nonce_str><![CDATA[k66j676kzd3tqq2sr3023ogeqrg4np9z]]></nonce_str> <openid><![CDATA[ojID50G-cjUsFMJ0PjgDXt9iqoOo]]></openid> <out_trade_no><![CDATA[A301089188132321]]></out_trade_no> //这个是我们服务器向微信服务器发送的订单号,该订单号由我们自己生成,根据该订单号可以做相应的业务 <result_code><![CDATA[SUCCESS]]></result_code> //支付结果 <return_code><![CDATA[SUCCESS]]></return_code> <sign><![CDATA[944E2F9AF80204201177B91CEADD5AEC]]></sign> <time_end><![CDATA[20170301030852]]></time_end> <total_fee>1</total_fee> <trade_type><![CDATA[JSAPI]]></trade_type> <transaction_id><![CDATA[4004312001201703011727741547]]></transaction_id> </xml>
- 第一种方法我们可以自己解析这个XML 然后获得需要的数据
- 第二种方法我们可以通过重写微信SDK中 WxPay.Notify.php 中 NotifyProcess 方法来处理这个数据
该方法两个参数,第一个参数就是服务器返回的XML数组化后的值()
我们可以重写该类
require_once ‘/application/extend/WxPay/WxPay.Notify.php‘; class WxNotify extends \WxPayNotify { public function NotifyProcess($data, &$msg) { if ($data[‘result_code‘] == ‘SUCCESS‘) { $orderNo = $data[‘out_trade_no‘]; //开启事务,避免因服务器阻塞,微信多个请求同时到达,出现重复执行业务代码 Db::startTrans(); try { $order = Order::where(‘order_no‘, ‘=‘, $orderNo)->lock(true)->find(); //如果订单处于未支付状态下才执行里面的业务代码 if ($order->status == 1) { //查库存 //改支付状态 //减库存 } Db::commit(); } catch (Exception $ex) { Db::rollback(); Log::error($ex); // 如果出现异常,向微信返回false,请求重新发送通知 return false; } } //如果处理成功,需要向微信服务器发送 TRUE, 告诉微信停止请求回调地址 return true; } }
在控制器的回调函数中调用该子类
注意:不能直接调用 NotifyProcess 方法,因为我们无法传递该方法的参数,该参数是由父类中方法生成,需要调用父类中 handle 方法来执行 NotifyProcess 中代码
public function receiveNotify() { $notify = new WxNotify(); $notify->handle(); }
原文地址:https://www.cnblogs.com/xiaoliwang/p/9381672.html
时间: 2024-11-05 19:00:27