公钥证书方式下如何使用HTTP方式调用支付宝接口

公钥证书方式下如何使用HTTP方式调用支付宝接口

       最近因为业务需求,公司调用支付宝接口采用公钥证书方式,由于之前使用的是普通公钥方式,所以我也抽空研究了两者不同,最终在公钥证书方式下采用HTTP方式调用接口,成功请求支付宝接口,下面跟大家分享代码,首先是公钥证书方式下转化SN码代码:

/**
 * 从证书中提取公钥
 * @param $cert
 * @return mixed
 */
function getPublicKey($certPath)
{
    $cert = file_get_contents($certPath);
    $pkey = openssl_pkey_get_public($cert);
    $keyData = openssl_pkey_get_details($pkey);
    $public_key = str_replace('-----BEGIN PUBLIC KEY-----', '', $keyData['key']);
    $public_key = trim(str_replace('-----END PUBLIC KEY-----', '', $public_key));
    return $public_key;
}

/**
 * 从证书中提取序列号
 * @param $cert
 * @return string
 */
function getCertSN($certPath)
{
    $cert = file_get_contents($certPath);
    $ssl = openssl_x509_parse($cert);
    $SN = md5(array2string(array_reverse($ssl['issuer'])) . $ssl['serialNumber']);
    return $SN;
}

/**
 * 提取根证书序列号
 * @param $cert  根证书
 * @return string|null
 */
function getRootCertSN($certPath)
{
    $cert = file_get_contents($certPath);
    $array = explode("-----END CERTIFICATE-----", $cert);
    $SN = null;
    for ($i = 0; $i < count($array) - 1; $i++) {
        $ssl[$i] = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----");
        if (strpos($ssl[$i]['serialNumber'], '0x') === 0) {
            $ssl[$i]['serialNumber'] = hex2dec($ssl[$i]['serialNumber']);
        }
        if ($ssl[$i]['signatureTypeLN'] == "sha1WithRSAEncryption" || 
        $ssl[$i]['signatureTypeLN'] == "sha256WithRSAEncryption") {
            if ($SN == null) {
                $SN = md5(array2string(array_reverse($ssl[$i]['issuer'])) . 
                $ssl[$i]['serialNumber']);
            } else {

                $SN = $SN . "_" . md5(array2string(array_reverse($ssl[$i]['issuer'])) . 
                $ssl[$i]['serialNumber']);
            }
        }
    }
    return $SN;
}

/**
 * 0x转高精度数字
 * @param $hex
 * @return int|string
 */
function hex2dec($hex)
{
    $dec = 0;
    $len = strlen($hex);
    for ($i = 1; $i <= $len; $i++) {
     $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
    }
    return $dec;
}

/**
 * 数组拼接成字符串
 * @param $array
 * @return string
 */
function array2string($array)
{
    $string = [];
    if ($array && is_array($array)) {
        foreach ($array as $key => $value) {
            $string[] = $key . '=' . $value;
        }
    }
    return implode(',', $string);
}

       然后是sign生成以及其他转化的代码:

/**
 * 获取支付宝HTTP方式请求URL
 * @param array $params
 * @param string $privatekey
 * @param string $url
 * @return string
 */
function getTarUrl($params = array(), $privatekey = "", $url = "")
{
    #请求数组转成字符串
    $signString = getAliSignContent($params);
    #待请求字符串加密获取sign
    $sign = aloneAliRsaSign($signString, $privatekey, "RSA2");
    #将sign带入数组
    $params["sign"] = $sign;
    #请求链接编码及转换
    $url = getAliSignContentUrlencode($params);
    #获取最终请求URL
    $targetUrl = "https://openapi.alipay.com/gateway.do?" . $url;
    #返回
    return $targetUrl;
}


/**
 * 链接拼接
 * @param $params
 * @return string
 */
function getAliSignContentUrlencode($params)
{
    ksort($params);
    $stringToBeSigned = "";
    $i = 0;
    foreach ($params as $k => $v) {
        if (false === checkAliEmpty($v) && "@" != substr($v, 0, 1)) {

            // 转换成目标字符集
            $v = aliCharacet($v, "UTF-8");

            if ($i == 0) {
                $stringToBeSigned .= "$k" . "=" . urlencode($v);
            } else {
                $stringToBeSigned .= "&" . "$k" . "=" . urlencode($v);
            }
            $i++;
        }
    }
    unset ($k, $v);
    return $stringToBeSigned;
}


/**
 * 请求参数加密获取sign
 * @param $data
 * @param $privatekey
 * @param string $signType
 * @param bool $keyfromfile
 * @return string
 */
