最近有一个项目,有需要对接微信支付,资质已经都申请好了,原来一直想试一试对接微信支付这些的,但是门槛太高,就没有研究这些支付的接口了,今天有机会,顺便记录下来
配置
根据官方的文档 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;
}
文章评论
@新的一天 就异步和加密那里有一点难度