当时接到这个需求,瞬间就想到了微信的小程序红包,后来大体翻了一下文档,觉得就是给这个需求量身定做的.在第一个30天流水失败后,找了个微信商户的合作公司,坐快车,2天开通了微信小程序红包,微信企业付款到零钱功能.
接下来就是开发了,主要是3个接口,发放红包,领取红包,和验证红包状态,4个步骤,发放红包,验证红包状态,领取红包,验证红包状态.这里是官方链接: https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=18_4&index=1
1. 发放红包,参数很多,我就不一一细说,可以看看官方的说明,我直接上代码
<?php
namespace app\api\controller;
/*
* 微信支付:小程序红包接口
*/
use think\Controller;
class Red extends Controller
{
private $sendurl = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendminiprogramhb';//发放红包接口
private $searchurl = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo';//红包查询接口
private $mch_id = '你的商户号';//商户号
private $wxappid = '你的公众账号appid';//公众账号appid
private $send_name = '随便写';//商户名称
private $total_num = 1;//红包发放总人数,默认都是1个
private $notify_way = 'MINI_PROGRAM_JSAPI';//通知用户形式,这里不用改
private $scene_id = '';//发放红包使用场景,红包金额大于200时必传
private $key='你的秘钥';//商户号支付钥匙
/**
* 发放红包
* @param $mch_billno
* @param $re_openid
* @param $total_amount
* @param $wishing
* @param $act_name
* @param $remark
* @return mixed
* @throws \Exception
*/
public function sendhb($mch_billno,$re_openid,$total_amount,$wishing,$act_name,$remark)
{
//随机字符串
$nonce_str = $this->createNoncestr();
$parameters = array(
'nonce_str' => $nonce_str,
'mch_billno' => $mch_billno,
'mch_id' => $this->mch_id,
'wxappid' => $this->wxappid,
'send_name' => $this->send_name,
're_openid' => $re_openid,
'total_amount' => $total_amount,
'total_num' => $this->total_num,
'wishing' => $wishing,
'act_name' => $act_name,
'remark' => $remark,
'notify_way' => $this->notify_way,
'scene_id' => $this->scene_id
);
//生成签名,所有参数+key然后MD5
$parameters['sign'] = $this->getSign($parameters);
$xmlData = $this->arrayToXml($parameters);
$curlres = $this->postXmlCurl($xmlData, $this->sendurl);
$res = $this->xmlToArray($curlres);
return $res;
}
/**
* 根据订单号查询红包状态
* @param $mch_billno
* @param $mch_id
* @param $appid
* @return mixed
* @throws \Exception
*/
public function searchhb($mch_billno,$mch_id,$appid)
{
//随机字符串
$nonce_str = $this->createNoncestr();
$parameters = array(
'nonce_str' => $nonce_str,
'mch_billno' => $mch_billno,
'mch_id' => $mch_id,
'appid' => $appid,
'bill_type' => 'MCHT'
);
//生成签名,所有参数+key然后MD5
$parameters['sign'] = $this->getSign($parameters);
$xmlData = $this->arrayToXml($parameters);
$curlres = $this->postXmlCurl($xmlData, $this->searchurl);
$res = $this->xmlToArray($curlres);
return $res;
}
private function postXmlCurl($xml, $url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
//证书的位置
curl_setopt($ch, CURLOPT_SSLCERT, APP_PATH . '/certRed/apiclient_cert.pem'); //你的证书所在路径
//证书key的位置
curl_setopt($ch, CURLOPT_SSLKEY, APP_PATH . '/certRed/apiclient_key.pem'); //你的证书key所在路径
//运行curl
$data = curl_exec($ch);
//返回结果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
throw new \Exception("curl出错,错误码:$error");
}
}
//数组转换成xml
private function arrayToXml($arr)
{
$xml = "<xml>";
foreach ($arr as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . $this->arrayToXml($val) . "</" . $key . ">";
} else {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
//xml转换成数组
private function xmlToArray($xml)
{
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring), true);
return $val;
}
//作用:产生随机字符串,不长于32位
public function createNoncestr($length = 32)
{
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
//作用:生成签名
public function getSign($Obj)
{
foreach ($Obj as $k => $v) {
//不为空的参数才参与签名
if (!empty($v)) {
$Parameters[$k] = $v;
}
}
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = $this->formatBizQueryParaMap($Parameters, false);
//签名步骤二:在string后加入KEY
$String = $String . "&key=" . $this->key;
//签名步骤三:MD5加密
$String = md5($String);
//签名步骤四:所有字符转为大写
$result = strtoupper($String);
return $result;
}
//作用:格式化参数,签名过程需要使用
private function formatBizQueryParaMap($paraMap, $urlencode)
{
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if ($urlencode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
$reqPar = '';
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
}
/**
* 测试红包发放/红包查询接口
* @param string $mch_billno 订单号
* @param string $mch_id 商户号
* @param string $appid appid
* @throws \Exception
*/
public function test($mch_billno='',$mch_id='',$appid='')
{
if ($mch_billno && $mch_id) { //查询红包状态
$weixinpay = new Red();
$res = $weixinpay->searchhb($mch_billno, $mch_id, $appid);
print_r($res);
} else { //发放红包
$money = mt_rand(100, 999); //红包金额,测试金额1元~9.99元
$mch_billno = date("YmdHis") . rand(100, 999);//商户订单号
$re_openid = $this->openid;//用户openid
$total_amount = $money;//付款金额,单位分
$wishing = '恭喜';//红包祝福语
$act_name = '奖励';//活动名称
$remark = '您的专属红包';//备注
$weixinpay = new Red();
$res = $weixinpay->sendhb($mch_billno, $re_openid, $total_amount, $wishing, $act_name, $remark);
print_r($res);
}
}
2. 领取红包,这个动作要在小程序中调用,还是直接上代码
1). 这里我将领取红包的参数在方法里处理好,用接口返回到小程序
$arr['appId'] = '你的appid';
$arr['timeStamp'] = '"'.time().'"'; //时间戳要转字符串格式
$arr['package'] = 'urlencode之后的package,这个参数在红包发放成功之后可获取'; //package要进行urlencode
$weixinpay = new Red();
$arr['nonceStr'] = $weixinpay->createNoncestr();
$arr['paySign'] = $weixinpay->getSign($arr);
$arr['signType'] = 'MD5'; //不参与签名加密
$this->success('发送成功',$arr);
1) 为了方便请求,封装一个红包基类Red.php
2). 在另外一个控制器,写个测试方法调用接口
3). 测试红包发放接口,尴尬,余额不足.这里提醒一下,刚开通小程序红包的朋友,一定要进行产品设置,限额限数限ip,我改一下金额再跑一下
第二次发放成功了,说明发放接口没问题
4). 测试红包验证接口,这次很顺利,请求成功,status对照文档看
2). 小程序端接口接收参数
//后端传参,前端调用sendBizRedPacket函数
httpGet("/api/web/getRed", function(res) {
if (res.code == 1) {
console.log('拆红包');
wx. sendBizRedPacket ({
timeStamp: res.data.timeStamp, // 支付签名时间戳,
nonceStr: res.data.nonceStr, // 支付签名随机串,不长于 32 位
package: res.data.package, //扩展字段,由商户传入
signType: res.data.signType, // 签名方式,
paySign: res.data.paySign, // 支付签名
success:function(res){
console.log('成功',res);
},
fail:function(res){
console.log('失败',res);
},
complete:function(res){
console.log('结束',res);
}
})
console.log('拆红包之后');
}
})
3). 查看执行结果
4). gg,彩蛋时间到了,场景值不支持.有没有想到什么,目前小程序红包仅支持用户微信扫码打开小程序,进行红包领取
我是gg了,我们的业务要求是用户发布信息成功之后,触发红包发放功能.如果你的需求是营销拉新,扫码触发.恭喜你,直接复制粘贴吧,记得改参数