• 0
  • 0

微信企业付款到零钱

2019-07-22 1431 0 admin 所属分类:PHP 记录

首先需要登录微信商户中心申请,获取应用ID和支付密钥

开发文档

然后做应用关联绑定 微信应用APPID

代码演示如下

$uid = intval($_GET['uid']);
$member = C::t(PT_USER)->get($uid);
if (!$member) {
    json(['status' => 0, 'msg' => '用户UID不存在,请检查']);
}
$openid = $member['mp_openid'];
$amount = floatval($_GET['amount']);
$desc = data_filter($_GET['remark']);
$realname = data_filter($_GET['realname']);
$device_info = '';
include './class/WXBusiness.class.php';
$WXBusiness = new WXBusiness('你的商户ID', '你的支付密钥', '目标应用ID 如微信公众号');
$result = $WXBusiness->payToUser($openid, $amount, $desc, $realname, $device_info);
if (!$result) {
    json(['status' => 0, 'msg' => $WXBusiness->getMsg()]);
}
$result = array_merge($result, $_POST);
C::t(PT_WXPAY_RECORD)->add($result);
json(['status' => 1, 'msg' => '付款成功']);

商户操作类如下 存放在 class目录下 WXBusiness.class.php

// 引入微信商户操作类
//include DISCUZ_ROOT . './class/WXBusiness.class.php';
// $WXBusiness = new WXBusiness();

class WXBusiness {
    private $appid; //商户APPID
    private $appserect;
    protected $mchid;
    protected $mchkey;
    private $msg;

    protected $errs = array(
        'NO_AUTH' => '没有该接口权限',
        'AMOUNT_LIMIT' => '金额超限',
        'PARAM_ERROR' => '参数错误',
        'OPENID_ERROR' => 'AOpenid错误',
        'SEND_FAILED' => '付款错误,请查单确认付款结果,以查单结果为准',
        'NOTENOUGH' => '余额不足',
        'SYSTEMERROR' => '系统繁忙,请稍后再试。',
        'NAME_MISMATCH' => '姓名校验出错',
        'SIGN_ERROR' => '签名错误',
        'XML_ERROR' => 'Post内容出错',
        'FATAL_ERROR' => '两次请求参数不一致',
        'FREQ_LIMIT' => '超过频率限制,请稍后再试。',
        'MONEY_LIMIT' => '已经达到今日付款总额上限/已达到付款给此用户额度上限',
        'CA_ERROR' => '商户API证书校验出错',
        'V2_ACCOUNT_SIMPLE_BAN' => '无法给非实名用户付款',
        'PARAM_IS_NOT_UTF8' => '请求参数中包含非utf8编码字符',
        'SENDNUM_LIMIT' => '该用户今日付款次数超过限制,如有需要请登录微信支付商户平台更改API安全配置',
        'RECV_ACCOUNT_NOT_ALLOWED' => '收款账户不在收款账户列表',
        'PAY_CHANNEL_NOT_ALLOWED' => '本商户号未配置API发起能力',
    );

    function __construct($mchid, $mchkey, $appid, $appserect) {
        $this->mchid = $mchid;
        $this->mchkey = $mchkey;
        $this->appid = $appid;
        $this->appserect = $appserect;
    }

    public function payToUser($openid, $amount, $desc, $username = '', $device_info = '') {
        $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';

        $str = '<xml>
           <mch_appid>%s</mch_appid>
           <mchid>%s</mchid>
           <device_info>%s</device_info>
           <nonce_str>%s</nonce_str>
           <sign>%s</sign>
           <partner_trade_no>%s</partner_trade_no>
           <openid>%s</openid>
           <check_name>%s</check_name>
           <re_user_name>%s</re_user_name>
           <amount>%s</amount>
           <desc>%s</desc>
           <spbill_create_ip>%s</spbill_create_ip>
        </xml>';
        $params['mch_appid'] = $this->appid;
        $params['mchid'] = $this->mchid;
        $params['device_info'] = $device_info;
        $params['nonce_str'] = random(32);//随机字符串32位
        $params['partner_trade_no'] = md5(microtime(true) + random(15));
        $params['openid'] = $openid;
        //是否强制检测用户真实姓名
        $params['check_name'] = $username ? 'FORCE_CHECK' : 'NO_CHECK';
        $params['re_user_name'] = $username;
        $params['amount'] = $amount * 100; //单位为分
        $params['desc'] = $desc ?: '转账';
        $params['spbill_create_ip'] = $_SERVER['SERVER_ADDR'];

        ksort($params);
        $string = $this->ToUrlParams($params);
        $string .= "&key={$this->mchkey}";
        $sign = strtoupper(md5($string));

        $params['sign'] = $sign;
        $data = sprintf(
            $str,
            $params['mch_appid'],
            $params['mchid'],
            $params['device_info'],
            $params['nonce_str'],
            $params['sign'],
            $params['partner_trade_no'],
            $params['openid'],
            $params['check_name'],
            $params['re_user_name'],
            $params['amount'],
            $params['desc'],
            $params['spbill_create_ip']
        );
        //需要操作证书 往商户平台获取
        $flag = $this->curl_post_ssl($url, $data, $msg,30, PERM_FILE_DIR);
            
        if (!$flag) {
            $this->msg = $msg;
            return false;
        }

        $return = $this->xmltoArray($msg);
        if (!$return) {
            $this->msg = '无法获取退款转账信息';
            return false;
        }

        if ($return['result_code'] != 'SUCCESS') {
            $this->msg = $this->errs[$return['return_msg']]?:$return['return_msg'];
            if ($return['err_code_des']) {
                $this->msg=$this->msg.':'.$return['err_code_des'];
            }
            return false;
        }

        $params = array_merge($params,$return);
        //记录返回的微信付款单号
        // $params['payment_no'] = $return['payment_no'];
        // $params['payment_time'] = $return['payment_time'];

        return $params;

    }

    protected function xmltoArray($result) {
        $return = simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        $return = json_encode($return);
        $return = json_decode($return, true);
        return $return;
    }

    protected function curl_post_ssl($url, $vars, &$msg = '', $second = 30, $fileDir = "C:/cert/", $aHeader = array()) {
        $ch = curl_init();
        //超时时间
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        //这里设置代理,如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '10.206.30.98');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch, CURLOPT_URL, $url);
        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, $fileDir . 'apiclient_cert.pem');
        //默认格式为PEM,可以注释
        curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
        curl_setopt($ch, CURLOPT_SSLKEY, $fileDir . 'apiclient_key.pem');

        //第二种方式,两个文件合成一个.pem文件
        // curl_setopt($ch, CURLOPT_SSLCERT, getcwd() . '/all.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);
            $msg = $data;
            return true;
        } else {
            $error = curl_errno($ch);

            $msg = "call faild, errorCode:$error\n";
            curl_close($ch);
            return false;
        }
    }

    // 获取消息内容
    public function getMsg() {
        return $this->msg;
    }

    /**
     * 格式化参数格式化成url参数
     */
    public function ToUrlParams($data) {
        $buff = "";
        foreach ($data as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

}



返回顶部