签名参数:
//按照参数名ASCII字典序排序; 就是按照首字母排序,首字母相同排第二个,以此类推;
$post['appid'] = $appid; //服务商appid
$post['body'] = $body; //商品描述
$post['mch_id'] = $mch_id; //服务商商户号
$post['nonce_str'] = $nonce_str;//随机字符串
$post['notify_url'] = $notify_url; //支付回调地址
$post['out_trade_no'] = $out_trade_no; //商户订单号
$post['profit_sharing'] = $profit_sharing; //统一下单的分账标识, 'Y'代表是
$post['sign_type'] = 'HMAC-SHA256'; //签名类型必须是 'HMAC-SHA256',不支持md5
$post['spbill_create_ip'] = $spbill_create_ip;//终端的ip
$post['sub_appid'] = $sub_appid; //子商户(特约商户)的appid
$post['sub_mch_id'] = $sub_mch_id; //子商户商户号
$post['sub_openid'] = $sub_openid; //支付者在子商户的openid
$post['total_fee'] = $total_fee;//总金额 最低为一分 必须是整数
$post['trade_type'] = $trade_type; //交易类型 默认;'JSAPI'
$sign = $this->sign_hash_hmac($post);//去签名,方法在下面
统一下单接口发送的xml参数:
$post_xml = '
' . $appid . '
' . $body . '
' . $mch_id . '
' . $nonce_str . '
' . $notify_url . '
' . $out_trade_no . '
' . $profit_sharing . '
' . 'HMAC-SHA256' . '
' . $spbill_create_ip . '
' . $sub_appid . '
' . $sub_mch_id . '
' . $sub_openid . '
' . $total_fee . '
' . $trade_type . '
' . $sign . '
';
签名组装函数:
//HMAC-SHA256签名
private function sign_hash_hmac($data){
// ksort($data);
$stringA = '';
foreach ($data as $key=>$value){
if(!$value) continue;
if($stringA) $stringA .= '&'.$key."=".$value;
else $stringA = $key."=".$value;
}
$wx_key = '188fd4aeabc1b1bb812312312312313'; //服务商的密钥
$stringSignTemp = $stringA.'&key='.$wx_key;
$sig = hash_hmac("sha256", $stringSignTemp, $wx_key);
return strtoupper($sig);
}
发送普通post方式curl到统一下单接口
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$xml = $this->curl_post($url, $post_xml);
$array = $this->xml($xml); //解析XML为数组
if ($array['return_code'] == 'SUCCESS' && $array['result_code'] == 'SUCCESS') {
$time = time();
$tmp = [];//临时数组用于签名
$tmp['appId'] = $sub_appid; //子商户appid
$tmp['nonceStr'] = $nonce_str; //统一下单接口使用的字符串
$tmp['package'] = 'prepay_id=' . $array['prepay_id'];
$tmp['signType'] = 'HMAC-SHA256';
$tmp['timeStamp'] = "$time";
$data['timeStamp'] = "$time";//时间戳
$data['nonceStr'] = $nonce_str;//统一下单接口使用的字符串
$data['package'] = 'prepay_id=' . $array['prepay_id'];//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
$data['signType'] = 'HMAC-SHA256';//签名算法,
$data['paySign'] = $this->sign_hash_hmac($tmp);//二次签名
//返回小程序前端所需调取支付的参数
dpReturn([
'status'=>1,
'pay_msg'=>$data
]);
} else {
dpReturn([
'status'=>0,
'pay_msg'=>$array
]);
}
解析XML:
private function xml($xml){
//将XML转为array
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $data;
}
在回调notify()中调起分账:
//分账
private function wxfenzhang($transaction_id,$out_order_no)
{
//$transaction_id和$out_order_no在统一支付回调参数中有
$appid = 'wx123456'; //服务商appid
$mch_id = 14260123456; //服务商商户号
$nonce_str = $this->random_key(32);//随机字符串
$sub_appid = config('hahaha.AppID');//子商户appid
$sub_mch_id = config('hahaha.mch_id'); //子商户号
$receivers = '[
{
"type": "PERSONAL_SUB_OPENID", //类型为子商户openid
"account":"oWJAa40MmpVUBl8U-s88oXGQYMl4", //子商户openid
"amount":1, //金额,整数
"description": "分给个人"
}
]';
$post['appid'] = $appid; //服务商appid
$post['mch_id'] = $mch_id; //服务商商户号
$post['nonce_str'] = $nonce_str;//随机字符串
$post['out_order_no'] = $out_order_no;
$post['receivers'] = $receivers;
$post['sign_type'] = 'HMAC-SHA256';
$post['sub_appid'] = $sub_appid;
$post['sub_mch_id'] = $sub_mch_id;
$post['transaction_id'] = $transaction_id;
$sign = $this->sign_hash_hmac($post);//签名
$post_xml = '
' . $appid . '
' . $mch_id . '
' . $nonce_str . '
' . $out_order_no . '
' . $receivers . '
' . 'HMAC-SHA256' . '
' . $sub_appid . '
' . $sub_mch_id . '
' . $transaction_id . '
' . $sign . '
';
//分账接口
$url = 'https://api.mch.weixin.qq.com/secapi/pay/profitsharing';
$xml = $this->curl_fenzhang($url, $post_xml);
$array = $this->xml($xml);
//返回结果写入文件
$fp = fopen('./fenzhang.txt','a+'); //public/fenzhang.txt
fwrite($fp,var_export($array,true));
fclose($fp);
}
记得添加分账接收方
分账的curl,需要验证支付api安全证书,服务商模式要用服务商的api证书
::api证书只有首次生成时候保存本地
private function curl_fenzhang($url,$data)
{
$sslCertPath = __DIR__.'/test_cert.pem'; //cert证书地址
$sslKeyPath = __DIR__.'/test_key.pem'; //key证书地址
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, $sslCertPath); //cert证书地址
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, $sslKeyPath); //key证书地址
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($ch);
return $result;
}