技术饭

PHP实现微信支付的现金红包、企业付款到零钱功能

copylian    0 评论    821 浏览    2020.08.07

企业付款:

提供由商户直接付钱至用户微信零钱的能力,支持平台操作及接口调用两种方式。具有免费、快速到账、灵活、安全等优点。商户可以使用企业付款,用于如:费用报销、员工福利、用户奖励等。

微信红包:

2014年春节一推出即受到广大用户好评,引发全民抢红包热潮。现将微信红包打造成“现金红包”,作为一款定向资金发放的营销工具,供商户使用。用户在客户端领取到红包之后,所得金额进入微信钱包,可用于转账、支付或提取到银行卡。

官方文档:

企业付款到零钱:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1

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

开通功能使用条件

商户号(或同主体其他非服务商商户号)已入驻90日商户号(或同主体其他非服务商商户号)有30天连续正常交易登录微信支付商户平台-产品中心,开通企业付款。具体的可以看微信支付开发文档

示例代码:

<?php
/**
 * Author [ CopyLian ]
 * Date: [ 2018.11.10 ]
 * Email: [ copylian@aikehou.com ]
 * Site: [ https://www.copylian.com/ ]
 * Description: [ 企业付款到零钱、红包发送接口基类 ]
 */
namespace wechat;

class WechatMmpaymk {

    //公众号APPID
    private $appid;

    //支付密钥签名
    private $secret;

    //IP
    private $ip;

    //微信接口域名
    private $api_url;

    //商户号
    private $mchid;

    /**
     * [__construct 构造函数]
     */
    public function __construct($prefix = '') {

        //前缀
        $prefix = !empty($prefix) ? $prefix : '';

        //初始化数据
        $this->appid = config('wechatpay.' . $prefix . 'pay_account.appid');
        $this->secret = config('wechatpay.' . $prefix . 'pay_account.secret');
        $this->mchid = config('wechatpay.' . $prefix . 'pay_account.mchid');
        $this->ip = config('wechatpay.' . $prefix . 'pay_account.ip');
        $this->api_url = config('wechatpay.' . $prefix . 'pay_account.api_url');
    }

