微信转账到零钱V2

<?php
// +----------------------------------------------------------------------
// | ITUX.CN [ ITUX.CN软件定制开发 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2014~2023 https://itux.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 此软件并不是自由软件,未经许可不能去掉ITUX相关版权
// +----------------------------------------------------------------------
// | Author: 13103895694 <itholiday@126.com>
// +----------------------------------------------------------------------
//微信企业付款接口sdk
namespace addons\gaga\library\cqrs\libs;

class WxpayTransfer
{
    const API_URL = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';
    private $_appid;
    private $_merchantid;
    private $_key;
    private $apiclient_cert;
    private $apiclient_key;
    private $debug = false;

    public function __construct($config)
    {
        $this->_appid = $config['app_id'];
        $this->_merchantid = $config['mch_id'];
        $this->_key = $config['api_key'];
        $this->apiclient_cert = ROOT_PATH . 'public' . DS . $config['apiclient_cert'];
        $this->apiclient_key = ROOT_PATH . 'public' . DS . $config['apiclient_key'];
    }

    function transfer($data, $check_name = true)
    {
        if ($this->debug) {
            return ['code' => 1, 'msg' => '测试转账'];
        }
        //支付信息
        $webdata = array(
            'mch_appid' => $this->_appid,//商户账号appid
            'mchid' => $this->_merchantid,//商户号
            'nonce_str' => $this->getNonceStr(),//随机字符串
            'partner_trade_no' => $data['order_sn'], //商户订单号,需要唯一
            'openid' => $data['openid'],//转账用户的openid
            'check_name' => 'NO_CHECK', //OPTION_CHECK不强制校验真实姓名, FORCE_CHECK:强制 NO_CHECK:
            'amount' => $data['money'] * 100, //付款金额单位为分
            'desc' => $data['desc'] ?? '业务退款',//企业付款描述信息
            'spbill_create_ip' => get_client_ip(),//获取IP
        );
        foreach ($webdata as $k => $v) {
            $tarr[] = $k . '=' . $v;
        }
        sort($tarr);
        $sign = implode($tarr, '&');
        $sign .= '&key=' . $this->_key;
        $webdata['sign'] = strtoupper(md5($sign));
        $wget = $this->ArrToXml($webdata);//数组转XML
        $res = $this->postData(self::API_URL, $wget);//发送数据
        write_log(['$webdata' => $webdata, '$res' => $res], 'tuikuan');
        if (!$res) {
            $this->log('转账失败:' . json_encode($webdata));
            $this->log('失败原因:不能连接到服务器');
            return array('code' => 0, 'msg' => "不能连接到服务器:" . json_encode($res, JSON_UNESCAPED_UNICODE));
        }
        $content = simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA);
        if (strval($content->return_code) == 'FAIL') {
            $this->log('转账失败:' . json_encode($webdata));
            $this->log('失败原因:' . strval($content->return_msg));
            return array('code' => 0, 'msg' => strval($content->return_msg));
        }
        if (strval($content->result_code) == 'FAIL') {
            $this->log('转账失败:' . json_encode($webdata));
            $this->log('失败原因:' . strval($content->err_code_des));
            return array('code' => 0, 'msg' => strval($content->err_code_des));
        }
        $rdata = array(
            'mch_appid' => strval($content->mch_appid),
            'mchid' => strval($content->mchid),
            'device_info' => strval($content->device_info),
            'nonce_str' => strval($content->nonce_str),
            'result_code' => strval($content->result_code),
            'partner_trade_no' => strval($content->partner_trade_no),
            'payment_no' => strval($content->payment_no),
            'payment_time' => strval($content->payment_time),
        );
        $this->log('转账成功:' . json_encode($webdata));
        $this->log('成功数据:' . json_encode($rdata));
        return array('code' => 1, 'data' => $rdata);
    }

    //数组转XML
    protected function ArrToXml($arr)
    {
        if (!is_array($arr) || count($arr) == 0) return '';
        $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;
    }


    //发送数据
    protected function postData($url, $postfields)
    {
        $ch = curl_init();
        $params[CURLOPT_URL] = $url;    //请求url地址
        $params[CURLOPT_HEADER] = false; //是否返回响应头信息
        $params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
        $params[CURLOPT_FOLLOWLOCATION] = true; //是否重定向
        $params[CURLOPT_POST] = true;
        $params[CURLOPT_POSTFIELDS] = $postfields;
        $params[CURLOPT_SSL_VERIFYPEER] = false;
        $params[CURLOPT_SSL_VERIFYHOST] = false;
        //以下是证书相关代码
        $params[CURLOPT_SSLCERTTYPE] = 'PEM';
        $params[CURLOPT_SSLCERT] = $this->apiclient_cert;//绝对路径
        $params[CURLOPT_SSLKEYTYPE] = 'PEM';
        $params[CURLOPT_SSLKEY] = $this->apiclient_key;//绝对路径
        curl_setopt_array($ch, $params); //传入curl参数
        $content = curl_exec($ch); //执行
        curl_close($ch); //关闭连接
        return $content;
    }

    //随机字符串(不长于32位)
    protected function getNonceStr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    private function log($content)
    {

    }
}

