单笔转账到支付宝账户,支付宝公钥证书实现版本tp6
【单笔转账到支付宝账户】,采用支付宝公钥证书签名来实现。
1、首先获取秘钥
由于我们使用的是php,点击pkcs1(非java适用)
按照上面图中的 三个步骤操作,操作完成后,点击【打开文件位置】,可以看到下面这些文件
会有
- 一个csr文件
- 一个公钥
- 一个私钥
我们将csr文件上传到支付宝 接口加签方式 里面,然后讲下图里面的三个整数下载下来
分别是:
- alipayCertPublicKey_RSA2.crt
- alipayRootCert.crt
- appCertPublicKey_202100000023232.crt
第二步,配置php配置
我们将 上面生成的三个文件复制到证书目录,如图:
配置代码如下:
1 <?php 2 return [ 3 'app_id' => '', // 支付宝应用的appid 4 'alipay_root_cert_sn' => BASE_PATH . '/cert/alipayRootCert.crt', // 支付宝根证书在自己服务器的绝对路径 5 'app_cert_sn' => BASE_PATH . '/cert/appCertPublicKey_2021000199651454.crt', // 应用公钥证书在自己服务器绝对路径 6 'rsa_private_key' => '' // 这个是RSA签名,特别要注意的是,是我们第一步中的对应自己域名的那个私钥哦 7 ];
编写AlipayTransServer
1 class AlipayTransServer 2 { 3 protected $appId; 4 //私钥值 5 protected $rsaPrivateKey; 6 /** 7 * @var string 8 */ 9 private $charset; 10 11 public function __construct($appid, $saPrivateKey) 12 { 13 $this->appId = $appid; 14 $this->charset = 'utf8'; 15 $this->rsaPrivateKey = $saPrivateKey; 16 } 17 18 /** 19 * 转帐 20 * @param float $totalFee 转账金额,单位:元。 21 * @param string $outTradeNo 商户转账唯一订单号 22 * @param string $remark 转帐备注 23 * @return array 24 */ 25 public function doPay($totalFee, $outTradeNo, $account, $realName, $remark = '') 26 { 27 //请求参数 28 $requestConfigs = array( 29 'out_biz_no' => $outTradeNo, 30 'payee_type' => 'ALIPAY_LOGONID', 31 'payee_account' => $account, 32 'payee_real_name' => $realName, //收款方真实姓名 33 'amount' => $totalFee, //转账金额,单位:元。 34 'remark' => $remark, //转账备注(选填) 35 ); 36 $commonConfigs = array( 37 //公共参数 38 'app_id' => $this->appId, 39 'method' => 'alipay.fund.trans.toaccount.transfer', //接口名称 40 'format' => 'JSON', 41 'charset' => $this->charset, 42 'sign_type' => 'RSA2', 43 'timestamp' => date('Y-m-d H:i:s'), 44 'alipay_root_cert_sn' => $this->getRootCertSN(BASE_PATH . '/cert/alipayRootCert.crt'),//支付宝根证书SN(alipay_root_cert_sn) 45 'app_cert_sn' => $this->getCertSN(BASE_PATH . '/cert/appCertPublicKey_2021000199651454.crt'), //应用公钥证书SN(app_cert_sn) 46 'version' => '1.0', 47 'biz_content' => json_encode($requestConfigs), 48 ); 49 $commonConfigs["sign"] = $this->generateSign($commonConfigs, $commonConfigs['sign_type']); 50 $result = $this->curlPost('https://openapi.alipay.com/gateway.do', $commonConfigs); 51 $resultArr = json_decode($result, true); 52 if (empty($resultArr)) { 53 $result = iconv('GBK', 'UTF-8//IGNORE', $result); 54 return json_decode($result, true); 55 } 56 return $resultArr; 57 } 58 59 public function generateSign($params, $signType = "RSA") 60 { 61 return $this->sign($this->getSignContent($params), $signType); 62 } 63 64 protected function sign($data, $signType = "RSA") 65 { 66 $priKey = $this->rsaPrivateKey; 67 $res = "-----BEGIN RSA PRIVATE KEY-----\n" . 68 wordwrap($priKey, 64, "\n", true) . 69 "\n-----END RSA PRIVATE KEY-----"; 70 ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置'); 71 if ("RSA2" == $signType) { 72 openssl_sign($data, $sign, $res, version_compare(PHP_VERSION, '5.4.0', '<') ? SHA256 : OPENSSL_ALGO_SHA256); //OPENSSL_ALGO_SHA256是php5.4.8以上版本才支持 73 } else { 74 openssl_sign($data, $sign, $res); 75 } 76 $sign = base64_encode($sign); 77 return $sign; 78 } 79 80 /** 81 * 校验$value是否非空 82 * if not set ,return true; 83 * if is null , return true; 84 **/ 85 protected function checkEmpty($value) 86 { 87 if (!isset($value)) 88 return true; 89 if ($value === null) 90 return true; 91 if (trim($value) === "") 92 return true; 93 return false; 94 } 95 96 public function getSignContent($params) 97 { 98 ksort($params); 99 $stringToBeSigned = ""; 100 $i = 0; 101 foreach ($params as $k => $v) { 102 if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) { 103 // 转换成目标字符集 104 $v = $this->characet($v, $this->charset); 105 if ($i == 0) { 106 $stringToBeSigned .= "$k" . "=" . "$v"; 107 } else { 108 $stringToBeSigned .= "&" . "$k" . "=" . "$v"; 109 } 110 $i++; 111 } 112 } 113 unset ($k, $v); 114 return $stringToBeSigned; 115 } 116 117 /** 118 * 转换字符集编码 119 * @param $data 120 * @param $targetCharset 121 * @return string 122 */ 123 function characet($data, $targetCharset) 124 { 125 if (!empty($data)) { 126 $fileType = $this->charset; 127 if (strcasecmp($fileType, $targetCharset) != 0) { 128 $data = mb_convert_encoding($data, $targetCharset, $fileType); 129 } 130 } 131 return $data; 132 } 133 134 public function curlPost($url = '', $postData = '', $options = array()) 135 { 136 if (is_array($postData)) { 137 $url = $url . '?' . http_build_query($postData); 138 cli_log($url); 139 } 140 $ch = curl_init(); 141 curl_setopt($ch, CURLOPT_URL, $url); 142 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 143 curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数 144 if (!empty($options)) { 145 curl_setopt_array($ch, $options); 146 } 147 //https请求 不验证证书和host 148 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 149 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 150 $data = curl_exec($ch); 151 curl_close($ch); 152 return $data; 153 } 154 155 /** 156 * 从证书中提取*** 157 * @param $cert 158 * @return string 159 */ 160 public function getCertSN($certPath) 161 { 162 $cert = file_get_contents($certPath); 163 $ssl = openssl_x509_parse($cert); 164 $SN = md5($this->array2string(array_reverse($ssl['issuer'])) . $ssl['serialNumber']); 165 return $SN; 166 } 167 168 /** 169 * 提取根证书*** 170 * @param $cert 根证书 171 * @return string|null 172 */ 173 public function getRootCertSN($certPath) 174 { 175 $cert = file_get_contents($certPath); 176 $array = explode("-----END CERTIFICATE-----", $cert); 177 $SN = null; 178 for ($i = 0; $i < count($array) - 1; $i++) { 179 $ssl[$i] = openssl_x509_parse($array[$i] . "-----END CERTIFICATE-----"); 180 if (strpos($ssl[$i]['serialNumber'], '0x') === 0) { 181 $ssl[$i]['serialNumber'] = $this->hex2dec($ssl[$i]['serialNumber']); 182 } 183 if ($ssl[$i]['signatureTypeLN'] == "sha1WithRSAEncryption" || $ssl[$i]['signatureTypeLN'] == "sha256WithRSAEncryption") { 184 if ($SN == null) { 185 $SN = md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']); 186 } else { 187 188 $SN = $SN . "_" . md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']); 189 } 190 } 191 } 192 return $SN; 193 } 194 195 /** 196 * 0x转高精度数字 197 * @param $hex 198 * @return int|string 199 */ 200 protected function hex2dec($hex) 201 { 202 $dec = 0; 203 $len = strlen($hex); 204 for ($i = 1; $i <= $len; $i++) { 205 $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i)))); 206 } 207 return $dec; 208 } 209 210 protected function array2string($array) 211 { 212 $string = []; 213 if ($array && is_array($array)) { 214 foreach ($array as $key => $value) { 215 $string[] = $key . '=' . $value; 216 } 217 } 218 return implode(',', $string); 219 } 220 }
实现业务部分:
1 /** 2 * 转账提现 3 * @param $realName 收款人真实姓名 4 * @param $account 收款人账号 5 * @param $amount 付款金额 6 * @param string $remark 付款备注 7 * @return array|void 8 */ 9 public function transfer($realName, $account, $amount, $remark = '提现') 10 { 11 $aliConfig = config('alipay'); 12 $aliTransfers = new Transfers($aliConfig['app_id'], $aliConfig['rsa_private_key']); 13 $outTradeNo = date('Ymd') . time() . rand_string(6, true);//退款对单号,可以自己生成 14 return $aliTransfers->doPay($amount, $outTradeNo, $account, $realName, $remark); 15 }
然后,我们去调用transfer 控制器,传入对应参数就可以了哦;
版权声明:本文为umufeng原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
csdn的不能复制,可以用下面的这个复制
https://www.freesion.com/article/9400246878/