    /**
     * [xmltoarray xml格式转换为数组]
     * @param  [type] $xml [xml]
     * @return [type]      [xml 转化为array]
     */
    public function xmltoarray($xml) { 
         //禁止引用外部xml实体 
        libxml_disable_entity_loader(true); 
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); 
        $val = json_decode(json_encode($xmlstring), true); 
        return $val;
    }

    /**
     * [arraytoxml 将数组转换成xml格式(简单方法):]
     * @param  [type] $data [数组]
     * @return [type]       [array 转 xml]
     */
    public function arraytoxml($data){
        $str='<xml>';
        foreach($data as $k=>$v) {
            $str.='<'.$k.'>'.$v.'</'.$k.'>';
        }
        $str.='</xml>';
        return $str;
    }

    /**
     * [createNoncestr 生成随机字符串]
     * @param  integer $length [长度]
     * @return [type]          [字母大小写加数字]
     */
    public function createNoncestr($length =32){
        $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz0123456789";  
        $str = "";

        for($i=0; $i < $length; $i++){  
            $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);   
        }  
        return $str;
    }

    /**
     * [curl_post_ssl 发送curl_post数据]
     * @param  [type]  $url     [发送地址]
     * @param  [type]  $xmldata [发送文件格式]
     * @param  [type]  $second [设置执行最长秒数]
     * @param  [type]  $aHeader [设置头部]
     * @return [type]           [description]
     */
    function curl_post_ssl($url, $vars, $second = 30, $aHeader = array()){
        //证书位置
        $isdir = __DIR__."/cert/";

        //初始化curl
        $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);//
        curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');//证书类型
        curl_setopt($ch, CURLOPT_SSLCERT, $isdir . 'apiclient_cert.pem');//证书位置
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');//CURLOPT_SSLKEY中规定的私钥的加密类型
        curl_setopt($ch, CURLOPT_SSLKEY, $isdir . 'apiclient_key.pem');//证书位置
        curl_setopt($ch, CURLOPT_CAINFO, 'PEM');
        curl_setopt($ch, CURLOPT_CAINFO, $isdir . 'rootca.pem');
        if (count($aHeader) >= 1) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);//设置头部
        }
        curl_setopt($ch, CURLOPT_POST, 1);//post提交方式
        curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);//全部数据使用HTTP协议中的"POST"操作来发送

        $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;
        }
    }

    /**
     * [sendMoneyToChange 企业付款到零钱]
     * @param  [type] $snedData   [数据]
     */
    public function sendMoneyToChange($snedData = []){

        //总金额
        if(empty($snedData) || !isset($snedData['order_sn']) || !isset($snedData['openid']) || !isset($snedData['amount']) || !isset($snedData['order_sn'])){
            //返回数据
            $rdata['code'] = 0;
            $rdata['msg'] = '参数异常';
            return $rdata;
        }

        //数据
        $data = array(
            'mch_appid' => $this->appid,//商户账号appid
            'mchid' => $this->mchid,//商户号
            'nonce_str' => $this->createNoncestr(),//随机字符串
            'partner_trade_no' => $snedData['order_sn'],//商户订单号
            'openid' => $snedData['openid'],//用户openid
            'check_name' => isset($snedData['check_name']) ? $snedData['check_name'] : 'NO_CHECK',//校验用户姓名选项,
            're_user_name' => isset($snedData['re_user_name']) ? $snedData['re_user_name'] : '',//收款用户姓名
            'amount' => $snedData['amount'],//金额
            'desc' => $snedData['desc'],//企业付款描述信息
            'spbill_create_ip' => $this->ip //Ip地址
        );

        //生成签名算法
        $secrect_key = $this->secret;///这个就是个API密码。MD5 32位。
        $data = array_filter($data);
        ksort($data);
        $str = '';
        foreach($data as $k=>$v) {
           $str .= $k . '=' . $v . '&';
        }
        $str .= 'key=' . $secrect_key;
        $data['sign'] = md5($str);

        //生成签名算法
        $xml = $this->arraytoxml($data);
      
        $url = $this->api_url . 'mmpaymkttransfers/promotion/transfers'; //调用接口
        $res = $this->curl_post_ssl($url,$xml);
        $return = $this->xmltoarray($res);

        //返回数据
        $rdata['code'] = 1;
        $rdata['msg'] = '提交成功';
        $rdata['data'] = $return;
        return $rdata;
    }

    /**
     * [queryChange 查询企业付款到零钱]
     * @param  [type] $snedData   [数据]
     */
    public function queryChange($snedData = []){

        //总金额
        if(empty($snedData) || !isset($snedData['order_sn'])){
            //返回数据
            $rdata['code'] = 0;
            $rdata['msg'] = '参数异常';
            return $rdata;
        }

        //数据
        $data = array(
            'appid' => $this->appid,//商户账号appid
            'mch_id' => $this->mchid,//商户号
            'nonce_str' => $this->createNoncestr(),//随机字符串
            'partner_trade_no' => $snedData['order_sn']//商户订单号
        );

        //生成签名算法
        $secrect_key = $this->secret;///这个就是个API密码。MD5 32位。
        $data = array_filter($data);
        ksort($data);
        $str = '';
        foreach($data as $k=>$v) {
           $str .= $k . '=' . $v . '&';
        }
        $str .= 'key=' . $secrect_key;
        $data['sign'] = md5($str);

        //生成签名算法
        $xml = $this->arraytoxml($data);
      
        $url = $this->api_url . 'mmpaymkttransfers/gettransferinfo'; //调用接口
        $res = $this->curl_post_ssl($url,$xml);
        $return = $this->xmltoarray($res);

        //返回数据
        $rdata['code'] = 1;
        $rdata['msg'] = '提交成功';
        $rdata['data'] = $return;
        return $rdata;
    }

    /**
     * [redPacketPay 现金红包]
     * @param  [type] $snedData   [数据]
     */
    public function redPacketPay($snedData = []){

        //总金额
        if(empty($snedData) || !isset($snedData['order_sn']) || !isset($snedData['openid']) || !isset($snedData['amount']) || !isset($snedData['order_sn'])){
            //返回数据
            $rdata['code'] = 0;
            $rdata['msg'] = '参数异常';
            return $rdata;
        }

        //数据
        $data = array(
            'wxappid' => $this->appid,//商户账号appid
            'mch_id' => $this->mchid,//商户号
            'nonce_str' => $this->createNoncestr(),//随机字符串
            'mch_billno' => $snedData['order_sn'],//商户订单号
            're_openid' => $snedData['openid'],//用户openid
            'act_name' =>  isset($snedData['act_name']) ? $snedData['act_name'] : '红包活动', //活动名称
            'send_name' => isset($snedData['send_name']) ? $snedData['send_name'] : '多想互动',//红包发送者名称
            'wishing' => isset($snedData['wishing']) ? $snedData['wishing'] : '恭喜发财', //红包祝福语
            'remark' =>  isset($snedData['remark']) ? $snedData['remark'] : '抢到红包了,恭喜发财!', //备注
            'total_num' => 1, //红包发放总人数
            'total_amount' => $snedData['amount'],//金额
            'client_ip' => $this->ip, //Ip地址
            'scene_id' => 'PRODUCT_2' //场景id,发放红包使用场景,红包金额大于200或者小于1元时必传 PRODUCT_1:商品促销;PRODUCT_2:抽奖;PRODUCT_3:虚拟物品兑奖 ;PRODUCT_4:企业内部福利;PRODUCT_5:渠道分润;PRODUCT_6:保险回馈;PRODUCT_7:彩票派奖;PRODUCT_8:税务刮奖
        );

        //生成签名算法
        $secrect_key = $this->secret;///这个就是个API密码。MD5 32位。
        $data = array_filter($data);
        ksort($data);
        $str = '';
        foreach($data as $k=>$v) {
           $str .= $k . '=' . $v . '&';
        }
        $str .= 'key=' . $secrect_key;
        $data['sign'] = md5($str);

        //生成签名算法
        $xml = $this->arraytoxml($data);
      
        $url = $this->api_url . 'mmpaymkttransfers/sendredpack'; //调用接口
        $res = $this->curl_post_ssl($url,$xml);
        $return = $this->xmltoarray($res);

        //返回数据
        $rdata['code'] = 1;
        $rdata['msg'] = '提交成功';
        $rdata['data'] = $return;
        return $rdata;
    }

    /**
     * [queryRedPacket 查询现金红包]
     * @param  [type] $snedData   [数据]
     */
    public function queryRedPacket($snedData = []){

        //总金额
        if(empty($snedData) || !isset($snedData['order_sn'])){
            //返回数据
            $rdata['code'] = 0;
            $rdata['msg'] = '参数异常';
            return $rdata;
        }

        //数据
        $data = array(
            'appid' => $this->appid,//商户账号appid
            'mch_id' => $this->mchid,//商户号
            'nonce_str' => $this->createNoncestr(),//随机字符串
            'mch_billno' => $snedData['order_sn'], //商户订单号
            'bill_type' => 'MCHT', //MCHT:通过商户订单号获取红包信息。
        );

        //生成签名算法
        $secrect_key = $this->secret;///这个就是个API密码。MD5 32位。
        $data = array_filter($data);
        ksort($data);
        $str = '';
        foreach($data as $k=>$v) {
           $str .= $k . '=' . $v . '&';
        }
        $str .= 'key=' . $secrect_key;
        $data['sign'] = md5($str);

        //生成签名算法
        $xml = $this->arraytoxml($data);
      
        $url = $this->api_url . 'mmpaymkttransfers/gethbinfo'; //调用接口
        $res = $this->curl_post_ssl($url,$xml);
        $return = $this->xmltoarray($res);

        //返回数据
        $rdata['code'] = 1;
        $rdata['msg'] = '提交成功';
        $rdata['data'] = $return;
        return $rdata;
    }
}
<?php
/**
 * Author: [ CopyLian ]
 * Date: [ 2017.02.23 ]
 * Email: [ copylian@aikehou.com ]
 * Site: [ http://www.copylian.com ]
 * Description [ 测试接口控制器 ]
 */
