PHP
公钥证书方式下如何使用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条评论