微信企业支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。
比如目前的保险行业向客户退保、给付、理赔。
企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”进行操作。
下面是微信企业付款接口THINKPHP控制器,
C(\'WX_APPID\'),C(\'WX_MCHID\'),C(\'WX_KEYC\') 这三项我已事先写在配置文件中了
<?php
/**
* 微信企业付款接口
*/
namespace Admin\Controller;
use Think\Controller;
class CompayController extends Controller {
protected $payurl = \'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers\';
//这里的路径很重要 一定要写相对路径
protected $cacab = array(
\'api_cert\'=>\'weixin/cert/apiclient_cert.pem\',
\'api_key\'=>\'weixin/cert/apiclient_key.pem\',
\'api_ca\'=>\'weixin/cert/rootca.pem\',
);
//$data 要传递的参数, $wxchat微信企业支付等信息
/** $data 格式如下
* $data = array(
\'userid\' //申请退款者ID
\'openid\' //退款者openid
\'refundid\' //退款申请ID
\'money\' //退款金额
\'desc\' //退款描述
);
*
*/
public function wxbuild($data, $wxchat){
//判断有没有CA证书及支付信息
if(empty($wxchat[\'api_cert\']) || empty($wxchat[\'api_key\']) || empty($wxchat[\'api_ca\']) || empty($wxchat[\'appid\']) || empty($wxchat[\'mchid\'])){
$wxchat[\'appid\'] = C(\'WX_APPID\'); //appid
$wxchat[\'mchid\'] = C(\'WX_MCHID\'); //商户号
$wxchat[\'api_cert\'] = $this->cacab[\'api_cert\'];
$wxchat[\'api_key\'] = $this->cacab[\'api_key\'];
$wxchat[\'api_ca\'] = $this->cacab[\'api_ca\'];
}
$webdata = array(
\'mch_appid\' => $wxchat[\'appid\'],
\'mchid\' => $wxchat[\'mchid\'],
\'nonce_str\' => md5(time()),
//\'device_info\' => \'1000\',
\'partner_trade_no\' => $data[\'bpno\'], //商户订单号,需要唯一
\'openid\' => $data[\'openid\'],
\'check_name\'=> \'NO_CHECK\', //OPTION_CHECK不强制校验真实姓名, FORCE_CHECK:强制 NO_CHECK:
//\'re_user_name\' => \'jorsh\', //收款人用户姓名
\'amount\' => $data[\'money\'] * 100, //付款金额单位为分
\'desc\' => empty($data[\'desc\'])? \'微信提现\' : $data[\'desc\'],
\'spbill_create_ip\' => $this->getip(),
);
$sig = $this->makeSign($webdata);
foreach ($webdata as $k => $v) {
$tarr[] =$k.\'=\'.$v;
}
sort($tarr);
$sign = implode($tarr, \'&\');
$sign .= \'&key=\'.C(\'WX_KEYC\'); //支付密钥
//$webdata[\'sign\']=strtoupper(md5($sign));
$webdata[\'sign\']= $sig;
$wget = $this->array2xml($webdata);
$content = $this->curl_post_ssl($this->payurl, $wget, $wxchat);
if(!$content){
return array(\'status\'=>1, \'msg\'=>"Can\'t connect the server" );
}
return $this->xmlToArray($content);
}
public function getip() {
static $ip = \'\';
$ip = $_SERVER[\'REMOTE_ADDR\'];
if(isset($_SERVER[\'HTTP_CDN_SRC_IP\'])) {
$ip = $_SERVER[\'HTTP_CDN_SRC_IP\'];
} elseif (isset($_SERVER[\'HTTP_CLIENT_IP\']) && preg_match(\'/^([0-9]{1,3}\.){3}[0-9]{1,3}$/\', $_SERVER[\'HTTP_CLIENT_IP\'])) {
$ip = $_SERVER[\'HTTP_CLIENT_IP\'];
} elseif(isset($_SERVER[\'HTTP_X_FORWARDED_FOR\']) AND preg_match_all(\'#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s\', $_SERVER[\'HTTP_X_FORWARDED_FOR\'], $matches)) {
foreach ($matches[0] AS $xip) {
if (!preg_match(\'#^(10|172\.16|192\.168)\.#\', $xip)) {
$ip = $xip;
break;
}
}
}
return $ip;
}
/**
* 将一个数组转换为 XML 结构的字符串
* @param array $arr 要转换的数组
* @param int $level 节点层级, 1 为 Root.
* @return string XML 结构的字符串
*/
public function array2xml($arr, $level = 1) {
$s = $level == 1 ? "<xml>" : \'\';
foreach($arr as $tagname => $value) {
if (is_numeric($tagname)) {
$tagname = $value[\'TagName\'];
unset($value[\'TagName\']);
}
if(!is_array($value)) {
$s .= "<{$tagname}>".(!is_numeric($value) ? \'<![CDATA[\' : \'\').$value.(!is_numeric($value) ? \']]>\' : \'\')."</{$tagname}>";
} else {
$s .= "<{$tagname}>" . $this->array2xml($value, $level + 1)."</{$tagname}>";
}
}
$s = preg_replace("/([\x01-\x08\x0b-\x0c\x0e-\x1f])+/", \' \', $s);
return $level == 1 ? $s."</xml>" : $s;
}
/**
* 微信支付发起请求
*/
protected function curl_post_ssl($url, $xmldata,$wxchat, $second=30,$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,0);
curl_setopt($ch, CURLOPT_SSLVERSION, 1);
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLCERTTYPE,\'PEM\');
curl_setopt($ch,CURLOPT_SSLCERT,$wxchat[\'api_cert\']);
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLKEYTYPE,\'PEM\');
curl_setopt($ch,CURLOPT_SSLKEY,$wxchat[\'api_key\']);
//curl_setopt($ch,CURLOPT_CAINFO,$config[\'rootca\']);
if( count($aHeader) >= 1 ){
curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
}
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS,$xmldata);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(\'Expect:\'));
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
$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;
}
}
//将XML转为array
public function xmlToArray($xml)
{
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$values = json_decode(json_encode(simplexml_load_string($xml, \'SimpleXMLElement\', LIBXML_NOCDATA)), true);
return $values;
}
/**
* 生成签名
* @return 签名,本函数不覆盖sign成员变量
*/
public function makeSign($data){
//获取微信支付秘钥
vendor(\'WxPayPubHelper.WxPayJsApiPay\');
$key = \WxPayConfig::KEY;
// 去空
$data=array_filter($data);
//签名步骤一:按字典序排序参数
ksort($data);
$string_a=http_build_query($data);
$string_a=urldecode($string_a);
//签名步骤二:在string后加入KEY
//$config=$this->config;
$string_sign_temp=$string_a."&key=".$key;
//签名步骤三:MD5加密
$sign = md5($string_sign_temp);
// 签名步骤四:所有字符转为大写
$result=strtoupper($sign);
return $result;
}
//企业付款测试
public function test(){
$bpid = session(\'dpid\');
//通过bpid查询提现信息
$balance = M(\'balance\')->where(\'bpid =\'.$bpid)->find();
//通过用户ID获取OPENID
$openid = M(\'userinfo\')->where(\'uid =\'.$balance[\'uid\'])->getField(\'openid\');
$username = M(\'userinfo\')->where(\'uid =\'.$balance[\'uid\'])->getField(\'username\');
$data = array(
\'userid\' => $balance[\'uid\'], //用户ID 做更新状态使用
\'openid\' => $openid, //收钱的人微信 OPENID
\'refundid\' => $balance[\'bpid\'], //提现申请IDbpno
\'bpno\' => $balance[\'bpno\'], //提现申请ID
\'money\' => $balance[\'dzprice\'], //金额
\'desc\' => \'微信提现\',
);
//var_dump($data);die;
$res = $this->wxbuild($data);
if ($res[\'result_code\'] == "SUCCESS") {
//微信提现成功
$time = date("Y-m-d H:i:s");
$cltime = time();
M(\'balance\')->where(\'bpid=\'.$bpid)->setField(array(\'isverified\'=>\'1\',\'remarks\'=>$time." 微信提现成功!",\'cltime\'=>$cltime));//1是同意
session(\'bpid\',NULL);
$this->ajaxReturn("success");
}else{
$this->ajaxReturn("error");
}
}
}