php实现微信公众平台发红包功能


Posted in PHP onJune 14, 2018

本文实例为大家分享了php微信公众平台给用户发红包的具体代码,供大家参考,具体内容如下

直接上代码:

代码

<?php
/**
 * 微信红包的类 
 * @Author snmoney#gmail.com 
 * @copyright 2015 
 * @version 2.0

 * *微信红包还有部分可选的参数,如分享预设值等将在后续版本补充上相关功能。
 * 对应官方接口更新,追加了分裂红包的玩法,详情参考官方文档。
 */

CLASS WXHongBao {

  private $mch_id = "********";               //商户ID写死
  private $wxappid = "********";          //微信公众号,写死
  private $client_ip = ""; //"127.0.0.1"; //调用红包接口的主机的IP,服务端IP,写死,即脚本文件所在的IP
  private $apikey = "";    //pay的秘钥值
  private $total_num = 1;                   //发放人数。固定值1,不可修改
  private $nick_name = "微信公众号红包";           //红包商户名称
  private $send_name = "微信公众号红包";          //红包派发者名称
  private $wishing = "欢迎再次参与";      //
  private $act_name = "";     //活动名称
  private $remark = "";
  private $nonce_str = "";
  private $mch_billno = "";
  private $re_openid = "";    //接收方的openID
  private $total_amount = 1 ;   //红包金额,单位 分
  private $min_value = 1;   //最小金额
  private $max_value = 1;   //根据接口要求,上述3值必须一致
  private $sign = "";     //签名在send时生成
  private $amt_type;     //分裂红包参数,在sendgroup中进行定义,是常量 ALL_RAND

  //证书,在构造函数中定义,注意!
  private $apiclient_cert; //= getcwd()."/apiclient_cert.pem";
  private $apiclient_key;// = getcwd()."/apiclient_key.pem";
  private $apiclient_ca;// = getcwd()."/apiclient_key.pem";

  //分享参数
  private $isShare = false; //有用?似乎是无用参数,全部都不是必选和互相依赖的参数
  private $share_content = ""; 
  private $share_url ="";
  private $share_imgurl = "";

  private $wxhb_inited;

  private $api_hb_group = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack";//裂变红包
  private $api_hb_single = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";

  private $error = "ok"; //init

  /**
   * WXHongBao::__construct()
   * 步骤
   * new(openid,amount)
   * setnickname
   * setsend_name
   * setwishing
   * setact_name
   * setremark
   * send()
   * @return void
   */
  function __construct(){
    //好像没有什么需要构造函数做的 引入需要的文件
    $this->wxhb_inited = false; 
    $this->apiclient_cert = getcwd() . "/zzz1/apiclient_cert.pem";
    $this->apiclient_key = getcwd() . "/zzz1/apiclient_key.pem";
    $this->apiclient_ca = getcwd() . "/zzz1/rootca.pem";
  }

  public function err(){
    return $this->error;
  }

  public function error(){
    return $this->err();
  }
  /**
   * WXHongBao::newhb()
   * 构造新红包 
   * @param mixed $toOpenId
   * @param mixed $amount 金额分
   * @return void
   */
  public function newhb($toOpenId,$amount){

    if(!is_numeric($amount)){
      $this->error = "金额参数错误";
      return;
    }elseif($amount<100){
      $this->error = "金额太小";
      return;
    }elseif($amount>20000){
      $this->error = "金额太大";
      return;
    }

    $this->gen_nonce_str();//构造随机字串
    $this->gen_mch_billno();//构造订单号
    $this->setOpenId($toOpenId);
    $this->setAmount($amount);
    $this->wxhb_inited = true; //标记微信红包已经初始化完毕可以发送

    //每次new 都要将分享的内容给清空掉,否则会出现残余被引用
    $this->share_content= "";
    $this->share_imgurl = "";
    $this->share_url = "";
  }

  /**
   * WXHongBao::sendGroup()
   * 发送裂变红包,参数为裂变数量
   * @param integer $num 3-20
   * @return
   */
  public function sendGroup($num=3){
    $this->amt_type = "ALL_RAND";//$amt; 固定值。发送裂变红包组文档指定参数,随机
    return $this->send($this->api_hb_group,$num);
  }

  public function getApiSingle(){
    return $this->api_hb_single;
  }

  public function getApiGroup(){
    return $this->api_hb_group;
  }

  public function setNickName($nick){
    $this->nick_name = $nick;
  }

  public function setSendName($name){
    $this->send_name = $name;
  }

  public function setWishing($wishing){
    $this->wishing = $wishing;
  }

  public function setActName($act){
    $this->act_name = $act;
  }

  public function setRemark($remark){
    $this->remark = $remark;
  }

  public function setOpenId($openid){
    $this->re_openid = $openid;
  }

  /**
   * WXHongBao::setAmount()
   * 设置红包金额
   * 文档有两处冲突描述
   * 一处指金额 >=1 (分钱)
   * 另一处指金额 >=100 < 20000 [1-200元]
   * 有待测试验证!
   * @param mixed $price 单位 分
   * @return void
   */
  public function setAmount($price){
    $this->total_amount = (int)$price;
    $this->min_value = (int)$price;
    $this->max_value = (int)$price;
  }

  //以下方法,为设置分裂红包时使用
  public function setHBminmax($min,$max){
    $this->min_value = $min;
    $this->max_value = $max;
  }

  public function setShare($img="",$url="",$content=""){
    //https://mmbiz.qlogo.cn/mmbiz/MS1jaDO92Ep4qNo9eV0rnItptyBrzUhJqT8oxSsCofdxibnNWMJiabaqgLPkDaEJmia6fqTXAXulKBa9NLfxYMwYA/0?wx_fmt=png
    //http://mp.weixin.qq.com/s?__biz=MzA5Njg4NTk3MA==&mid=206257621&idx=1&sn=56241da30e384e40771065051e4aa6a8#rd
    $this->share_content = $content;
    $this->share_imgurl = $img;
    $this->share_url = $url;
  }


  /**
   * WXHongBao::send()
   * 发出红包
   * 构造签名
   * 注意第二参数,单发时不要改动!
   * @return boolean $success
   */
  public function send(){

    $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
    $total_num = 1;

    if(!$this->wxhb_inited) {
      $this->error .= "(红包未准备好)";
      return false; //未初始化完成
    }

    $this->total_num = $total_num;

    $this->gen_Sign(); //生成签名

    //构造提交的数据    
    $xml = $this->genXMLParam();

    //echo $xml;

    //debug
    file_put_contents("hbxml.debug",$xml);

    //提交xml,curl
    //$url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
    $ch = curl_init();   
    curl_setopt($ch,CURLOPT_TIMEOUT,10);
    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);

    //curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
    curl_setopt($ch,CURLOPT_SSLCERT,$this->apiclient_cert);    
    //curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
    curl_setopt($ch,CURLOPT_SSLKEY,$this->apiclient_key);

    curl_setopt($ch,CURLOPT_CAINFO,$this->appclient_ca);

    /* 
    if( count($aHeader) >= 1 ){
      curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
    }
    */    
    curl_setopt($ch,CURLOPT_POST, 1);
    curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
    $data = curl_exec($ch);
     //die(print_r($data));
    if($data){
      curl_close($ch);
      $rsxml = simplexml_load_string($data);
      if($rsxml->return_code == 'SUCCESS' ){
        return true;
      }else{
        $this->error = json_encode($rsxml->return_msg);
        return false;  
      }
    }else{ 
      $this->error = curl_errno($ch);

      curl_close($ch);
      return false;
    }

  }

  private function gen_nonce_str(){
    $this->nonce_str = strtoupper(md5(mt_rand().time())); //确保不重复而已
  }

  private function gen_Sign(){
    unset($param); 
    //其实应该用key重排一次 right?
    $param["act_name"]=$this->act_name;//

    if($this->total_num==1){ //这些是裂变红包用不上的参数,会导致签名错误
      $param["client_ip"]=$this->client_ip;
       $param["max_value"]=$this->max_value;
       $param["min_value"]=$this->min_value;
      $param["nick_name"]=$this->nick_name;
    }

    $param["mch_billno"] = $this->mch_billno;  //   
    $param["mch_id"]=$this->mch_id;//    
    $param["nonce_str"]=$this->nonce_str;  //  
    $param["re_openid"]=$this->re_openid;//
    $param["remark"]=$this->remark;    //
    $param["send_name"]=$this->send_name;//
    $param["total_amount"]=$this->total_amount;//
    $param["total_num"]=$this->total_num;    //
    $param["wishing"]=$this->wishing;//
    $param["wxappid"]=$this->wxappid;//

    //裂变红包 用不到就注释掉
     if($this->share_content) $param["share_content"] = $this->share_content;
     if($this->share_imgurl) $param["share_imgurl"] = $this->share_imgurl;
     if($this->share_url) $param["share_url"] = $this->share_url;
    if($this->amt_type) $param["amt_type"] = $this->amt_type; //

    ksort($param); //按照键名排序...艹,上面排了我好久

    //$sign_raw = http_build_query($param)."&key=".$this->apikey;
    $sign_raw = "";
    foreach($param as $k => $v){
      $sign_raw .= $k."=".$v."&";
    }
    $sign_raw .= "key=".$this->apikey;
    //可以用下面方法查看
    // file_put_contents("11sign.txt",$sign_raw);//debug
    $this->sign = strtoupper(md5($sign_raw));

  }

  /**
   * WXHongBao::genXMLParam()
   * 生成post的参数xml数据包
   * 注意生成之前各项值要生成,尤其是Sign
   * @return $xml
   */
  public function genXMLParam(){
    // $xml = "<xml>


    //   <sign>".$this->sign."</sign> 
    //   <mch_billno>".$this->mch_billno."</mch_billno> 
    //   <mch_id>".$this->mch_id."</mch_id> 
    //   <wxappid>".$this->wxappid."</wxappid> 
    //   <nick_name><![CDATA[".$this->nick_name."]]></nick_name> 
    //   <send_name><![CDATA[".$this->send_name."]]></send_name> 
    //   <re_openid>".$this->re_openid."</re_openid> 
    //   <total_amount>".$this->total_amount."</total_amount> 
    //   <min_value>".$this->min_value."</min_value> 
    //   <max_value>".$this->max_value."</max_value> 
    //   <total_num>".$this->total_num."</total_num> 
    //   <wishing><![CDATA[".$this->wishing."]]></wishing> 
    //   <client_ip><![CDATA[".$this->client_ip."]]></client_ip> 
    //   <act_name><![CDATA[".$this->act_name."]]></act_name> 
    //   <remark><![CDATA[".$this->remark."]]></remark>       
    //   <nonce_str>".$this->nonce_str."</nonce_str>";
   $xml = "<xml>
         <act_name><![CDATA[".$this->act_name."]]></act_name> 
         <client_ip><![CDATA[".$this->client_ip."]]></client_ip> 
         <max_value>".$this->max_value."</max_value> 
          <mch_billno>".$this->mch_billno."</mch_billno> 
          <mch_id>".$this->mch_id."</mch_id>
          <min_value>".$this->min_value."</min_value> 
          <nick_name><![CDATA[".$this->nick_name."]]></nick_name> 
          <nonce_str>".$this->nonce_str."</nonce_str>
          <re_openid>".$this->re_openid."</re_openid> 
          <remark><![CDATA[".$this->remark."]]></remark>
           <send_name><![CDATA[".$this->send_name."]]></send_name>
           <total_amount>".$this->total_amount."</total_amount> 
           <total_num>".$this->total_num."</total_num>
           <wishing><![CDATA[".$this->wishing."]]></wishing>
           <wxappid>".$this->wxappid."</wxappid>
           <sign>".$this->sign."</sign> 
        </xml>
           ";

      // <nick_name><![CDATA[".$this->nick_name."]]></nick_name> 



      // <min_value>".$this->min_value."</min_value> 
      // <max_value>".$this->max_value."</max_value> 

    // $xml .="</xml>";

    return $xml;
  }

  /**
   * WXHongBao::gen_mch_billno()
   * 商户订单号(每个订单号必须唯一) 
    组成: mch_id+yyyymmdd+10位一天内不能重复的数字。 
    接口根据商户订单号支持重入, 如出现超时可再调用。 
   * @return void
   */
  private function gen_mch_billno(){
    //生成一个长度10,的阿拉伯数字随机字符串
    $rnd_num = array('0','1','2','3','4','5','6','7','8','9');
    $rndstr = "";
    while(strlen($rndstr)<10){
      $rndstr .= $rnd_num[array_rand($rnd_num)];  
    }

    $this->mch_billno = $this->mch_id.date("Ymd").$rndstr;
  }
}
/**
*1.上边是红包类,需要用的时候直接引入红包类。
*2.//实例化红包类
*  $wxhongbao=new \WXHongBao();
*3. //需要发放的openid 金额 openid 根据微信提供的接口获取,金额根据自己需求
* $wxhongbao->newhb($user_openid, $pay_money*100);
*$wxhongbao->setActName("根据自己需求设置");
* $wxhongbao->setWishing("根据自己需求设置");
*$wxhongbao->setRemark("根据自己需求设置");
*参数设置之后发放红包
*$wxhongbao->send();
**/
?>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP脚本的10个技巧(3)
Oct 09 PHP
php win下Socket方式发邮件类
Aug 21 PHP
PHP学习 变量使用总结
Mar 24 PHP
destoon实现调用当前栏目分类及子分类和三级分类的方法
Aug 21 PHP
php递归创建目录的方法
Feb 02 PHP
如何使用php实现评委评分器
Jul 31 PHP
PHP比较运算符的详细介绍
Sep 29 PHP
DWZ+ThinkPHP开发时遇到的问题分析
Dec 12 PHP
php获取网站根目录物理路径的几种方法(推荐)
Mar 04 PHP
浅谈laravel中的关联查询with的问题
Oct 10 PHP
解决thinkPHP 5 nginx 部署时,只跳转首页的问题
Oct 16 PHP
PHP 8新特性简介
Aug 18 PHP
ThinkPHP3.2框架自定义配置和加载用法示例
Jun 14 #PHP
thinkPHP框架实现多表查询的方法
Jun 14 #PHP
php微信开发之关注事件
Jun 14 #PHP
thinkPHP框架动态配置用法实例分析
Jun 14 #PHP
php微信开发之谷歌测距
Jun 14 #PHP
php微信开发之图片回复功能
Jun 14 #PHP
php微信开发之音乐回复功能
Jun 14 #PHP
You might like
PHP模板引擎SMARTY
2006/10/09 PHP
php checkbox复选框值的获取与checkbox默认值输出方法
2010/05/15 PHP
基于PHP字符串的比较函数strcmp()与strcasecmp()的使用详解
2013/05/15 PHP
php实现zip文件解压操作
2015/11/03 PHP
PHP统计目录中文件以及目录中目录大小的方法
2016/01/09 PHP
javascript设置金额样式转换保留两位小数示例代码
2013/12/04 Javascript
点击表单提交时出现jQuery没有权限的解决方法
2014/07/23 Javascript
常用的JavaScript模板引擎介绍
2015/02/28 Javascript
javascript实现3D切换焦点图
2015/10/16 Javascript
如何消除inline-block属性带来的标签间间隙
2016/03/31 Javascript
AngularJS上拉加载问题解决方法
2016/05/23 Javascript
Vue.js实现可排序的表格组件功能示例
2019/02/19 Javascript
js实现列表向上无限滚动
2020/01/13 Javascript
Python文件及目录操作实例详解
2015/06/04 Python
Python文件和流(实例讲解)
2017/09/12 Python
Flask框架WTForm表单用法示例
2018/07/20 Python
python pandas cumsum求累计次数的用法
2019/07/29 Python
Pytorch使用PIL和Numpy将单张图片转为Pytorch张量方式
2020/05/25 Python
Python分类测试代码实例汇总
2020/07/23 Python
使用Python将xmind脑图转成excel用例的实现代码(一)
2020/10/12 Python
用HTML5.0制作网页的教程
2010/05/30 HTML / CSS
HTML5 图片悬停放大的实现代码示例
2019/12/04 HTML / CSS
海滩咖啡馆:Beach Cafe
2018/02/02 全球购物
大学四年规划书范文
2013/12/27 职场文书
新闻学专业大学生职业生涯规划范文
2014/03/02 职场文书
竞聘书模板
2014/03/31 职场文书
学校安全责任书
2014/04/14 职场文书
《天安门广场》教学反思
2014/04/23 职场文书
道路交通事故人身损害赔偿协议书
2014/11/19 职场文书
总经理司机岗位职责
2015/04/10 职场文书
python munch库的使用解析
2021/05/25 Python
详解Java实践之抽象工厂模式
2021/06/18 Java/Android
JavaScript实现登录窗体
2021/06/22 Javascript
Python 处理表格进行成绩排序的操作代码
2021/07/26 Python
动画「进击的巨人」第86话播出感谢绘公开
2022/03/21 日漫
Python语法学习之进程的创建与常用方法详解
2022/04/08 Python