<think>好的,我需要帮助用户了解如何通过微信支付V2版实现商家向用户零钱转账的功能集成。首先,我需要回忆相关的引用内容,特别是引用[2]和引用[3]中提到的信息。引用[2]提到使用V2密钥的企业付款到零钱接口,而引用[3]则提到了平台证书的下载,可能涉及接口调用时的安全验证。 首先,用户需要确认是否具备使用企业付款到零钱接口的资格。根据引用[1]中的文档链接,用户需要检查商户号是否开通了该功能,可能需要登录微信支付商户平台查看权限。接下来,确保API密钥V2已经设置,因为这是V2接口的必要条件,如引用[2]所述,密钥需要在商户平台配置,并且代码中需要使用该密钥进行签名。 然后,准备请求参数。用户的openid是必需的,可以通过微信授权获取。商户订单号需要唯一,避免重复。金额以分为单位,所以需要转换。企业付款的Desc字段描述用途,比如“佣金发放”。IP地址需要填写服务器的IP,这可能容易被忽略,但引用[1]的文档中可能提到这一点。 接下来,生成签名。使用MD5或HMAC-SHA256算法,这里用户使用V2密钥,所以可能是MD5。参数需要按ASCII排序并拼接成字符串,加上key后生成签名。这一步需要特别注意参数顺序和拼接的正确性,否则签名会失败。 构造XML请求数据,将所有参数包括签名放入XML中,发送到微信的API地址。引用[2]和引用[4]提到可能需要处理证书的问题,但V2接口可能不需要平台证书,而V3需要。不过引用[3]提到在查询明细单时需要平台证书,但如果是V2接口,可能不需要,这里需要确认文档。根据引用[2],V2企业付款到零钱可能使用商户证书而不是平台证书,所以可能需要加载商户的证书文件进行双向验证。 处理响应时,解析返回的XML,检查result_code是否为SUCCESS。如果失败,需要根据err_code和err_code_des进行排查。例如,余额不足、用户未实名认证等情况,引用[1]的文档可能有错误代码说明。 安全方面,引用[3]和引用[4]强调证书管理,但V2接口可能主要依赖API密钥和商户证书。需要注意IP白名单和频率限制,防止恶意请求。 最后,用户可能需要参考引用[2]中的ThinkPHP示例,结合自己的后端语言实现。例如,在PHP中使用curl发送请求,加载证书文件,并处理响应。同时,提醒用户注意接口的权限和合规性,确保符合微信支付的使用规范。 在生成相关问题时,需要考虑用户可能遇到的下一步问题,比如如何获取用户openid,如何处理回调通知,或者如何调试签名错误等,这些都可能在实际集成中出现。</think>### 微信支付 V2 商家转账零钱功能集成步骤 #### 1. **确认接口权限与准备条件** - **商户资质要求**:需开通微信支付企业付款到零钱功能(需满足「商户号余额≥最低付款金额」等条件)[^1]。 - **API密钥配置**:登录微信支付商户平台,在「账户中心 > API安全」中设置`API密钥V2`(32位随机字符串),并保存备用[^2]。 #### 2. **接口文档与请求参数** - **V2接口文档地址**:[企业付款到零钱V2文档](https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_1) [^1] - **核心请求参数**: ```xml <xml> <mch_appid>APPID</mch_appid> <mchid>商户号</mchid> <nonce_str>随机字符串</nonce_str> <sign>MD5签名</sign> <partner_trade_no>商户订单号</partner_trade_no> <openid>用户OpenID</openid> <check_name>NO_CHECK</check_name> <!-- 不校验实名 --> <amount>100</amount> <!-- 单位:分 --> <desc>佣金发放</desc> <spbill_create_ip>服务器IP</spbill_create_ip> </xml> ``` #### 3. **签名生成(以MD5为例)** - **步骤**: 1. 按参数名ASCII升序排列(如`amount`, `desc`, `mch_appid`等)。 2. 拼接为`key1=val1&key2=val2`格式,末尾追加`&key=API密钥V2`。 3. 对结果进行`MD5`加密,转为大写。 4. 将签名填入`<sign>`字段。 #### 4. **请求示例(PHP实现)** ```php $url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; $params = [ 'mch_appid' => 'APPID', 'mchid' => '商户号', 'nonce_str' => md5(uniqid()), 'partner_trade_no' => '商户订单号', 'openid' => '用户OpenID', 'check_name' => 'NO_CHECK', 'amount' => 100, 'desc' => '佣金发放', 'spbill_create_ip' => '服务器IP' ]; // 生成签名 ksort($params); $signStr = urldecode(http_build_query($params)) . "&key=API密钥V2"; $params['sign'] = strtoupper(md5($signStr)); // 发送请求(需加载商户证书) $xml = arrayToXml($params); $ch = curl_init(); curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM'); curl_setopt($ch, CURLOPT_SSLCERT, 'apiclient_cert.pem'); curl_setopt($ch, CURLOPT_SSLKEY, 'apiclient_key.pem'); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); $response = curl_exec($ch); curl_close($ch); ``` #### 5. **响应处理与错误排查** - **成功响应**: ```xml <xml> <return_code>SUCCESS</return_code> <result_code>SUCCESS</result_code> <payment_no>微信付款单号</payment_no> </xml> ``` - **常见错误**: - `NO_AUTH`: 未开通企业付款权限 - `AMOUNT_LIMIT`: 付款金额超过限制(单用户单日限额) - `OPENID_ERROR`: 用户OpenID与AppID不匹配 #### 6. **安全与合规** - **证书要求**:需使用商户API证书(`apiclient_cert.pem`和`apiclient_key.pem`)双向验证[^4]。 - **频率限制**:单商户给同一用户付款频率限制为1次/分钟。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玉阳软件yuyangdev_cn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值