php实现微信发红包


Posted in PHP onDecember 05, 2015

本文实例讲述了php实现的微信红包算法。分享给大家供大家参考。具体如下:

php实现微信发红包

具体代码:

<?php
/**
 * 微信红包的类 
 * 
 */

CLASS WXHongBao {
  
  private $mch_id = "111111";//商户ID写死
  private $wxappid = "22222222";//微信公众号,写死
  private $client_ip = "119.29.80.114"; //调用红包接口的主机的IP,服务端IP,写死,即脚本文件所在的IP
  private $apikey = "33333333";//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 $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()."/apiclient_cert.pem";
    $this->apiclient_key = getcwd()."/apiclient_key.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::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();
    
    
    //debug
    file_put_contents("hbxml.txt",$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);
    
    /* 
    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);
    if($data){
      curl_close($ch);  
      $rsxml = simplexml_load_string($data);
      if($rsxml->return_code == 'SUCCESS' ){
        return true;
      }else{
        $this->error = $rsxml->return_msg;
        return false;  
      }
      
    }else{ 
      $this->error = curl_errno($ch);
       
      curl_close($ch);
      return false;
    }

  }
  
  /**
   * 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;
  }
  
  /**
   * WXHongBao::setActName()
   * 活动名称 
   * @param mixed $act
   * @return void
   */
  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 = $price;
    $this->min_value = $price;
    $this->max_value = $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;
  }
  
  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("sign.raw",$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>
      "; 
    
      
    if($this->share_content) $xml .= "<share_content><![CDATA[".$this->share_content."]]></share_content>
    ";
    if($this->share_imgurl) $xml .= "<share_imgurl><![CDATA[".$this->share_imgurl."]]></share_imgurl>
    ";
    if($this->share_url) $xml .= "<share_url><![CDATA[".$this->share_url."]]></share_url>
    ";
    if($this->amt_type) $xml .= "<amt_type><![CDATA[".$this->amt_type."]]></amt_type>
    ";
    
    $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;
  }
}
?>

然后实例化class.

 $toOpenId = 'asdasdasd'; //接收红包的用户的微信OpenId
    $hb = new WXHongBao();

    $hb->newhb($toOpenId,1000); //新建一个10元的红包,第二参数单位是 分,注意取值范围 1-200元
    //以下若干项可选操作,不指定则使用class脚本顶部的预设值
     $hb->setNickName("土豪有限公司");
     $hb->setSendName("土豪");
     $hb->setWishing("恭喜发财");
     $hb->setActName("发钱活动");
     $hb->setRemark("任性一把");

    //发送红包

    if(!$hb->send()){ //发送错误

      echo $hb->err();

    }else{

      echo "红包发送成功";

    }

希望本文所述对大家的php程序设计有所帮助。

PHP 相关文章推荐
PHP中uploaded_files函数使用方法详解
Mar 09 PHP
ThinkPHP之foreach标签使用概述
Jun 30 PHP
PHP实现Soap通讯的方法
Nov 03 PHP
php格式输出文件var_export函数实例
Nov 15 PHP
Codeigniter的一些优秀特性总结
Jan 21 PHP
PHP借助phpmailer发送邮件
May 11 PHP
PHP中的事务使用实例
May 26 PHP
ThinkPHP5实现作业管理系统中处理学生未交作业与已交作业信息的方法
Nov 12 PHP
Yii CDBCriteria常用方法实例小结
Jan 19 PHP
PHP实现对xml进行简单的增删改查(CRUD)操作示例
May 19 PHP
Laravel框架表单验证操作实例分析
Sep 30 PHP
laravel在中间件内生成参数并且传递到控制器中的2种姿势
Oct 15 PHP
详解php比较操作符的安全问题
Dec 03 #PHP
thinkPHP模型初始化实例分析
Dec 03 #PHP
ZF框架实现发送邮件的方法
Dec 03 #PHP
PHP实现的蚂蚁爬杆路径算法代码
Dec 03 #PHP
PHP实现QQ空间自动回复说说的方法
Dec 02 #PHP
如何在旧的PHP系统中使用PHP 5.3之后的库
Dec 02 #PHP
thinkphp微信开发(消息加密解密)
Dec 02 #PHP
You might like
浅谈电磁辐射对健康的影响
2021/03/01 无线电
PHP 面向对象程序设计(oop)学习笔记 (五) - PHP 命名空间
2014/06/12 PHP
实用的PHP带公钥加密类分享(每次加密结果都不一样哦)
2014/08/20 PHP
ThinkPHP使用Smarty第三方插件方法小结
2016/03/19 PHP
浅谈PHP5.6 与 PHP7.0 区别
2019/10/09 PHP
javascript编程起步(第六课)
2007/01/10 Javascript
js操作时间(年-月-日 时-分-秒 星期几)
2010/06/20 Javascript
清空上传控件input file的值
2010/07/03 Javascript
jQuery实现按钮只点击一次后就取消点击事件绑定的方法
2015/06/26 Javascript
基于jQuery实现歌词滚动版音乐播放器的代码
2016/09/17 Javascript
canvas仿iwatch时钟效果
2017/03/06 Javascript
vue watch监听对象及对应值的变化详解
2018/02/24 Javascript
亲自动手实现vue日历控件
2019/06/26 Javascript
实例讲解React 组件
2020/07/07 Javascript
javascript实现简单页面倒计时
2021/03/02 Javascript
在Django框架中运行Python应用全攻略
2015/07/17 Python
在Linux系统上部署Apache+Python+Django+MySQL环境
2015/12/24 Python
Python实现购物程序思路及代码
2017/07/24 Python
python实现dijkstra最短路由算法
2019/01/17 Python
对Python实现累加函数的方法详解
2019/01/23 Python
python实现列表中最大最小值输出的示例
2019/07/09 Python
python获取指定日期范围内的每一天,每个月,每季度的方法
2019/08/08 Python
tensorflow 固定部分参数训练,只训练部分参数的实例
2020/01/20 Python
Python视频编辑库MoviePy的使用
2020/04/01 Python
Python实现自动签到脚本功能
2020/08/20 Python
Python页面加载的等待方式总结
2021/02/28 Python
简单介绍HTML5中audio标签的使用
2015/09/24 HTML / CSS
个人生活学习自我评价范文
2013/11/26 职场文书
银行员工辞职信范文
2014/01/20 职场文书
体育系毕业生求职自荐信
2014/04/16 职场文书
发展党员工作情况汇报
2014/10/28 职场文书
出国留学单位推荐信
2015/03/26 职场文书
兴趣班停课通知
2015/04/24 职场文书
python如何利用traceback获取详细的异常信息
2021/06/05 Python
公历12个月名称的由来
2022/04/12 杂记
vue如何在data中引入图片的正确路径
2022/06/05 Vue.js