微信小程序 支付 - 红包功能实现 附源码( 签名错误、CA证书错误等解决办法)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/abs1004/article/details/80006931

场景:小程序开发一个拆红包的功能,后台thinkphp3.2,小程序和微信商户平台不是同一个账号,但是已经关联
官方接口文档:微信支付-企业付款到零钱
使用条件
1、商户号(或同主体其他商户号)已入驻90日
2、商户号(或同主体其他商户号)有30天连续正常交易
3、登录微信支付商户平台-产品中心,开通企业付款。
4、红包金额目前最新规定为 0.30元 到 200元(传参的时候微信以分为单位,所以amount最小值30,最大值20000
企业付款到零钱 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
目前项目的小程序
各种坑不一一列举,只写注意事项及容易出错的地方:
注意事项:
1. 参数名严格按照官方文档输入(文后有代码范例作为参考)
2. 小程序登录网址 https://mp.weixin.qq.com
3. CA证书要用商户号里下载的证书。商户号登录网址:https://pay.weixin.qq.com(商户登录账号类似:1492678888@1492678888,密码在腾讯发的邮件里有六位数字的)
4. mchid:商户平台下的mchid
5. mch_appid: 小程序的appid
6. openid: 小程序的用户openid
7. key: 微信商户平台的密钥key(sign签名使用的密钥)

另外:如果你用微信在线签名生成的签名跟你自己生成的签名是一样的,但是返回还是报签名错误,很有可能是以上4-7的参数用错了,仔细检查吧(小程序支付也一样
小程序拆红包代码:

//红包js代码
   onHongbao: function () {
      var that = this;
      if (that.hongbaoOpened){
         wx.showModal({
            title: '红包已拆过',
            content: '红包已拆过',
            showCancel: false,
         })
      }else{
         //拆红包按钮显示控制
         that.setData({
            hongbaoOpened: true
         })
         //openid传给后台,获取红包
         app.post('https://zhipur.com/api/pay/wxpay_hongbao',{
            openid: openid,
         }).then( (res)=>{
            console.log(res);//微信接口返回信息
            if(res.wxmsg.return_code=="SUCCESS"&&res.wxmsg.result_code=="SUCCESS"){
                //用户界面显示红包信息
                wx.showModal({
                    title: res.from + '发放的红包',
                    content: res.amount + '元已转入微信钱包',
                    showCancel: false,
                 })
            }else{
                //用户界面显示红包信息
                wx.showModal({
                    title: '红包出错了',
                    content: '红包出错了',
                    showCancel: false,
                 })
            } 
         }).catch( (err)=>{
            console.log(err);//微信接口返回信息 
         });  
      } 
   },

后台PHP代码:

/**
     * 微信小程序红包 企业付款
     * @param {String} $cid 订单编号
     * @param {String} $name 订单名
     * @param {Datetime} $subdate 提交日期
     */
    public function wxpay_hongbao(){

        $post = I('post.');

        // 是否已开启过红包
        // $this->hongbaoOpened($post['openid'], $post['itemId']);

        //读取配置
        $cfg = C('WXPAY_CONFIG');

        $nonce_str = abs_rand(16);//生成16位随机字符串

        $api = $cfg['hongbao_api'];//微信企业付款到零钱接口

        //获取IP 或者直接获取$_SERVER['REMOTE_ADDR']
        $spbill_create_ip = $_SERVER['REMOTE_ADDR'] == '::1' ? '192.127.1.1' : $_SERVER['REMOTE_ADDR'];
        //微信随机金额红包 范围:30 - 2000分,默认:30 - 50分
        $min=30;
        $max=50;
        $amount = $this->make_wxhb_rand_money($min,$max);
        /** 微信接口 */
        $mchid = $cfg['mch_id'];//微信商户平台 商户号
        $appid = $cfg['mini_appid'];//小程序 appid
        $trade_key = $cfg['trade_key'];//微信商户平台 密钥
        $openid = $post['openid'] ? $post['openid'] : 'oVyb00JwH1J8tKdlUuZ4FZOsteVw';//默认openid回收错误openid的红包资金
        $desc = '红包';
        $partner_trade_no = date('Ymd').mt_rand(10000,99999) ;//生成订单号 比如'2018032812345'
        $signArr = array(
                        'amount'=>$amount,
                        'check_name'=>'NO_CHECK',
                        'desc'=>$desc,
                        'mch_appid'=>$appid,
                        'mchid'=>$mchid,
                        'nonce_str'=>$nonce_str,
                        'openid'=>$openid,
                        'partner_trade_no'=>$partner_trade_no,
                        'spbill_create_ip'=>$spbill_create_ip,

            );

        //企业付款到零钱 签名
        $sign = $this->make_wxhb_sign($signArr,$trade_key);

        $postXml = $this->array2xml($signArr, $sign);
        //curl 微信支付接口获取 prepay_id
        $xmlRes = curl_post_xml_with_wxCA($api, $postXml);//微信返回数据

        $postObj = xml2obj($xmlRes);//转对象

        //如果成功,写入数据库hongbao表
        if($postObj->result_code=='SUCCESS'&&$postObj->return_code=='SUCCESS'){
            $this->doHongbao($amount, $openid, $post['cityName']);
            $this->ajaxReturn( array('wxmsg'=>$postObj, 'amount'=>($amount/100), 'from'=>'货验金睛') );
        }else{
            $this->ajaxReturn( array('wxmsg'=>$postObj) );
        }
    }

    /**
     * 红包成功后的业务逻辑
     * @param  {Array}    $arr   源数组
     * @param  {String}   $sign  签名字符串
     * @return  {String}  $xml   xml字符串
     */
    protected function doHongbao($amount, $openid, $city='北京市朝阳区', $time){
        //未完成
    }

    /**
     * 改红包是否已经被拆过
     * @param  {String}   $openid  小程序对应openid
     * @param  {String}   $itemid  物品id/红包id
     * @return  {String}  $xml   xml字符串
     */
    protected function hongbaoOpened($openid, $itemid){
        //未完成
    }

    /**
     * 数组生成微信api适配的xml字符串
     * @param  {Array}    $arr   源数组
     * @param  {String}   $sign  签名字符串
     * @return  {String}  $xml   xml字符串
     */
    protected function array2xml($arr,$sign){

        if(! is_array($arr) ) return false;
        $xml = '<xml>';
        foreach ($arr as $k => $v) {
            $xml .= '<'.$k.'>'.$v.'</'.$k.'>';
        }
        $xml .= '<sign>'.$sign.'</sign></xml>';
        return $xml;
    }
    /**
     * 生成随机红包金额 - 小程序企业付款到零钱
     * @param  {Float}  $min   下限
     * @param  {Float}  $max   上限
     * @param  {Float}  $rnd   随机金额
     */
    protected function make_wxhb_rand_money($min=30,$max=50){

        return mt_rand($min,$max);
    }
    /**
     * 生成签名 - 小程序企业付款到零钱
     * @param  {Array}   $arr   要传递的参数数组
     * @param  {Boolean} $is_call_back 是否二次签名
     * @return {String}  $sign  签名字符串
     */
    protected function make_wxhb_sign($arr,$trade_key,$is_call_back=false) {

        ksort($arr);        //将参数数组按照参数名ASCII码从小到大排序
        reset($arr);

        foreach ($arr as $key => $value) {
            if($key!='sign' && $key!='sign_type'){
                $newArr[] = $key.'='.$value;     // 整合新的参数数组
            }

        }
        $stringA = implode("&", $newArr);         //使用 & 符号连接参数
        $stringSignTemp = $stringA."&key=".$trade_key;        //拼接key

        $sign = strtoupper( MD5($stringSignTemp) );//将字符串进行MD5加密 并转换为大写

        return $sign;
    }
展开阅读全文

没有更多推荐了,返回首页