紅包功能實現 附原始碼( 簽名錯誤、CA證書錯誤等解決辦法)
阿新 • • 發佈:2019-01-05
場景:小程式開發一個拆紅包的功能,後臺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
另外:如果你用微信線上簽名生成的簽名跟你自己生成的簽名是一樣的,但是返回還是報簽名錯誤,很有可能是以上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;
}