php 商户转账到微信零钱

首先在微信商户开通此功能(开通可能不易)

拿到  商户号   证书 还有证书序列号   关联商户的appid(如果是app在开放平台申请appid小程序的话那就是小程序的appid)   注意一定要关联appid   

在微信商户号里   开通 api 权限 以及添加服务器的ip

     /**生成认证信息
     * @param $url
     * @param $pars
     * @param $http_method
     * @param $cert_path
     * @param $key_path
     * @param $mch_id
     * @return string
     */
    public static function getToken($url, $pars, $http_method, $cert_path, $key_path, $mch_id)
    {
        $timestamp = time();                                  // 请求时间戳
        $url_parts = parse_url($url);                         // 获取请求的绝对URL
        $nonce = $timestamp . rand('10000', '99999');     // 请求随机串
        $body = empty($pars) ? '' : json_encode((object)$pars);              // 请求报文主体
        $stream_opts = [
            "ssl" => [
                "verify_peer" => false,
                "verify_peer_name" => false,
            ]
        ];
 
        $apiclient_cert_arr = openssl_x509_parse(file_get_contents($cert_path, false, stream_context_create($stream_opts)));
        // 证书序列号
        $serial_no = $apiclient_cert_arr['serialNumberHex'];
        // 密钥
        $mch_private_key = file_get_contents($key_path, false, stream_context_create($stream_opts));
        // 商户id:文档顶部定义
        $merchant_id = $mch_id;
        $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);
        // 微信返回token
        return sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $merchant_id, $nonce, $timestamp, $serial_no, $sign);
    }
 
 
     /**
     * @param $url
     * @param $token
     * @param null $serial_no
     * @param null $data
     * @return bool|string
     */
    public static function https_request($url, $token, $serial_no = null, $data = null)
    {
        $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:' . $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($serial_no)) {
            array_push($headers, 'Wechatpay-Serial:' . $serial_no);
        }
 
        if (!empty($headers)) {
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
 
        $output = curl_exec($curl);
        curl_close($curl);
 
        return $output;
    }
 
 
    /**微信敏感信息加密
     * @param $str
     * @param $platform_path //平台证书路径
     * @return string
     * @throws Exception
     */
    private static function getEncrypt($str, $platform_path)
    {
        //$str是待加密字符串
        $public_key = file_get_contents($platform_path);
        $encrypted = '';
        if (openssl_public_encrypt($str, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) {
            //base64编码
            $sign = base64_encode($encrypted);
        } else {
            throw new Exception('encrypt failed');
        }
        return $sign;
    }
 
    /**
     * @param $sOpenid
     * @param $sName
     * @param $sOrderId
     * @param $sDetailOrderId
     * @param $nMoney
     * @param $appid
     * @param $cert_path
     * @param $key_path
     * @param $mch_id
     * @param $serial_no
     * @param $platform_path
     * @return mixed
     * @throws Exception
     */
    public static function transfer_batches($sOpenid, $sName, $sOrderId, $sDetailOrderId, $nMoney, $appid, $cert_path, $key_path, $mch_id, $serial_no, $platform_path)
    {
        // 付款到零钱方法url
        $url = 'https://api.mch.weixin.qq.com/v3/transfer/batches';
 
        // 转账备注 (微信用户会收到该备注)
        $tRemark = '提现到账';
        // 转账金额:微信是分为单位 *100 转换
        $transfer_amount = $nMoney * 100;
 
        // 转账接收列表设置
        $transfer_detail_list = array(
            [
                'out_detail_no' => $sDetailOrderId,                  // 明细单号
                'transfer_amount' => intval($transfer_amount),   // 转账总金额
                'transfer_remark' => $tRemark,                   // 单条转账备注
                'openid' => $sOpenid,                   // 收款方openid
                'user_name' => self::getEncrypt($sName, $platform_path),     // 转账金额 >= 2,000元,收款用户姓名必填
            ],
        );
        // 请求参数设置
        $params = [                                                // 请求参数设置
            'appid' => $appid,                 // 文档顶部定义
            'out_batch_no' => $sOrderId,                   // 商家批次单号
            'batch_name' => '提现到账',                 // 转账的名称
            'batch_remark' => '提现到账',                 // 转账的备注
            'total_amount' => intval($transfer_amount),    // 转账总金额
            'total_num' => 1,                           // 转账总笔数
            'transfer_detail_list' => $transfer_detail_list,       // 转账接收列表
        ];
        // 获取token
        $token = self::getToken($url, $params, 'POST', $cert_path, $key_path, $mch_id);
        // 发送请求
        $res = self::https_request($url, $token, $serial_no, json_encode($params));
        // 反馈数组化
        return json_decode($res, true);
    }
 
    /**获取平台证书列表
     * @param $cert_path//商户证书路径(绝对路径)
     * @param $key_path //商户私钥路径(绝对路径)
     * @param $mch_id   //商户号
     * @param $key      //商户秘钥
     * @return array
     */
    public static function certificates($cert_path, $key_path, $mch_id, $key): array
    {
        $url = 'https://api.mch.weixin.qq.com/v3/certificates';
 
        $token = self::getToken($url, '', 'GET', $cert_path, $key_path, $mch_id);
 
        $res = self::https_request($url, $token);
 
        $certificate = json_decode($res, true);
 
        if (!isset($certificate['data'])) {
            $error_msg = $certificate['message'] ?? '平台证书下载失败!';
            throw new HttpException('500', $error_msg);
        }
 
        $certificate_serial_no = $certificate['data'][0]['serial_no'];//平台证书序列号
        $ciphertext = $certificate['data'][0]['encrypt_certificate']['ciphertext'];
        $associatedData = $certificate['data'][0]['encrypt_certificate']['associated_data'];
        $nonceStr = $certificate['data'][0]['encrypt_certificate']['nonce'];
        $data = self::decryptToString($ciphertext, $associatedData, $nonceStr, $key);
        if (!$data) {
            throw new HttpException(500, '获取证书解密失败');
        }
 
        $dir = ROOT_PATH . '/public/public_cert';
        !is_dir($dir) && @mkdir($dir, 0755, true);
        if (!file_exists($dir . '/wx_public_cert.pem')) {
            //保存平台证书 (https://myssl.com/cert_decode.html)获取证书序列号
            file_put_contents(ROOT_PATH . '/public/public_cert/wx_public_cert.pem', $data);
        }
        return [$certificate_serial_no, $dir . '/wx_public_cert.pem'];
    }
 
    public static function decryptToString($ciphertext, $associatedData, $nonceStr, $apiV3Key)
    {
        $str = base64_decode($ciphertext);
        if (strlen($str) <= 16) {
            return '';
        }
        // ext-sodium (default installed on >= PHP 7.2) 如果没有该函数需要安装sodium扩展
        return sodium_crypto_aead_aes256gcm_decrypt($str, $associatedData, $nonceStr, $apiV3Key);
    }

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值