前期准备工作,包括
1、公众号绑定到同一个开放平台(非必须,unionid机制才需要)
2、登陆公众号平台,修改如下
2.1 业务域名 : aaa.net.cn
2.2 JS接口安全域名 :aaa.net.cn
2.3 网页授权域名:aaa.net.cn
2.4 ip白名单都添加有 123.56.219.177
2.5 在商户平台添加支付授权链接为:http://aaa.net.cn/order/payment/sid/
3、更改config.php中的配置代码中的‘APPID’,‘APPSECRET’,‘MCHID’,‘KEY’(注意其中APPID和APPSECRET会影响到授权登录;APPID、MCHID和KEY会影响微信支付,即APPSECRET的值不会影响微信支付:前提是微信授权登录时openid获取的是正确的),至此前期准备工作完成
调用方法一:价格变量等都为后台php直接分配过去前台的
在config配置项配置好如下参数
php 'APPID' => 'xxxxxx', //公众平台可以查看 'APPSECRET' => 'xxxxxx', //公众平台可以查看 'MCHID' => 'xxxxx', //微信支付商户号,商户平台查看 'KEY' => 'xxxxx', //API秘钥,商户平台查看
在需要微信支付的地方引入微信支付类:
Vendor('Pay.WxPayData')
后台生成js参数分配到前台,在支付方法中加入,其中:
body为标题
attach为用户自定义数据
total_fee为总价钱
notify_url为通知函数(必须是完整地址,即要使用C('WEBSITE'))
trade_type包括'JSAPI'和'NATIVE'两种,其中'JSAPI'为公众号支付,'NATIVE'扫码支付
php $pay = new \WxPay($openid, $body, $attach, $total_fee, $notify_url, $trade_type = 'JSAPI', $goods_tag = ''); $this->jsApiParameters = $pay->getJsParameters();
前台js调用如下,其中支付按钮就是onclick="callpay()"属性触发支付行为
javascript//调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', <?php echo $jsApiParameters; ?>, function(res){ // WeixinJSBridge.log(res.err_msg); alert('err_code:' + res.err_code + ', err_desc:' +res.err_desc + ', err_msg:' + res.err_msg); } ); } function callpay() { if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } }
调用方法二:价格变量等都为前端ajax到后台获取的
在config配置项配置好如下参数
php 'APPID' => 'xxxxxx', //公众平台可以查看 'APPSECRET' => 'xxxxxx', //公众平台可以查看 'MCHID' => 'xxxxx', //微信支付商户号,商户平台查看 'KEY' => 'xxxxx', //API秘钥,商户平台查看
前端通过js去后端获取数据,其中支付按钮就是onclick="callpay()"属性触发支付行为,money为传入的参数
//调用微信JS api 支付 function jsApiCall(money) { var values = { money : money, shop_id : shop_id }; $.ajax({ type : 'post', url : '/home/order/get_wechat_payment', data: values, success : function (ret) { if(ret.status == 200){ var order_id = ret.order_id; var jsApiParameters = JSON.parse(ret.jsApiParameters); WeixinJSBridge.invoke( 'getBrandWCPayRequest', jsApiParameters, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ){ location.href = '/home/order/payment_result/order_id/'+order_id; } else if(res.err_msg == "get_brand_wcpay_request:cancel" ){ toast('支付取消'); closeLoading(); } else{ toast('支付失败'); closeLoading(); } } ); } } }); } function callpay(money) { if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(money); } }
后端在需要微信支付的地方引入微信支付类(此处为get_wechat_payment控制器内):
Vendor('Pay.WxPayData')
在get_wechat_payment方法中创建一个新订单,状态为未支付且写入数据库;生成统一下单数据,并返回给前台
public function get_wechat_payment () { $user = $_SESSION['user']; $openid = $user['openid']; $money = I("money"); $shop_id = I("shop_id"); $save_data['uid'] = $user['id']; $save_data['shop_id'] = $shop_id; $attach = $save_data['out_trade_no'] = $save_data['order_number'] = create_order_number($user['id']); $save_data['must_pay'] = $money; $save_data['create_time'] = date('Y-m-d H:i:s'); $save_data['order_type'] = 2; // 线下买单 $save_data['pay_type'] = 1; // 微信支付 $save_data['status'] = 0; // 待支付 $res = M('GoodsOrder')->add($save_data); $body = '线下买单订单'; $body = '线下买单'; $total_fee = $money*100; $notify_url = C('WEBSITE').'/home/index/test_notify_url'; $pay = new \WxPay($openid, $body, $attach, $total_fee, $notify_url, $trade_type = 'JSAPI', $goods_tag = ''); $jsApiParameters = $pay->getJsParameters(); $data['status'] = 200; $data['jsApiParameters'] = $jsApiParameters; $data['order_id'] = $res; $this->ajaxReturn($data);die; }
前台接收后台返回的参数并处理,具体见上述jsApiCall方法。
支付结果异步通知处理
public function test_notify_url () { $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; $post = json_decode(json_encode(simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA)), true); // 方法一 $post = (array)simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); // 方法二 // 首先验证签名 $bool = $this->checkSign($post); if($bool){ $attach = $post['xml']['attach']['@cdata']; $attach_data = explode('|', $attach); $out_trade_no = $attach_data[0]; $re = M("GoodsOrder")->where(array('out_trade_no'=>$out_trade_no))->find(); if($re['status'] == 0){ M("GoodsOrder")->where(array('id'=>$re['id']))->setField('status',1); D("Api/GoodsOrder")->paySuccess($re['id'],1,2); } echo '<xml><return_code><![CDATA[SUCCESS]]></return_code> <return_msg><![CDATA[OK]]></return_msg></xml>'; } } public function checkSign ($post) { if($post['xml']){ $sign1 = $post['xml']['sign']['@cdata']; unset($post['xml']['sign']); $str1 = ''; foreach ($post['xml'] as $k => $v) { if(is_array($v)){ $str1 .= $k . '=' . $v['@cdata'] . '&'; } else{ $str1 .= $k . '=' . $v . '&'; } } // 拼接key $str2 = $str1 . 'key=' . C('KEY'); // md5编码并转成大写 $sign2 = strtoupper(md5($str2)); if($sign1 == $sign2){ return true; } return false; } }
支付完成!