2

<?php

//商户付款 到 个人

class mchPay
{


protected $key = 'c2a7d6411111111f1662e795';  //商户号API KEY
protected $appId = 'wxbb111111f5e5f04';
protected $mchid = '141111582';
protected $CertPem = BASE_ROOT_PATH.'/data/cert/apiclient_cert.pem';   //证书的位置  绝对路径
protected $KeyPem = BASE_ROOT_PATH.'/data/cert/apiclient_key.pem';     //证书的位置  绝对路径


/*
    商户付款到 用户零钱 
    out_trade_no 外单订单号 
    openid  用户openid
    total_fee  操作的金额

*/
public function payToChange($data)
{
    $params = array();
    $params['mch_appid'] = $this->appId;
    $params['mchid'] = $this->mchid;
    $params['nonce_str'] = $this->createNoncestr();
    $params['partner_trade_no'] = $data['out_trade_no'];
    $params['openid'] = $data['openid'];
    $params['check_name'] = 'NO_CHECK';            
    $params['amount'] = $data['total_fee'];
    $params['desc'] = '提现';            
    $params['spbill_create_ip'] = $_SERVER["REMOTE_ADDR"];    
    $params['sign'] = $this->getSign($params);

    $postXml = $this->arrayToXml($params);

    $resXml  = $this->postXmlCurl('https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers',$postXml,30,true); 
    $resData = $this->xmlToArray($resXml);
    if(!$resData || $resData['return_code']!='SUCCESS' || $resData['result_code']!='SUCCESS') return false;

    // var_dump($resData); 
    return $resData;

}


/*
    商户付款到 用户银行卡
    out_trade_no 外单订单号 
    total_fee  操作的金额
    enc_bank_no  收款用户的银行卡号
    enc_true_name 收款用户的姓名
    bank_code  收款银行对应的编号 微信文档获取
*/
public function payToBank($data)
{
    $params = array();
    $params['mch_id'] = $this->mchid;
    $params['nonce_str'] = $this->createNoncestr();
    $params['partner_trade_no'] = $data['out_trade_no'];
    $params['enc_bank_no'] = $data['enc_bank_no'];
    $params['enc_true_name'] = $data['enc_true_name'];        
    $params['amount'] = $data['total_fee'];
    $params['bank_code'] = $data['bank_code'];    
    $params['sign'] = $this->getSign($params);

    $postXml = $this->arrayToXml($params);

    $resXml  = $this->postXmlCurl('https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank',$postXml,30); 
    $resData = $this->xmlToArray($resXml);
    if(!$resData || $resData['return_code']!='SUCCESS' || $resData['result_code']!='SUCCESS') return false;
    return $resData; 

}


//作用:生成签名
private function getSign($Obj) 
{
    $Parameters = array();
    foreach ($Obj as $k => $v) {
        $Parameters[$k] = $v;
    }
    //签名步骤一:按字典序排序参数
    ksort($Parameters);
    $String = $this->formatBizQueryParaMap($Parameters, false);
    //签名步骤二:在string后加入KEY
    $String = $String . "&key=" . $this->key;
    //签名步骤三:MD5加密
    $String = md5($String);
    //签名步骤四:所有字符转为大写
    $result_ = strtoupper($String);
    return $result_;
}

///作用:格式化参数,签名过程需要使用
private function formatBizQueryParaMap($paraMap, $urlencode)
{
    $buff = "";
    ksort($paraMap);
    foreach ($paraMap as $k => $v) {
        if ($urlencode) {
            $v = urlencode($v);
        }
        $buff .= $k . "=" . $v . "&";
    }
    if (strlen($buff) > 0) {
        $reqPar = substr($buff, 0, strlen($buff) - 1);
    }
    return $reqPar;
}  

//将数组转换为xml格式 
private 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;
}      

//xml转换成数组
private 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;
}    


//作用:产生随机字符串,不长于32位
private function createNoncestr($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 postXmlCurl($url,$xml, $second = 30) 
{
    $ch = curl_init();
    //设置超时
    curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验
    //设置header
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    //要求结果为字符串且输出到屏幕上
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

    //设置证书
    //使用证书:cert 与 key 分别属于两个.pem文件
    //默认格式为PEM,可以注释
    curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
    curl_setopt($ch,CURLOPT_SSLCERT, $this->CertPem); 
    //默认格式为PEM,可以注释
    curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
    curl_setopt($ch,CURLOPT_SSLKEY, $this->KeyPem);                     

    //post提交方式
    curl_setopt($ch, CURLOPT_POST, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);

    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
    curl_setopt($ch, CURLOPT_TIMEOUT, 40);
    set_time_limit(0);


    //运行curl
    $data = curl_exec($ch);
    //返回结果
    if ($data) {
        curl_close($ch);
        return $data;
    } else {
        $error = curl_errno($ch);
        var_dump($error);
        curl_close($ch);
        return false;
    }
}

}

//支付到用户零钱
$obj = new mchPay();
$params = array(
    'out_trade_no' => date('YmdHis'),
    'openid'       => 'ouD2222222228',
    'total_fee'    => 100, 
);
$res = $obj->payToChange($params);     

?>

商户付款给用户是需要用到证书的,证书的申请在商户后台。一步步申请即可。还有就是如果一直报签名错误, 可以先到签名工具里对签名进行验证。 如果在签名工具里校验签名是正确的,那很有可能是api key的问题,重新在商户后台 ,设置一下api key,一般就可以正常了


在路上f_x
66 声望7 粉丝

a phper