zoukankan      html  css  js  c++  java
  • 微信发红包 PHP 实现

    最近做生日营销,需要微信发红包,特此从网上找了一篇教程

    首先你的有个服务号,并且开通了微信支付,我在这就不说怎么去申请和开通了,我是看了微信官方文档后,想看官方文档的朋友可以到下面这个链接

    https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_1

    class WxRedPack
    {
        //配置参数信息
        const SHANGHUHAO = "***********";//商户号
        const PARTNERKEY = "***********";
    
        //核心支付函数,参数:请求地址和参数
        function pay($url, $obj)
        {
            $obj['nonce_str'] = $this->create_noncestr();    //创建随机字符串
            $stringA = $this->create_qianming($obj, false);    //创建签名
            $stringSignTemp = $stringA . "&key=2470f691aee2bfae92087c10e81cb4d0";    //签名后加api
            $sign = strtoupper(md5($stringSignTemp));    //签名加密并大写
            $obj['sign'] = $sign;    //将签名传入数组
            $postXml = $this->arrayToXml($obj);    //将参数转为xml格式
            $responseXml = $this->curl_post_ssl($url, $postXml);    //提交请求
            return $responseXml;
        }
    
        //生成签名,参数:生成签名的参数和是否编码
        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位
        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
        function arrayToXml($arr)
        {
            $xml = "<xml>";
            foreach ($arr as $key => $val) {
                if (is_numeric($val)) {
                    $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
                } else {
                    $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
                }
            }
            $xml .= "</xml>";
            return $xml;
        }
    
        //post请求网站,需要证书
        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, dirname(__FILE__) . DIRECTORY_SEPARATOR .
                'cert' . DIRECTORY_SEPARATOR . 'apiclient_cert.pem');
            curl_setopt($ch, CURLOPT_SSLKEY, dirname(__FILE__) . DIRECTORY_SEPARATOR .
                'cert' . DIRECTORY_SEPARATOR . 'apiclient_key.pem');
            curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . DIRECTORY_SEPARATOR .
                'cert' . DIRECTORY_SEPARATOR . '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
    ";
                curl_close($ch);
                return false;
            }
        }
    
    }
    然后调用:
    public function setredpack($moneys,$openid)
        {
            $money = $moneys; //最低1元,单位分
            $sender = "******";
            $obj2 = array();
            $obj2['wxappid'] = "**********"; //appid
            $obj2['mch_id'] = "***********";        //商户id
            $obj2['mch_billno'] = "********" . date('YmdHis') . rand(1000, 9999);//商户订单号
            $obj2['client_ip'] = $_SERVER['REMOTE_ADDR'];
            $obj2['re_openid'] = $openid; //接收红包openid
            $obj2['total_amount'] = $money;
            $obj2['min_value'] = $money;
            $obj2['max_value'] = $money;
            $obj2['total_num'] = 1;
            $obj2['scene_id'] = 'PRODUCT_2';
            $obj2['nick_name'] = $sender;
            $obj2['send_name'] = $sender;
            $obj2['wishing'] = "恭喜发财";
            $obj2['act_name'] = $sender ;
            $obj2['remark'] = $sender ;
    
            $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
         $Wxpay = new WxRedPack();
        $res = $wxpay->pay($url, $obj2);return $res; 
    }
    另一个版本方法:

    一个PHP文件搞定微信支付系列之现金红包

    网上的很多PHP微信支付接入教程都颇为复杂,且需要配置和引入较多的文件,本人通过整理后给出一个单文件版的,希望可以给各位想接入微信支付的带来些许帮助和借鉴意义。

    直接运行该文件即可给指定的微信用户发送现金红包。

    需要注意的事项:

    • 1.微信现金红包要求必传证书,需要到https://pay.weixin.qq.com 账户中心->账户设置->API安全->下载证书,然后修改代码中的证书路径

    • 2.默认的使用场景是抽奖(即scene_id参数为PRODUCT_2),额度是1-200元,所以测试时的最低金额是1元。如需修改在产品中心->产品大全->现金红包->产品设置中修改

    • 3.该文件需放到支付授权目录下,可以在微信支付商户平台->产品中心->开发配置中设置。

    • 4.如提示签名错误可以通过微信支付签名验证工具进行验证:https://pay.weixin.qq.com/wik...

    • 5.错误码参照 :https://pay.weixin.qq.com/wik...

    • <?php
      /**
       * 关于微信现金红包的说明
       * 1.微信现金红包要求必传证书,需要到https://pay.weixin.qq.com 账户中心->账户设置->API安全->下载证书,证书路径在第214行和217行修改
       * 2.默认的使用场景是抽奖(即scene_id参数为PRODUCT_2),额度是1-200元,所以测试时的最低金额是1元。如需修改在产品中心->产品大全->现金红包->产品设置中修改
       * 3.错误码参照 :https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
       */
      header('Content-type:text/html; Charset=utf-8');
      $mchid = 'xxxxx';          //微信支付商户号 PartnerID 通过微信支付商户资料审核后邮件发送
      $appid = 'xxxxx';  //微信支付申请对应的公众号的APPID
      $appKey = 'xxxxx';   //微信支付申请对应的公众号的APP Key
      $apiKey = 'xxxxx';   //https://pay.weixin.qq.com 帐户设置-安全设置-API安全-API密钥-设置API密钥
      
      //①、获取当前访问页面的用户openid(如果给指定用户发送红包,则填写指定用户的openid)
      $wxPay = new WxpayService($mchid,$appid,$appKey,$apiKey);
      $openId = $wxPay->GetOpenid();      //获取openid
      if(!$openId) exit('获取openid失败');
      //②、发送红包
      $outTradeNo = uniqid();     //你自己的商品订单号
      $payAmount = 1;          //红包金额,单位:元
      $sendName = '织梦猫';    //红包发送者名称
      $wishing = '感谢您参加猜灯谜活动,祝您元宵节快乐!';      //红包祝福语
      $act_name='猜灯谜抢红包活动';           //活动名称
      $result = $wxPay->createJsBizPackage($openId,$payAmount,$outTradeNo,$sendName,$wishing,$act_name);
      echo 'success';
      
      class WxpayService
      {
          protected $mchid;
          protected $appid;
          protected $appKey;
          protected $apiKey;
          public $data = null;
      
          public function __construct($mchid, $appid, $appKey,$key)
          {
              $this->mchid = $mchid;
              $this->appid = $appid;
              $this->appKey = $appKey;
              $this->apiKey = $key;
          }
      
          /**
           * 通过跳转获取用户的openid,跳转流程如下:
           * 1、设置自己需要调回的url及其其他参数,跳转到微信服务器https://open.weixin.qq.com/connect/oauth2/authorize
           * 2、微信服务处理完成之后会跳转回用户redirect_uri地址,此时会带上一些参数,如:code
           * @return 用户的openid
           */
          public function GetOpenid()
          {
              //通过code获得openid
              if (!isset($_GET['code'])){
                  //触发微信返回code码
                  $scheme = $_SERVER['HTTPS']=='on' ? 'https://' : 'http://';
                  $baseUrl = urlencode($scheme.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);
                  $url = $this->__CreateOauthUrlForCode($baseUrl);
                  Header("Location: $url");
                  exit();
              } else {
                  //获取code码,以获取openid
                  $code = $_GET['code'];
                  $openid = $this->getOpenidFromMp($code);
                  return $openid;
              }
          }
      
          /**
           * 通过code从工作平台获取openid机器access_token
           * @param string $code 微信跳转回来带上的code
           * @return openid
           */
          public function GetOpenidFromMp($code)
          {
              $url = $this->__CreateOauthUrlForOpenid($code);
              $res = self::curlGet($url);
              //取出openid
              $data = json_decode($res,true);
              $this->data = $data;
              $openid = $data['openid'];
              return $openid;
          }
      
          /**
           * 构造获取open和access_toke的url地址
           * @param string $code,微信跳转带回的code
           * @return 请求的url
           */
          private function __CreateOauthUrlForOpenid($code)
          {
              $urlObj["appid"] = $this->appid;
              $urlObj["secret"] = $this->appKey;
              $urlObj["code"] = $code;
              $urlObj["grant_type"] = "authorization_code";
              $bizString = $this->ToUrlParams($urlObj);
              return "https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString;
          }
      
          /**
           * 构造获取code的url连接
           * @param string $redirectUrl 微信服务器回跳的url,需要url编码
           * @return 返回构造好的url
           */
          private function __CreateOauthUrlForCode($redirectUrl)
          {
              $urlObj["appid"] = $this->appid;
              $urlObj["redirect_uri"] = "$redirectUrl";
              $urlObj["response_type"] = "code";
              $urlObj["scope"] = "snsapi_base";
              $urlObj["state"] = "STATE"."#wechat_redirect";
              $bizString = $this->ToUrlParams($urlObj);
              return "https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString;
          }
      
          /**
           * 拼接签名字符串
           * @param array $urlObj
           * @return 返回已经拼接好的字符串
           */
          private function ToUrlParams($urlObj)
          {
              $buff = "";
              foreach ($urlObj as $k => $v)
              {
                  if($k != "sign") $buff .= $k . "=" . $v . "&";
              }
              $buff = trim($buff, "&");
              return $buff;
          }
      
          /**
           * 发送红包
           * @param string $openid 用户在该公众号下的Openid
           * @param float $totalFee 红包金额 单位元
           * @param string $outTradeNo 订单号
           * @param string $orderName 红包发送者名称
           * @param string $wishing 祝福语
           * @param string $actName 互动名称
           * @return string
           */
          public function createJsBizPackage($openid, $totalFee, $outTradeNo, $sendName,$wishing,$actName)
          {
              $config = array(
                  'mch_id' => $this->mchid,
                  'appid' => $this->appid,
                  'key' => $this->apiKey,
              );
              $unified = array(
                  'wxappid' => $config['appid'],
                  'send_name' => $sendName,
                  'mch_id' => $config['mch_id'],
                  'nonce_str' => self::createNonceStr(),
                  're_openid' => $openid,
                  'mch_billno' => $outTradeNo,
                  'client_ip' => '127.0.0.1',
                  'total_amount' => intval($totalFee * 100),       //单位 转为分
                  'total_num'=>1,                 //红包发放总人数
                  'wishing'=>$wishing,            //红包祝福语
                  'act_name'=>$actName,           //活动名称
                  'remark'=>'remark',            //备注信息,如为中文注意转为UTF8编码
                  'scene_id'=>'PRODUCT_2',      //发放红包使用场景,红包金额大于200时必传。https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
              );
              $unified['sign'] = self::getSign($unified, $config['key']);
              $responseXml = $this->curlPost('https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack', self::arrayToXml($unified));
              $unifiedOrder = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
              if ($unifiedOrder === false) {
                  die('parse xml error');
              }
              if ($unifiedOrder->return_code != 'SUCCESS') {
                  die($unifiedOrder->return_msg);
              }
              if ($unifiedOrder->result_code != 'SUCCESS') {
                  die($unifiedOrder->err_code);
              }
              return true;
          }
      
          public static function curlGet($url = '', $options = array())
          {
              $ch = curl_init($url);
              curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
              curl_setopt($ch, CURLOPT_TIMEOUT, 30);
              if (!empty($options)) {
                  curl_setopt_array($ch, $options);
              }
              //https请求 不验证证书和host
              curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
              curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
              $data = curl_exec($ch);
              curl_close($ch);
              return $data;
          }
      
          public function curlPost($url = '', $postData = '', $options = array())
          {
              if (is_array($postData)) {
                  $postData = http_build_query($postData);
              }
              $ch = curl_init();
              curl_setopt($ch, CURLOPT_URL, $url);
              curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
              curl_setopt($ch, CURLOPT_POST, 1);
              curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
              curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
              if (!empty($options)) {
                  curl_setopt_array($ch, $options);
              }
              //https请求 不验证证书和host
              curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
              curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
      
              //第一种方法,cert 与 key 分别属于两个.pem文件
              //默认格式为PEM,可以注释
              curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
              curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/cert/apiclient_cert.pem');
              //默认格式为PEM,可以注释
              curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
              curl_setopt($ch,CURLOPT_SSLKEY,getcwd().'/cert/apiclient_key.pem');
              //第二种方式,两个文件合成一个.pem文件
      //        curl_setopt($ch,CURLOPT_SSLCERT,getcwd().'/all.pem');
              $data = curl_exec($ch);
              curl_close($ch);
              return $data;
          }
      
          public static function createNonceStr($length = 16)
          {
              $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
              $str = '';
              for ($i = 0; $i < $length; $i++) {
                  $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
              }
              return $str;
          }
          public static function arrayToXml($arr)
          {
              $xml = "<xml>";
              foreach ($arr as $key => $val) {
                  if (is_numeric($val)) {
                      $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
                  } else
                      $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
              }
              $xml .= "</xml>";
              return $xml;
          }
      
          public static function getSign($params, $key)
          {
              ksort($params, SORT_STRING);
              $unSignParaString = self::formatQueryParaMap($params, false);
              $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
              return $signStr;
          }
          protected static function formatQueryParaMap($paraMap, $urlEncode = false)
          {
              $buff = "";
              ksort($paraMap);
              foreach ($paraMap as $k => $v) {
                  if (null != $v && "null" != $v) {
                      if ($urlEncode) {
                          $v = urlencode($v);
                      }
                      $buff .= $k . "=" . $v . "&";
                  }
              }
              $reqPar = '';
              if (strlen($buff) > 0) {
                  $reqPar = substr($buff, 0, strlen($buff) - 1);
              }
              return $reqPar;
          }
      }
      ?>

      github下载地址:https://github.com/dedemao/we...

  • 相关阅读:
    Java后端WebSocket的Tomcat实现
    Shiro session和Spring session一样吗?
    HTTP请求类
    JSP页面中的时间显示问题
    Oracle在linux中相关设置操作
    关于BigDecimal类型在jsp页面中进行除法运算问题
    Spring与Redis的实现
    gson介绍
    busybox介绍
    vsftp中426 Failure writing network stream的错误解决
  • 原文地址:https://www.cnblogs.com/yszr/p/9588745.html
Copyright © 2011-2022 走看看