<?php

//商户付款 到 个人

class mchPay{protected $key = 'c2a7d6411111111f1662e795';  //商户号API KEYprotected $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,一般就可以正常了