前期准备工作,包括
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;
}
}支付完成!