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条评论