namespace app\wechat\controller;
use wechat\Wechat;
use wechat\WechatAuth;

class Test extends Base{

    //授权公众号前缀
    //private $prefix_account = 'many_'; //正式机
    private $prefix_account = ''; //测试机

    /**
     * [initialize 初始化]
     */
    public function initialize(){
        parent::initialize();
    }

    /**
     * [auth 测试第三方平台授权]
     */
    public function getauth(){
        if($this->request->isPost()){

            //获取参数
            $params = $this->request->param();

            //验证地址
            if(!isset($params['back_url']) || empty($params['back_url'])){
                $rdata['code'] = 0;
                $rdata['msg'] = lang('l_back_url_error');
                return $rdata;
            }

            //平台ID
            $platform_id = 2; //平台ID
            $state = 'test'; //重定向后会带上 state 参数、平台活动名称
            //$scope = 'snsapi_userinfo'; //授权作用域:snsapi_userinfo、snsapi_base
            $scope = 'snsapi_base'; //授权作用域:snsapi_userinfo、snsapi_base
            $back_url = $params['back_url']; //重定向URL
            $code = isset($params['code']) ? $params['code'] : '';

            //执行第三方的授权
            $Thirdplatform = new \app\wechat\controller\Thirdplatform();
            $data = $Thirdplatform->agent_thirdplatform_auth($platform_id, $state, $back_url, $scope, $code);
            return $data;
        }
    }

