微信公众号发红包功能中按照官方文档开发,其中我碰见的问题:
1 证书路径问题 : 绝对路径不是网站路径,而是服务器路径。
2 opendid 微信公众号openid不是普通的微信openid
3 发钱金额单位是分 需要乘以100
4 签名数据按照顺序排序。
下面是代码:
/**
* [redenvelopehandle 发红包处理]
* @Author liuxuyang163@163.com
* @DateTime 2019-04-17T11:03:27+0800
* @return [type] [description]
*/
public function redenvelopehandle()
{
$openid = request()->param('openid');//公众号openid
$amount = request()->param('amount');//金额
$wechat_name = request()->param('wechat_name');//金额
//每个公众号Opendid在每天最多发3次红包
//php获取今日0时0分0秒时间戳
$today = strtotime(date("Y-m-d"),time());
$res_check_award = Db::name('redenvelope_cash')->where('openid',$openid)->whereTime('cash_time','>=',date("Y-m-d"))->count();
if($res_check_award>3){
return json(array('code'=>1,'msg'=>'每个公众号每天最多发3次红包'));
}
$arr_denvelope = array();
$arr_denvelope['act_name'] = $wechat_name.;
$arr_denvelope['client_ip'] = Config::get('app.common.service_ip');
$arr_denvelope['mch_billno'] = Config::get('app.wx.wechat_business_number').date('YmdHis').rand(1000,9999);
$arr_denvelope['mch_id'] = Config::get('app.wx.wechat_business_number');
$arr_denvelope['nonce_str'] = $this->create_noncestr();
$arr_denvelope['re_openid'] = $openid;//"oYzL857oj8E8r7XuaaGt-TvWvQ6M";
$arr_denvelope['remark'] = "*********";//随便说点啥又不显示
$arr_denvelope['scene_id'] = "PRODUCT_1";
$arr_denvelope['send_name'] = $wechat_name;
$arr_denvelope['total_amount'] = $amount * 100;//金额单位为分所以 *100
$arr_denvelope['total_num'] = 1;
$arr_denvelope['wishing'] = "恭喜小主喜提红包";
$arr_denvelope['wxappid'] = Config::get('app.wx.wechat_public_number_appid');
$wx_url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
$res = $this->pay($wx_url,$arr_denvelope);
libxml_disable_entity_loader(true);
$postObj = simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($postObj),true);
if($val['result_code'] == 'SUCCESS'){
//如果红包发放成功了 向数据库redenvelope_cash 插入一条发放记录
$arr_redenvelope_cash = [
'openid' => $openid,
'amount' => $amount,
'cash_time' => time(),
'cash_type' => '手动发放',
'wechat_name' => $wechat_name,
'status' => 1,
'mch_billno'=>$val['mch_billno']
];
$res_envelope_add = Db::name('redenvelope_cash')->insert($arr_redenvelope_cash);
if($res_envelope_add ==1){
return json(array('code'=>0,'msg'=>'红包发放成功','url'=>'/admin/User/redenvelope'));
}else{
return json(array('code'=>1,'msg'=>'红包发放失败'));
}
}else{
//file_put_contents(CACHE_PATH.'sendPacketErr.txt',var_export($val,true),FILE_APPEND);
return json(array('code'=>1,'msg'=>$val['err_code_des']));
}
}
private function pay($url,$obj)
{
$stringA = $this->create_qianming($obj,false);
$stringSignTemp = $stringA."&key=".Config::get('app.wx.wechat_business_ipv3_pwd');;
$sign = strtoupper(md5($stringSignTemp));
$obj['sign'] = $sign;
$postXml = $this->arrayToXml($obj);
$responseXml = $this->curl_post_ssl($url,$postXml);
return $responseXml;
}
//生成签名,参数:生成签名的参数和是否编码
private function create_qianming($arr,$urlencode)
{
$buff = "";
ksort($arr); //对传进来的数组参数里面的内容按照字母顺序排序,a在前面,z在最后(字典序)
foreach ($arr as $k=>$v) {
if(null!=$v && "null" != $v && "sign" != $k){
//签名不要转码
if ($urlencode){
$v = urlencode($v);
}
$buff.=$k."=".$v."&";
}
}
if (strlen($buff)>0) {
$reqPar = substr($buff,0,strlen($buff)-1); //去掉末尾符号“&”
}
return $reqPar;
}
//生成随机字符串,默认32位
private function create_noncestr($length=32)
{
//创建随机字符
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
$str = "";
for($i=0;$i<$length;$i++){
$str.=substr($chars, mt_rand(0,strlen($chars)-1),1);
}
return $str;
}
//数组转xml
public function arrayToXml( $params )
{
if(!is_array($params)|| count($params) <= 0)
{
return false;
}
$xml = "<xml>";
foreach ($params as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
//post请求网站,需要证书
private function curl_post_ssl($url, $vars, $second=30,$aHeader=array())
{
$ch = curl_init();
//超时时间
curl_setopt($ch,CURLOPT_TIMEOUT,$second);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
//这里设置代理,如果有的话
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
//cert 与 key 分别属于两个.pem文件
//请确保您的libcurl版本是否支持双向认证,版本高于7.20.1
curl_setopt($ch, CURLOPT_SSLCERT, '/www/wwwroot/www.*******.com/public/cert/apiclient_cert.pem');
curl_setopt($ch, CURLOPT_SSLKEY, '/www/wwwroot/www.*******.com/public/cert/apiclient_key.pem');
curl_setopt($ch, CURLOPT_CAINFO, '/www/wwwroot/www.*******.com/public/cert/rootca.pem');
if( count($aHeader) >= 1 ){
curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
}
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$vars);
$data = curl_exec($ch);
if($data){
curl_close($ch);
return $data;
}else{
$error = curl_errno($ch);
echo "call faild, errorCode:$error\n";
curl_close($ch);
return false;
}
}