PHP在微信支付API v3环境下请求接口

PHP在微信支付API v3环境下请求接口

       今天接到一个需求,需要调用微信商家券接口,看了下文档,起初也是有点懵逼,因为代码示例或者SDK都很少,百度上也几乎没有,最终决定自己写。

       大概看了下文档介绍,主要难题还是在签名生成,只要这个解决,其他都不是问题,看了下签名生成的步骤,跟之前自己写的上传图片到腾讯云COS上的过程有点类似,所以也参考了下,并根据文档的介绍,最终成功完成调用,下面贴出详细的代码,封装调用方法:

<?php
/**
 * 微信公共配置方法
 * Created by PhpStorm.
 * User: pc001
 * Date: 2020/5/20
 * Time: 14:20
 */

/*备注:apiclient_cert.p12是商户证书文件,除PHP外的开发均使用此证书文件*/


#微信基础信息
$wxMerchantId = "商户号";                                               //商户号
$wxMerchantApiCertificate = __DIR__ . "/cert/apiclient_cert.pem";       //商户证书
$wxMerchantApiPrivateKey = __DIR__ . "/cert/apiclient_key.pem";         //商户私钥
$wxApiV3Key = "微信API v3密钥";                                         //微信API v3密钥
$wxApiSerialNo = "商户API证书序列号";                                   //商户API证书序列号

#############微信构造签名流程#############

/**
 * 生成签名
 * @param string $method 请求方法 POST 或者GET
 * @param string $url 请求URL
 * @param string $request 请求中的请求报文主体
 * @param $wxMerchantId商户号
 * @param $certKey商户私钥
 * @param $wxApiSerialNo商户API证书序列号
 * @return string
 */
function RequestSign($method = "POST", $url = "", $request = "", $wxMerchantId, $certKey, $wxApiSerialNo)
{
    #截取获取当前请求地址【去除域名】
    $url_parts = parse_url($url);
    $path = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
    #获取当前时间戳
    $timeStamp = time();
    #生成一个随机字符串
    $nonceStr = getNonceStr();
    #构造签名串
    $requestSign = sprintf("%s\n%s\n%s\n%s\n%s\n", $method, $path, $timeStamp, $nonceStr, $request);
    #计算计算签名值
    $sign = calculateSignatureValue($requestSign, $certKey);
    #设置HTTP头获取Authorization
    $token = createToken($wxMerchantId, $nonceStr, $timeStamp, $wxApiSerialNo, $sign);
    #返回
    return $token;
}

/**
 * 计算签名值
 * @param $requestSign
 * @param $certKey
 * @return string
 * 使用商户私钥对待签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码得到签名值
 */
function calculateSignatureValue($requestSign, $certKey)
{
    $certKey = file_get_contents($certKey);
    openssl_sign($requestSign, $raw_sign, $certKey, 'sha256WithRSAEncryption');
    $sign = base64_encode($raw_sign);
    return $sign;
}

/**
 * 获取token
 * @param $merchant_id
 * @param $nonce
 * @param $timestamp
 * @param $serial_no
 * @param $sign
 * @return string
 */
function createToken($merchant_id, $nonce, $timestamp, $serial_no, $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);
    return $token;
}

/**
 * 产生随机字符串,不长于32位
 * @param int $length
 * @return string
 */
function getNonceStr($length = 32)
{
    $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    $str = "";
    for ($i = 0; $i < $length; $i++) {
        $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
    }
    return $str;
}


/**
 * post请求
 * @param $url
 * @param $authorization
 * @return mixed
 */
function curlPostWithWx($url, $authorization)
{
    $paramsString = json_encode($params);
    // 初始化curl
    $ch = curl_init();
    // 设置超时
    curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    // post数据
    curl_setopt($ch, CURLOPT_POST, 1);
    // post的变量
    curl_setopt($ch, CURLOPT_POSTFIELDS, $paramsString);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json; charset=utf-8',
            'Content-Length: ' . strlen($paramsString),
            'Authorization: ' . "WECHATPAY2-SHA256-RSA2048 " . $authorization,
            'Accept: application/json',
            'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
        )
    );
    // 运行curl,结果以jason形式返回
    $res = curl_exec($ch);
    curl_close($ch);
    // 取出数据
    $data = json_decode($res, true);
    return $data;
}

/**
 * get请求
 * @param $url
 * @param $authorization
 * @return mixed
 */
function curlGetWithWx($url, $authorization)
{
    // 初始化curl
    $ch = curl_init();
    // 设置超时
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json; charset=utf-8',
            'Content-Length: ' . strlen($paramsString),
            'Authorization: ' . "WECHATPAY2-SHA256-RSA2048 " . $authorization,
            'Accept: application/json',
            'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
        )
    );
    // 运行curl,结果以jason形式返回
    $res = curl_exec($ch);
    curl_close($ch);
    // 取出数据
    $data = json_decode($res, true);
    //返回
    return $data;
}

       下面我们调用的demo:

#引入文件
require __DIR__ . "/wxComm.php";

#请求接口地址
$url = "https://api.mch.weixin.qq.com/v3/certificates";
#组合基本信息
$params = array();
$request = json_encode($params);
#获取authorization
$authorization = RequestSign("GET", $url, "", $wxMerchantId, $wxMerchantApiPrivateKey, $wxApiSerialNo);
#请求接口
$data = curlGetWithWx($url, $authorization);
#输出
echo json_encode($data);

       这样我们就成功的在微信支付API v3环境下请求接口,这里是在GET情况下调用接口,其实POST情况下也差不多,只是调用http请求时换了另一个方法,实现过程其实不难,主要是参考的东西太少。

       这里要注意一点,这里的证书是指API证书,要在后台申请,而不是以前的证书,具体申请可以查看官方文档。

0条评论

发表评论