微信企业付款到用户微信零钱功能(yii2)

微信官方文档

微信企业付款到零钱:官方文档链接地址

前期准备

  1. 准备一个商户号,商户号已入驻90日且截止今日回推30天商户号保持连续不间断的交易。商户号还需要开通付款到零钱功能。
  2. 准备商户号的appid。
  3. 准备商户号的支付证书,商户证书的获取方法可以看官方文档。
  4. 用户提现前需要确保用户登录,获取用户的openid。用户登录所用的公众号或者小程序的appid需要绑定到商户号下。

实际应用示例

  1. 提现接口
	//支付到用户零钱
    public function transfers()
    {
        //调用付款到零钱接口的参数
        $data = [
            'mch_appid' =>'XXXXXXXXXX',           //商户账号appid
            'mchid' => 'XXXXXXXXXX',           //商户号
            'nonce_str' => 'XXXXXXXXXX',      //随机字符串,小于32
            'partner_trade_no' => 'no123456789',    //商户订单号
            'openid' => 'XXXXXXXXX',              //用户openid
            'check_name' => 'NO_CHECK', //NO_CHECK:不校验真实姓名 FORCE_CHECK:强校验真实姓名
            'amount' => 1 * 100,     //付款金额,单位分,测试提现1元
            'desc' => '这是付款的备注',         //付款备注
        ];
        //微信接口地址
        $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';
        //获取签名
        $data['sign'] = $this->makeSign($data,'md5');
        //发送数据转为xml格式
        $xml = $this->arrayToXml($data);
        //发送参数到微信接口
        $res = self::curl_post_ssl($url,$xml);
        $result = $this->xmlToArray($res);
        //判断支付结果
        if ($result['result_code'] == 'SUCCESS'){  //支付成功
            return $result;
        }else{  //支付失败,返回错误代码和错误描述
            $result = [
                'err_code' => $result['err_code'],
                'err_code_des' => $result['err_code_des'],
            ];
            $this->setErrmsg($result);
            return false;
        }
    }
  1. 提现接口中的签名算法
	protected function makeSign($data, $signType = 'HMAC-SHA256')
    {
        //签名步骤一:按字典序排序参数
        ksort($data);
        $string = self::toUrlParams($data);
        //签名步骤二:在string后加入KEY
        $string = $string . "&key=" . self::$key;
        //签名步骤三:MD5加密或者HMAC-SHA256
        if ($signType == 'md5') {
            //如果签名小于等于32个,则使用md5验证
            $string = md5($string);
        } else {
            //是用sha256校验
            $string = hash_hmac("sha256", $string, self::$key);
        }
        //签名步骤四:所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }
  1. 提现接口中的数组转XML格式
	public 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;
    }
  1. 提现接口中的使用curl的方式发送数据到微信接口
	public static function curl_post_ssl($url, $vars, $second = 30, $aHeader = array())
    {
        $isdir = $path = Yii::$app->basePath;//证书位置;
        $ch = curl_init();//初始化curl

        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 .'/certificate/apiclient_cert.pem');//证书位置
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');//CURLOPT_SSLKEY中规定的私钥的加密类型
        curl_setopt($ch, CURLOPT_SSLKEY, $isdir . '/certificate/apiclient_key.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;
        }
    }
  1. 提现接口中的XML格式转数组
	public function xmlToArray($xml) {
        $arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $arr;
    }

可能需要注意的点

  1. 确保商户号,商户号appid,支付证书等信息的正确。尤其确保支付证书的路径没错误,使用证书的绝对路径。
  2. 确保使用的小程序之类的appid绑定到商户号中。
  3. 订单编号需要始终保证是唯一的,用户的提现记录包含订单编号最好保存在数据库中,出现问题时,可以使用订单编号对这个提现进行查询。
  4. 用户的提现金额需要换算成分,传入微信的接口的金额单位为分。

可能遇到的问题及解决办法

1.使用沙箱环境的时候。在使用curl发送数据到微信接口时,需要加上一下代码。否则会一直提示"请确认请求参数是否正确 param mch_id invalid"。非沙箱环境不需要。

	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/xml'));

后续补充

1、查询支付信息接口

直接代码展示

	public function getTransferInfo($order_no)
    {
        //调用查询接口需要的参数
        $data = [
            'nonce_str' => 'XXXXXXX',      //随机字符串
            'partner_trade_no' => $order_no,       //商户订单号
            'mch_id' => 'XXXXX',      //商户号
            'appid' => 'XXXXX',       //商户号的appid
        ];
        $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo';
        //获取签名
        $data['sign'] = $this->makeSign($data,'md5');
        //发送数据转为xml格式
        $xml = $this->arrayToXml($data);
        //发送参数到微信接口
        $res = self::curl_post_ssl($url,$xml);
        $result = $this->xmlToArray($res);
        if ($result['result_code'] == 'SUCCESS'){ //查询成功
            if ($result['status'] == 'FAILED'){ //转账失败
                $this->setErrmsg($result['reason']); //失败原因
                return false;
            }else{
                return $result;
            }
        }else{
            $this->setErrmsg($result['err_code_des']);
            return false;
        }
    }

2、获取沙箱环境商户密钥接口

直接代码展示

	public function getSignKey()
    {
        $url = 'https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey';
        $data = [
            'mch_id' => self::$mch_id,
            'nonce_str' => time(),
        ];
        $sign = $this->makeSign($data,'md5');
        $data['sign'] = $sign;
        //发送数据转为xml格式
        $xml = $this->arrayToXml($data);
        //发送参数到微信接口
        $res = self::post_remote_result($url,$xml);
        $result = $this->xmlToArray($res);
        if ($result['return_code'] == 'SUCCESS'){
            return $result['sandbox_signkey']; //沙箱密钥
        }else{
            $this->setErrmsg($result['return_msg']);
            return false;
        }
    }

通过curl的方式发送数据到微信接口,代码如下

	public static function post_remote_result($url, $data, $second = 20, $setoptArr=array(), $http_code = 200)
    {
        $ch = curl_init();
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch,CURLOPT_HEADER,0);
        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/xml'));
        if (preg_match("/^(http:\/\/|https:\/\/).*$/", $url)) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }

        foreach($setoptArr as $key=>$value){
            curl_setopt($ch,constant($key),$value);
        }
        $content = curl_exec($ch);
        $httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE);

        if($httpCode == $http_code) {
            //成功
        } else {
            //失败
            $content = json_encode(array('httpErr'=>1,'httpCode'=>$httpCode));
        }

        curl_close($ch);
        return $content;
    }

注意: 下面的代码必须加到curl方法中,不然会提示"请确认请求参数是否正确 param mch_id invalid"。

	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/xml'));
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值