微信支付对接

最近有一个项目,有需要对接微信支付,资质已经都申请好了,原来一直想试一试对接微信支付这些的,但是门槛太高,就没有研究这些支付的接口了,今天有机会,顺便记录下来

配置

根据官方的文档 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3 配置好url,就不多说了
我的使用场景是微信公众号,所以需要一个h5页面,调起微信支付

公众号支付(JSAPI支付)是指用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块来完成支付。

下单

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

在我们调起支付之前,需要调用这个统一下单的接口,获取我们支付的一些参数

获取openid

在h5中,我们需要获取到用户的openid,才能进行下单操作,一个简单的方法是,在公众号生成链接的时候,给链接带上一些参数,指向用户。这里我们用微信给我们提供的接口来获取openid https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842

我们只需要openid,我们使用snsapi_base就好了,关于其他的信息可以通过openid从数据库中读取

直接将此链接发送给用户
https://open.weixin.qq.com/connect/oauth2/authorize?appid=[appid]&redirect_uri=[url]&response_type=code&scope=snsapi_base#wechat_redirect

然后会调用我们的链接,后面带了code参数,到这里就要获取openid了

$http = new \lib\http(
    "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appid&secret=$secret&code={$_GET['code']}&grant_type=authorization_code"
);
$data = $http->get();
$json = json_decode($data, true);
$openid = $json['openid'];

获取支付参数

在使用前端调起的时候,需要一个参数才能成功

$http = new \lib\http('https://api.mch.weixin.qq.com/pay/unifiedorder');
$data = [
    'appid' => $appid,//公众号id
    'mch_id' => $mch_id,//商户id
    'nonce_str' => $rand,//随机字符串
    'body' => 'test order',//商品描述
    'out_trade_no' => $trade_no,//商户自己的订单id,可以用来判断订单情况
    'total_fee' => '1',//金额,单位为分 我这样就是0.01元
    'spbill_create_ip' => getip(),//获取客户的ip
    'notify_url' => '',//异步回调链接
    'openid' => '',//必须要有openid
    'trade_type' => 'JSAPI'//JSAPI类型
];
ksort($data);
$sign = '';
foreach ($data as $k => $value) {
    $sign .= "$k=$value&";
}
$sign .= "key=$key";
$data['sign'] = strtoupper(md5($sign));//转换为大写
$xmlData = \controller\baseMsgController::arr2xml($data);//数组转换成xml
$xmlData = $http->post($xmlData);
//转换xml
$xml = simplexml_load_string($xmlData);
$prepay_id = $xml->prepay_id->__toString();//这个值是下面调起支付需要的,其他的到是无所谓

调起支付

直接复制官网的过来https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6

那几个监听什么的,主要是监听网页的WeixinJSBridge加载完成事件,不然一开始就调起支付,可能没加载出来,导致失败

function onBridgeReady(){
   WeixinJSBridge.invoke(
      'getBrandWCPayRequest', {
         "appId":"wx2421b1c4370ec43b",     //公众号名称,由商户传入     
         "timeStamp":"1395712654",         //时间戳,自1970年以来的秒数     
         "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串     
         "package":"prepay_id=u802345jgfjsdfgsdg888",     //**主要就是这里了**
         "signType":"MD5",         //微信签名方式:     
         "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 
      },
      function(res){
      if(res.err_msg == "get_brand_wcpay_request:ok" ){
      // 使用以上方式判断前端返回,微信团队郑重提示:
            //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
      } 
   }); 
}
if (typeof WeixinJSBridge == "undefined"){
   if( document.addEventListener ){
       document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
   }else if (document.attachEvent){
       document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
       document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
   }
}else{
   onBridgeReady();
}

异步回调

异步回调算是最重要的一步了,有了它才能让我们知道用户支付完成了,并且给用户增加积分等等

这是我一次成功支付回调的xml

<xml><appid><![CDATA[******]]></appid>
<bank_type><![CDATA[CFT]]></bank_type>
<cash_fee><![CDATA[1]]></cash_fee>
<fee_type><![CDATA[CNY]]></fee_type>
<is_subscribe><![CDATA[Y]]></is_subscribe>
<mch_id><![CDATA[1514896031]]></mch_id>
<nonce_str><![CDATA[****]]></nonce_str>
<openid><![CDATA[****-YRcXk]]></openid>
<out_trade_no><![CDATA[1537084330722301]]></out_trade_no>
<result_code><![CDATA[SUCCESS]]></result_code>
<return_code><![CDATA[SUCCESS]]></return_code>
<sign><![CDATA[****]]></sign>
<time_end><![CDATA[20180916155215]]></time_end>
<total_fee>1</total_fee>
<trade_type><![CDATA[JSAPI]]></trade_type>
<transaction_id><![CDATA[*****]]></transaction_id>
</xml>

对于异步回调我们需要校验sign

<?php
$xmlData = file_get_contents('php://input');

$xml = simplexml_load_string($xmlData);
$xmlArray = xml2arr($xml);
$sign = $xmlArray['sign'];
unset($xmlArray['sign']);
ksort($xmlArray);
//校验sign,appid等
if ($sign == pay_sign($xmlArray, $key) && $xmlArray['appid'] == $appid
    && $xmlArray['mch_id'] == $mch_id) {
//校验成功,查询订单等等,这里主要用 out_trade_no 来判断我们的商品信息等等
}else{
    //失败处理
}

function xml2arr($xml) {
    $ret_array = [];
    foreach ($xml as $key => $value) {
        $ret_array[$key] = $value->__toString();
    }
    return $ret_array;
}


function pay_sign($data, $key) {
    ksort($data);
    $sign = '';
    foreach ($data as $k => $value) {
        $sign .= "$k=$value&";
    }
    $sign .= "key=$key";
    $sign = strtoupper(md5($sign));
    return $sign;
}

点赞
  1. 新的一天说道:

    :cry: 为什么我一直学不会支付接口!!!

    1. Farmer Farmer说道:

      ?就异步和加密那里有一点难度

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.