1. 程式人生 > >紅包功能實現 附原始碼( 簽名錯誤、CA證書錯誤等解決辦法)

紅包功能實現 附原始碼( 簽名錯誤、CA證書錯誤等解決辦法)

場景:小程式開發一個拆紅包的功能,後臺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(商戶登入賬號類似:[email protected],密碼在騰訊發的郵件裡有六位數字的)
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;
    }