<?php
namespace app\common\service;
use app\common\exception\BaseException;
class WechatPayTransfer
{
protected $wxapp = [];
public function __construct($wxapp)
{
$this->wxapp = $wxapp;
}
/**
* 商家转账到零钱(公众号:程序员在囧途)
* @param $batch_name
* @param $out_trade_no
* @param $money
* @param $openid
* @throws BaseException
*/
public function transfer($batch_name, $out_trade_no, $money, $openid)
{
$url = 'https://api.mch.weixin.qq.com/v3/transfer/batches';
$pars = [];
$pars['appid'] = $this->wxapp['app_id'];//直连商户的appid
$pars['out_batch_no'] = 'batch' . $out_trade_no;//商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
$pars['batch_name'] = $batch_name;//该笔批量转账的名称
$pars['batch_remark'] = $batch_name;//转账说明,UTF8编码,最多允许32个字符
$pars['total_amount'] = intval($money * 100);//转账总金额 单位为“分”
$pars['total_num'] = 1;//转账总笔数
$pars['transfer_detail_list'][0] = [
'out_detail_no' => 'transfer' . $out_trade_no,
'transfer_amount' => $pars['total_amount'],
'transfer_remark' => $batch_name,
'openid' => $openid
];//转账明细列表
$token = $this->getToken($pars);//获取token
$res = $this->https_request($url, json_encode($pars), $token);//发送请求
$data = json_decode($res, true);
if(isset($data['batch_id']) && $data['batch_id']){
return $data;
}
return [];
}
function https_request($url, $data = null, $token)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, (string)$url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//添加请求头
$headers = [
'Authorization:WECHATPAY2-SHA256-RSA2048 ' . $token,
'Accept: application/json',
'Content-Type: application/json; charset=utf-8',
'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
];
if (!empty($headers)) {
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
public function getToken($pars)
{
// $url = 'https://api.mch.weixin.qq.com/v3/certificates';
$url = 'https://api.mch.weixin.qq.com/v3/transfer/batches';
$http_method = 'POST';//请求方法(GET,POST,PUT)
$timestamp = time();//请求时间戳
$url_parts = parse_url($url);//获取请求的绝对URL
$nonce = $timestamp . rand('10000', '99999');//请求随机串
$body = json_encode((object)$pars);//请求报文主体
$stream_opts = [
"ssl" => [
"verify_peer" => false,
"verify_peer_name" => false,
]
];
try {
$certPem = $this->getCertPem();
$apiclient_cert_path = $certPem['certPem'];
$apiclient_key_path = $certPem['keyPem'];
$apiclient_cert_arr = openssl_x509_parse(file_get_contents($apiclient_cert_path, false, stream_context_create($stream_opts)));
$serial_no = $apiclient_cert_arr['serialNumberHex'];//证书序列号
$mch_private_key = file_get_contents($apiclient_key_path, false, stream_context_create($stream_opts));//密钥
$merchant_id = $this->wxapp['mchid'];
$canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
$message = $http_method . "\n" .
$canonical_url . "\n" .
$timestamp . "\n" .
$nonce . "\n" .
$body . "\n";
openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
$sign = base64_encode($raw_sign);//签名
$schema = 'WECHATPAY2-SHA256-RSA2048';
$token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
$merchant_id, $nonce, $timestamp, $serial_no, $sign);//微信返回token
} catch (\Exception $e) {
throw new BaseException(['msg' => $e->getMessage()]);
}
return $token;
}
/**
* 获取cert证书文件
* @return array
* @throws BaseException
*/
private function getCertPem()
{
if (empty($this->wxapp['cert_pem']) || empty($this->wxapp['key_pem'])) {
throw new BaseException(['msg' => '请先到后台小程序设置填写微信支付证书文件']);
}
// cert目录
$filePath = dirname(__DIR__) . '/library/wechat/cert/' . $this->wxapp['wxapp_id'] . '/';
return [
'certPem' => $filePath . 'cert.pem',
'keyPem' => $filePath . 'key.pem'
];
}
}
The latest PHP docks WeChat payment, initiates merchant transfer API, and merchants transfer money to change
The above class files can be used directly, and can be modified according to your own needs. Below is the official interface document of WeChat payment