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截取中文字符串的问题
Jul 12 PHP
十天学会php之第一天
Oct 09 PHP
PHP+XML 制作简单的留言本 图文教程
Nov 02 PHP
php二维数组转成字符串示例
Feb 17 PHP
php使用多个进程同时控制文件读写示例
Feb 28 PHP
php数组添加元素方法小结
Dec 20 PHP
PHP和Shell实现检查SAMBA与NFS Server是否存在
Jan 07 PHP
基于php的微信公众平台开发入门实例
Apr 15 PHP
PHP实现HTTP断点续传的方法
Jun 17 PHP
PHP扩展开发教程(总结)
Nov 04 PHP
Zend Framework实现多服务器共享SESSION数据的方法
Mar 22 PHP
MAC下通过改apache配置文件切换php多版本的方法
Apr 26 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
PHP编码转换函数 自动转换字符集支持数组转换
2012/12/16 PHP
PHP zip扩展Linux下安装过程分享
2014/05/05 PHP
destoon在360浏览器下出现用户被强行注销的解决方法
2014/06/26 PHP
php+xml编程之SimpleXML的应用实例
2015/01/24 PHP
PHP获取当前文件的父目录方法汇总
2016/07/21 PHP
php 遍历目录,生成目录下每个文件的md5值并写入到结果文件中
2016/12/12 PHP
PHP上传文件及图片到七牛的方法
2018/07/25 PHP
js word表格动态添加代码
2010/06/07 Javascript
理解Javascript闭包
2013/11/01 Javascript
jquery自定义滚动条插件示例分享
2014/02/21 Javascript
三种动态加载js的jquery实例代码另附去除js方法
2014/04/30 Javascript
jquery通过visible来判断标签是否显示或隐藏
2014/05/08 Javascript
禁用Enter键表单自动提交实现代码
2014/05/22 Javascript
非jQuery实现照片散落桌子上,单击放大的LightBox效果
2014/11/28 Javascript
node.js中的http.request.end方法使用说明
2014/12/10 Javascript
jQuery在ul中显示某个li索引号的方法
2015/03/17 Javascript
jQuery版本升级踩坑大全
2016/01/12 Javascript
MUI  Scroll插件的使用详解
2017/04/13 Javascript
extjs简介_动力节点Java学院整理
2017/07/17 Javascript
jQueryMobile之窗体长内容的缺陷与解决方法实例分析
2017/09/20 jQuery
微信小程序picker组件下拉框选择input输入框的实例
2017/09/20 Javascript
详解如何去除vue项目中的#——History模式
2017/10/13 Javascript
JavaScript实现三级级联特效
2017/11/05 Javascript
NodeJS 中Stream 的基本使用
2018/07/30 NodeJs
Vuex 单状态库与多模块状态库详解
2018/12/11 Javascript
介绍Python中的文档测试模块
2015/04/28 Python
Python制作钉钉加密/解密工具
2016/12/07 Python
PyCharm2020.1.2社区版安装,配置及使用教程详解(Windows)
2020/08/07 Python
函数指针的定义是什么
2016/08/14 面试题
机电一体化毕业生求职信
2013/11/02 职场文书
建筑学推荐信
2013/11/03 职场文书
上班离岗检讨书
2014/09/10 职场文书
小学总务工作总结
2015/08/13 职场文书
人事部:年度述职报告范文
2019/07/12 职场文书
MySQL复制问题的三个参数分析
2021/04/07 MySQL
SQL Server中使用表变量和临时表
2022/05/20 SQL Server