业务场景
微信提现使用场景一般为用户客户端发起提现申请,服务端收到请求后调用微信Api发起微信提现。然后通过查询提现结果接口确认一下即可。
接口介绍
https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
特别注意:该接口对微信商户有如下要求:
- 商户号已入驻90日且截止今日回推30天商户号保持连续不间断的交易。
接入流程
第一步
登录微信商户平台,配置一下(配置微信商户流程),获取商户号、支付密钥、证书文件;点击产品中心–我的产品开通企业付款到零钱的功能;
第二步
调用接口发起提现申请,上代码(不喜勿喷):
//接口地址
$url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
//参数
$param = [];
$param['mch_appid'] = '***********'; //申请商户号的appid或商户号绑定的appid
$param['mchid'] = '***********'; //商户id
$param['device_info'] = ""; //设备号,可空值
$param['nonce_str'] = Zmd5(time() . Zrand(5) . 'test'); //随机字符串
$param['partner_trade_no'] = $withdrawInfo['tid']; //内部订单号
$param['openid'] = $userInfo['open_id']; //提现用户的open_id
$param['check_name'] = "NO_CHECK"; //不校验用户姓名
$param['re_user_name'] = '';
$param['amount'] = "" . $withdrawInfo['real_price'] * 100; //提现金额,单位是分故乘100
$param['desc'] = "佣金提现"; //提现描述
$param['spbill_create_ip'] = request()->ip(); //客户端ip或服务端ip均可
//处理签名(签名规则末尾有官方文档链接,此处不介绍)
ksort($param);
$string = ToUrlParams($param);
$string = $string . "&key=" . '********'; //商户支付密钥
$string = md5($string);
$sign = strtoupper($string);
$param['sign'] = $sign;
//参数xml格式化
$param = xml()->Zoutput($param, 'xml');
$rs = self::curl_post_ssl($url, $param);
$PayRs = (array)simplexml_load_string($rs, 'SimpleXMLElement', LIBXML_NOCDATA);
if ($PayRs['return_code'] == "SUCCESS") {
if (!$PayRs['return_msg']) {
#发起提现成功
} else{
#官方给了错误提示
}
} else{
//通讯失败
}
function ToUrlParams($param)
{
$buff = "";
foreach ($param as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
//此函数写在tp框架的Xml.php中
public function Zoutput($data,$root_node="")
{
$root_node=$root_node?$root_node:$this->options['root_node'];
// XML数据转换
return $this->xmlEncode($data,$root_node, $this->options['item_node'], $this->options['root_attr'], $this->options['item_key'], $this->options['encoding']);
}
//配合微信提现接口,发起请求(注意证书文件路径设置)
public static function curl_post_ssl($url, $xmldata, $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, false);
//以下两种方式需选择一种
//第一种方法,cert 与 key 分别属于两个.pem文件
//默认格式为PEM,可以注释
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERT, realpath(ROOT_PATH . "vendor/JsPayWechat/cert/apiclient_cert.pem"));
//默认格式为PEM,可以注释
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, realpath(ROOT_PATH . "vendor/JsPayWechat/cert/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, $xmldata);
$data = curl_exec($ch);
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_error($ch);
echo "call faild, errorCode:$error\n";
curl_close($ch);
return false;
}
}