function aloneAliRsaSign($data, $privatekey, $signType = "RSA", $keyfromfile = false)
{

    if (!$keyfromfile) {
        $priKey = $privatekey;
        $res = "-----BEGIN RSA PRIVATE KEY-----\n" .
            wordwrap($priKey, 64, "\n", true) .
            "\n-----END RSA PRIVATE KEY-----";
    } else {
        $priKey = file_get_contents($privatekey);
        $res = openssl_get_privatekey($priKey);
    }

    ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');

    if ("RSA2" == $signType) {
        openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
    } else {
        openssl_sign($data, $sign, $res);
    }

    if ($keyfromfile) {
        openssl_free_key($res);
    }
    $sign = base64_encode($sign);

    return $sign;
}


/**
 * 数组转成字符串
 * @param $params
 * @return string
 */
function getAliSignContent($params)
{
    ksort($params);

    $stringToBeSigned = "";
    $i = 0;
    foreach ($params as $k => $v) {
        if (false === checkAliEmpty($v) && "@" != substr($v, 0, 1)) {

            // 转换成目标字符集
            $v = aliCharacet($v, "UTF-8");

            if ($i == 0) {
                $stringToBeSigned .= "$k" . "=" . "$v";
            } else {
                $stringToBeSigned .= "&" . "$k" . "=" . "$v";
            }
            $i++;
        }
    }

    unset ($k, $v);
    return $stringToBeSigned;
}


/**
 * 判断参数值是否为空
 * @param $value
 * @return bool
 */
function checkAliEmpty($value)
{
    if (!isset($value))
        return true;
    if ($value === null)
        return true;
    if (trim($value) === "")
        return true;

    return false;
}


/**
 * 转换成目标字符集
 * @param $data
 * @param $targetCharset
 * @return string
 */
function aliCharacet($data, $targetCharset)
{

    if (!empty($data)) {
        $fileType = "UTF-8";
        if (strcasecmp($fileType, $targetCharset) != 0) {
            $data = mb_convert_encoding($data, $targetCharset, $fileType);
            //          $data = iconv($fileType, $targetCharset.'//IGNORE', $data);
        }
    }


    return $data;
}


/**
 * Get请求
 * @param $url
 * @param $apiName
 * @return mixed
 */
function curlAliGet($url, $apiName)
{
    // 初始化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,结果以jason形式返回
    $res = curl_exec($ch);
    curl_close($ch);
    #json转换
    $returnData = json_decode($res);
    #获取结果体
    $responseNode = str_replace(".", "_", $apiName) . "_response";
    $result = $returnData->$responseNode;
    //返回
    return $result;
}

       然后下面是调用支付宝发送模板消息接口,代码如下:

#获取数据
$to_user_id = "支付宝用户app_id";
$form_id ="支付宝用户form_id";
#基本数据
$rsa_private_key = "支付宝的密钥";
$user_template_id = "支付宝模板ID";
$app_id = "支付宝app_id";
$page = "跳转地址";
#证书内容
$appCertPath = "应用公钥证书路径";
$rootCertPath = "支付宝根证书路径";
#内容
$bizCont = "{" .
    "\"to_user_id\":\"" . $to_user_id . "\"," .
    "\"form_id\":\"" . $form_id . "\"," .
    "\"user_template_id\":\"" . $user_template_id . "\"," .
    "\"page\":\"" . $page . "\"," .
    "\"data\":{" .
    "\"keyword1\": {\"value\" : \"测试\"}," .
    "\"keyword2\": {\"value\" : \"测试\"}," .
    "\"keyword3\": {\"value\" : \"测试\"}" .
    "        }" .
    "  }";
#生成签名
$params = array(
    'app_id' => $app_id,
    'charset' => 'UTF-8',
    'method' => 'alipay.open.app.mini.templatemessage.send',
    'sign_type' => 'RSA2',
    'timestamp' => date('Y-m-d H:i:s', time()),
    'version' => '1.0',
    'biz_content' => $bizCont,
    'app_cert_sn' => getCertSN($appCertPath),
    'alipay_root_cert_sn' =>getRootCertSN($rootCertPath)
);
#获取最终请求URL
$url = getTarUrl($params, $rsa_private_key, "https://openapi.alipay.com/gateway.do?");
$data = curlAliGet($url, $params["method"]);
#输出
print_r($data);

      这样我们就成功的在公钥证书方式下采用HTTP方式调用支付宝接口,如果是普通公钥方式可以参考我之前写过的另一篇文章。

0条评论

发表评论