这里有个坑
1:转账低于5毛会失败
2:转账金额需要自己取整一下,微信官方金额是 分 为单位,换算成 元 时可能会除不尽
{ "code":"PARAM_ERROR", "detail":{ "location":"body", "value":7.000000000000001 // 微信金额除不尽出现的问题 }, "message":" 无法将 JSON 输入源“\/body\/ total_amount”映射到目标字段“转账总金额”中, 此字段需要一个合法的 64 位有符号整数" }
1.服务层
const SSLCERT_PATH = '证书路径'; const SSLKEY_PATH = '证书key路径'; const MCHID = '商户号'; const APPID = 'app_id'; const KEY = 'key值'; /** * 付款到微信零钱 * sOpenid:收款方openid * nMoney:转账金额 */ public function transfer_batches($sOpenid, $nMoney) { // 付款到零钱方法url $url = 'https://api.mch.weixin.qq.com/v3/transfer/batches'; // 订单号 $sOrderId = '测试付款' . time(); // 转账备注 (微信用户会收到该备注) $tRemark = '测试付款' . $sOrderId; // 转账金额:微信是分为单位 *100 转换 $transfer_amount = $nMoney * 100; // 转账接收列表设置 $transfer_detail_list = array( [ 'out_detail_no' => $sOrderId, // 明细单号 'transfer_amount' => intval($transfer_amount), // 转账总金额 'transfer_remark' => $tRemark, // 单条转账备注 'openid' => $sOpenid, // 收款方openid // 'user_name' => '张三', // 转账金额 >= 2,000元,收款用户姓名必填 ], ); // 请求参数设置 $params = [ // 请求参数设置 'appid' => self::APPID, // 文档顶部定义 'out_batch_no' => $sOrderId, // 商家批次单号 'batch_name' => 'x年x月转账', // 转账的名称 'batch_remark' => 'x年x月转账', // 转账的备注 'total_amount' => intval($transfer_amount), // 转账总金额 'total_num' => 1, // 转账总笔数 'transfer_detail_list' => $transfer_detail_list, // 转账接收列表 ]; // 获取token $token = $this->getToken($params); // 发送请求 $res = $this->https_request($url, json_encode($params), $token); // 反馈数组化 $resArr = json_decode($res, true); dump($resArr); // 存储转账成功信息或别的操作 // 成功实例返回值 { "out_batch_no": "plfk2020042013", // wx唯一识别号 "batch_id": "1030000071100999991182020050700019480001", // 商家批次单号 "create_time": "2015-05-20T13:29:35.120+08:00" // 创建时间 } } /** * 构造请求 */ 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; } /** * 获取token */ public function getToken($pars) { $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, ] ]; // 证书路径信息:文档顶部定义 $apiclient_cert_path = self::SSLCERT_PATH; $apiclient_key_path = self::SSLKEY_PATH; $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)); // 商户id:文档顶部定义 $merchant_id = self::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 return $token; }
2.控制层
public function onTransferBatches($openid, $nMoney) { // 实例化服务层 $serviceTransfer = new serviceTransfer(); // 带参请求:sOpenid(收款方openid) nMoney(转账金额) $result = $serviceTransfer->transfer_batches($openid, $nMoney); return $result; }