1. 程式人生 > >微信小程式-微信支付詳細介紹(Thinkphp後端程式碼)

微信小程式-微信支付詳細介紹(Thinkphp後端程式碼)

流程

如微信支付的文件,不再多說

https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_4&index=3

一一分析一下每一步我們具體要做什麼:

1、小程式內呼叫登入介面,獲取到使用者的openid,api參見公共api【小程式登入API

一般我們在資料庫儲存了使用者openid,所以我們是去資料庫取。

2、商戶server呼叫支付統一下單,api參見公共api【統一下單API

 這一步是拿到使用者openid、訂單詳情等文件中要求的資訊後,轉換成xml格式(轉換格式是有微信介面的),呼叫微信封裝好的統一下單介面,便會返回包含prepay_id的一些引數。

3、商戶server呼叫再次簽名,api參見公共api【再次簽名

 我認為這個步驟名稱寫的不好,“再次簽名”的連結開啟,標題寫的卻是調起支付API。實際上分兩步:再次簽名、調起支付API。就是說,獲取到上一步的一些引數後,按照簽名演算法處理資料,然後呼叫微信API再次簽名,這樣就有了簽名引數。最後將被要求的引數填入調起支付API就可以了。

4、商戶server接收支付通知,api參見公共api【支付結果通知API

在第二步的xml中要求填入我們伺服器上的通知地址,這樣第三步的微信支付結果就會發送到這個地址。 在這個方法裡面,我們要校對微信發來的支付結果是哪個訂單的,然後可以修改訂單的支付狀態,還要返回給微信接受成功的xml資訊,不然微信會一直髮通知過來。

5、商戶server查詢支付結果,api參見公共api【查詢訂單API

查詢支付訂單詳情見文章最後一塊程式碼。

準備工作

首先小程式要繫結商戶,不然沒法做也沒法測試。

開通微信支付後,下載微信支付API的包(我用的是PHP)

https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

前端

使用者已下單(還未付款),當用戶點選付款時,執行PayOrder函式。

函式主要有三個請求介面:Order/get獲取訂單詳情(省略)、Order/getPrepay(統一下單/再次簽名/支付通知)、wx.requestPayment(發起微信支付)。

PayOrder: function(t) {
        var that = this;
        var order_id = t.currentTarget.dataset.id;//訂單id
        wx.request({
          url: 'https://XX.com/Order/get',//這是獲取訂單詳情的請求
          data:{
            id:order_id 
          },
          success:function(a){
            //統一下單並再次簽名
            wx.request({
              url: 'https://wechat.cdd.jianfengweb.com/Order/getPrepay',
              data: {
                total_fee: a.data.data.total_price*100,
                order_number: a.data.data.order_number,
              },
              success: function (res) {
                // 返回引數和sign後調起微信支付
                wx.requestPayment(
                  {
                    'timeStamp': new Date().getTime().toString(),
                    'nonceStr': res.data.data['nonce_str'],
                    'package': "prepay_id=" + res.data.data['prepay_id'],
                    'signType': 'MD5',
                    'paySign': res.data.data['sign'],
                    'success': function (e) {
                      console.log('success')
                    },
                    'fail': function (e) {
                      console.log(e)
                    },
                    'complete': function (e) { }
                  })
              }
            })
          }
        })
    }

後端

Order/getPrepay方法(統一下單、再次簽名)

