1. 程式人生 > >微信小程序 支付功能 服務器端(TP5.1)實現

微信小程序 支付功能 服務器端(TP5.1)實現

ces 形式 當前 單位 class private cda 庫存 vat

首先下載微信支付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();
    }

微信小程序 支付功能 服務器端(TP5.1)實現