微信发红包 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\n";
            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...

posted @ 2018-09-04 21:53  御世制人  阅读(324)  评论(0编辑  收藏  举报