public function getPrepay()
    {
        extract(generateRequestParamVars());
        //獲取openid
        $user = D(self::$WECHAT_USER_MODEL)->find($user_id);
        $openid = $user['openid'];

        //引用微信支付API
        require_once C('APPLICATION_DIR') . '/Home/Libs/WechatPay/lib/WxPay.Api.php';
        require_once C('APPLICATION_DIR') . '/Home/Libs/WechatPay/lib/WxPay.Notify.php';
        require_once C('APPLICATION_DIR') . '/Home/Libs/WechatPay/lib/WxPay.Data.php';
        require_once C('APPLICATION_DIR') . '/Home/Libs/WechatPay/example/log.php';
        require_once C('APPLICATION_DIR') . '/Home/Libs/WechatPay/example/WxPay.NativePay.php';
        require_once C('APPLICATION_DIR') . '/Home/Libs/WechatPay/example/WxPay.JsApiPay.php';

        // WxPayUnifiedOrder類會直接設定xml
        $xml = new \WxPayUnifiedOrder();
        $xml->SetBody("購買商品");
        $xml->SetAttach("attach");
        $xml->SetOpenid($openid);
        $xml->SetOut_trade_no($product_id);
        $xml->SetTotal_fee($total_fee * 100);
        $xml->SetTime_start(date("YmdHis", time()));
        $xml->SetTime_expire(date("YmdHis", time() + 600));
        $xml->SetNotify_url("https://XX.com/Order/getNotify");
        $xml->SetGoods_tag("goods_tag");
        $xml->SetTrade_type("JSAPI");

        //統一下單(獲取prepay_id)
        $nativepay = new \NativePay();
        $result = $nativepay->GetPayUrl($xml);

        //再次簽名
        $sign_array = array();
        $sign_array['appId'] = $result['appid'];
        $sign_array['nonceStr'] = $result['nonce_str'];
        $sign_array['package'] = 'prepay_id=' . $result['prepay_id'];
        $sign_array['signType'] = 'MD5';
        $sign_array['timeStamp'] = floor($result['startTimeStamp'] / 1000);

        $sign = new \WxPayDataBase();
        $sign_two = $sign->MakeSigns($sign_array);
        $result['paySign'] = $sign_two;

        $ajaxReturnData['data'] = $result;
        $this->ajaxReturn($ajaxReturnData);
    }

Order/getNotify方法(接收微信通知)

public function getNotify()
    {
        $xmlData = file_get_contents('php://input');
        libxml_disable_entity_loader(true);
        $data = json_decode(json_encode(simplexml_load_string($xmlData, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        ksort($data);
        $buff = '';
        foreach ($data as $k => $v) {
            if ($k != 'sign') {
                $buff .= $k . '=' . $v . '&';
            }
        }

        $save = [];
        foreach ($data as $k => $v) {
            $save['key'] = $k . '';
            $save['value'] = $v . '';
            D(self::$NOTIFY_TEST)->add($save);
        }

        $stringSignTemp = $buff . 'key=1d8r14jiu58fs12qsd824j1o52d8r14c';//key為證書金鑰
        $sign = strtoupper(md5($stringSignTemp));

        $conditions = [];
        $conditions['order_number'] = $data['out_trade_no'];
        $order = D(self::$ORDER_MODEL)->where($conditions)->find();

        //判斷算出的簽名和通知資訊的簽名是否一致
        if ($order && $sign == $data['sign'] && $order['total_price']*100 == $data['total_fee']) {
            $test = [];
            $test['key'] = '校驗是否成功';
            $test['value'] = 'yes';
            D(self::$NOTIFY_TEST)->add($test);

            $order_data = [];
            $order_data['shop_status'] = 1;
            D(self::$ORDER_MODEL)->where($conditions)->save($order_data);

            //處理完成之後,告訴微信成功結果
            echo '<xml>
                    <return_code><![CDATA[SUCCESS]]></return_code>
                    <return_msg><![CDATA[OK]]></return_msg>
                  </xml>';
            exit();
        }else{
            echo '<xml>
                    <return_code><![CDATA[FAIL]]></return_code>
                    <return_msg><![CDATA[FAIL]]></return_msg>
                  </xml>';
            exit();
        }
    }

 Order/findOrder方法(查詢支付訂單)

public function findOrder()
    {
        try{
            extract(generateRequestParamVars());
            require_once C('APPLICATION_DIR') . '/Home/Libs/WechatPay/lib/WxPay.Api.php';
            $input = new \WxPayOrderQuery();
            $input->SetOut_trade_no($order_number); // 設定好要查詢的訂單
            $order = \WxPayApi::orderQuery($input); // 進行查詢

            $ajaxReturnData['status'] = 1;
            $ajaxReturnData['message'] = '操作成功';
            $ajaxReturnData['data'] = $order;
        }catch (\Exception $e){
            $ajaxReturnData['status'] = 0;
            $ajaxReturnData['message'] = '操作失敗' . $e->getMessage();
        }
        $this->ajaxReturn($ajaxReturnData);
    }