    /**
     * [getSign 测试第三方平台获取微信签名包]
     */
    public function getSign() {
        //获取参数
        $params = $this->request->param();

        //跨域
        if(isset($params['url'])){
            $url = $params['url'];
        } else{
            $url = 'https://h5test.ponyfamily.cn/wechat/index.html';
        }

        //设置分享数据缓存
        $cache_name = md5($url);
        $share_data = cache($cache_name);
        if(empty($share_data)){

            //平台ID
            $platform_id = 2; //平台ID
            $code = isset($params['code']) ? $params['code'] : '';

            //执行第三方的授权
            $Thirdplatform = new \app\wechat\controller\Thirdplatform();
            $share_data = $Thirdplatform->getSignPackage($platform_id, $url);

            //设置缓存
            cache($cache_name, $share_data, 7200);
        }

        //微信签名包
        $data['code'] = 1;
        $data['msg'] = lang('l_get_data_success');
        $data['data'] = $share_data;
        return json($data);
    }

    /**
     * [changePay 企业付款到零钱]
     */
    public function changePay() {
        
        //1、获取红包链接
        //实例化
        $WechatMmpaymk = new \wechat\WechatMmpaymk($this->prefix_account);

        //发送数据
        $send_data = [
            'amount'       => 60, //单位分
            'openid'       => 'oHL30wVEuI58Lgp8dkQmSSW4dU4g',
            'order_sn'     => create_order_sn(1, "qylq"),
            'desc'         => '企业付款到零钱',
            'check_name'   => 'NO_CHECK', //NO_CHECK:不校验真实姓名、FORCE_CHECK:强校验真实姓名
            're_user_name' => '', //收款用户真实姓名,如果check_name设置为FORCE_CHECK,则必填用户真实姓名
        ];
        
        //返回结果
        $res = $WechatMmpaymk->sendMoneyToChange($send_data);
        if($res['code'] == 0){
            $rdata['code'] = 0;
            $rdata['msg'] = $res['msg'];
            return json($rdata);
        } else if($res['code'] == 1){
            if($res['data']['return_code'] == 'SUCCESS' && $res['data']['result_code'] == 'SUCCESS'){
                $rdata['code'] = 1;
                $rdata['msg'] = '支付成功';
                $rdata['data'] = $res['data'];
                return json($rdata);
            } else {
                $rdata['code'] = 0;
                $rdata['msg'] = $res['data']['err_code_des'];
                $rdata['data'] = $res['data'];
                return json($rdata);
            }
        }
    }

