微信小程式-微信支付詳細介紹(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);
}