    /**
     * [queryChangePay 查询企业付款到零钱]
     */
    public function queryChangePay() {
        
        //1、获取红包链接
        //实例化
        $WechatMmpaymk = new \wechat\WechatMmpaymk($this->prefix_account);

        //发送数据
        $send_data = [
            'order_sn'     => 'qylq00807115204001340'
        ];
        
        //返回结果
        $res = $WechatMmpaymk->queryChange($send_data);
        if($res['code'] == 0){
            $rdata['code'] = 0;
            $rdata['msg'] = $res['msg'];
            return json($rdata);
        } else if($res['code'] == 1){
            if($res['data']['return_code'] == 'SUCCESS' && $res['data']['result_code'] == 'SUCCESS'){
                $rdata['code'] = 1;
                $rdata['msg'] = '查询成功';
                $rdata['data'] = $res['data'];
                return json($rdata);
            } else {
                $rdata['code'] = 0;
                $rdata['msg'] = $res['data']['err_code_des'];
                $rdata['data'] = $res['data'];
                return json($rdata);
            }
        }
    }

    /**
     * [redPacketPay 发送红包]
     */
    public function redPacketPay() {
        
        //1、获取红包链接
        //实例化
        $WechatMmpaymk = new \wechat\WechatMmpaymk($this->prefix_account);

        //发送数据
        $send_data = [
            'amount'       => 30, //单位分
            'openid'       => 'oHL30wVEuI58Lgp8dkQmSSW4dU4g',
            'order_sn'     => create_order_sn(1, "qylq")
        ];
        
        //返回结果
        $res = $WechatMmpaymk->redPacketPay($send_data);
        if($res['code'] == 0){
            $rdata['code'] = 0;
            $rdata['msg'] = $res['msg'];
            return json($rdata);
        } else if($res['code'] == 1){
            if($res['data']['return_code'] == 'SUCCESS' && $res['data']['result_code'] == 'SUCCESS'){
                $rdata['code'] = 1;
                $rdata['msg'] = '支付成功';
                $rdata['data'] = $res['data'];
                return json($rdata);
            } else {
                $rdata['code'] = 0;
                $rdata['msg'] = $res['data']['err_code_des'];
                $rdata['data'] = $res['data'];
                return json($rdata);
            }
        }
    }

    /**
     * [queryRedPacket 查询现金红包]
     */
    public function queryRedPacket() {
        
        //1、获取红包链接
        //实例化
        $WechatMmpaymk = new \wechat\WechatMmpaymk($this->prefix_account);

        //发送数据
        $send_data = [
            'order_sn'     => 'qylq00807151840001406'
        ];
        
        //返回结果
        $res = $WechatMmpaymk->queryRedPacket($send_data);
        if($res['code'] == 0){
            $rdata['code'] = 0;
            $rdata['msg'] = $res['msg'];
            return json($rdata);
        } else if($res['code'] == 1){
            if($res['data']['return_code'] == 'SUCCESS' && $res['data']['result_code'] == 'SUCCESS'){
                $rdata['code'] = 1;
                $rdata['msg'] = '查询成功';
                $rdata['data'] = $res['data'];
                return json($rdata);
            } else {
                $rdata['code'] = 0;
                $rdata['msg'] = $res['data']['err_code_des'];
                $rdata['data'] = $res['data'];
                return json($rdata);
            }
        }
    }
}

参考资料PHP实现微信商户支付企业付款到零钱功能代码实例

附件:PHP实现微信支付的现金红包、企业付款到零钱功能.zip

飓风呀
感谢你的支持,我会继续努力!
扫码打赏,感谢您的支持!

文明上网理性发言!

  • 还没有评论,沙发等你来抢