支付宝支付(alipay.trade.app.pay(app支付接口2.0)) 证书方法也比较简单 主要是获取证书 (支付宝根证书SN(alipay_root_cert_sn)和 应用公钥证书SN(app_cert_sn)和 公钥证书(alipay_cert_public_key))
class Alipay { public $config; public function __construct(){ $alipayCertPath = "/datadisk/webroot/uopin/data/cert/alipay/alipayCertPublicKey_RSA2.crt"; $this->config = [ 'APPID'=>'appid', 'ALIPAY_PUBLIC_KEY'=>$this->getPublicKey($alipayCertPath), 'APP_PRIVATE_KEY'=>''//私钥 ]; } /*支付宝-统一支付接口*/ public function pay($order){ $method='alipay.trade.app.pay'; $product_code = "QUICK_MSECURITY_PAY"; //公共参数 $data["app_id"] = $this->config['APPID']; $data["version"] = "1.0"; $data["format"] = "JSON"; $data["sign_type"] = "RSA2"; $data["method"] = $method; $data["timestamp"] = date("Y-m-d H:i:s"); $data["notify_url"] = url('/shop/order/notify',['callback'=>$order['callback'],'paytype'=>$order['paytype']],'html',true); $data["charset"] = "utf-8"; $data["alipay_root_cert_sn"] = $this->getRootCertSN('../data/cert/alipay/alipayRootCert.crt');//支付宝根证书SN(alipay_root_cert_sn) $data["app_cert_sn"] = $this->getCertSN('../data/cert/alipay/appCertPublicKey_20210021212***.crt'); //应用公钥证书SN(app_cert_sn) //业务参数 $ydata["subject"] = $order['body']; //商品名称,此处用商户名称代替 $ydata["out_trade_no"] = $order['sno']; //平台订单号 $ydata["total_amount"] = $order['payamount']; //总金额,精确到小数点两位 if($product_code != ""){ $ydata["product_code"] = $product_code; } //除公共参数外所有请求参数都必须放在这个参数中传递 $data["biz_content"] = json_encode($ydata,JSON_UNESCAPED_UNICODE); //待签名字符串 $preSignStr = $this->getSignContent($data); $sign = $this->sign($preSignStr,$data['sign_type']); $data = $preSignStr . "&sign=" . urlencode($sign); $data= [ 'pay_type'=>1, 'info' => $data ]; return ajaxReturn(0,'调起支付成功',$data); } /** * 从证书中提取序列号 * @param $cert * @return string */ public function getCertSN($certPath) { $cert = file_get_contents($certPath); $ssl = openssl_x509_parse($cert); $SN = md5($this->array2string(array_reverse($ssl['issuer'])) . $ssl['serialNumber']); return $SN; } /** * 提取根证书序列号 * @param $cert 根证书 * @return string|null */ public function getRootCertSN($certPath) { $cert = file_get_contents($certPath); // $this->alipayRootCertContent = $cert; $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'] = $this->hex2dec($ssl[$i]['serialNumberHex']); } if ($ssl[$i]['signatureTypeLN'] == "sha1WithRSAEncryption" || $ssl[$i]['signatureTypeLN'] == "sha256WithRSAEncryption") { if ($SN == null) { $SN = md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']); } else { $SN = $SN . "_" . md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']); } } } return $SN; } /** * 0x转高精度数字 * @param $hex * @return int|string */ public 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; } protected function array2string($array) { $string = []; if ($array && is_array($array)) { foreach ($array as $key => $value) { $string[] = $key . '=' . $value; } } return implode(',', $string); } /** * 从证书中提取公钥 * @param $cert * @return mixed */ public 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; } /*签名*/ private function sign($data, $signType = "RSA") { $priKey=$this->config['APP_PRIVATE_KEY']; $res = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($priKey, 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; if ("RSA2" == $signType) { openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256); } else { openssl_sign($data, $sign, $res); } $sign = base64_encode($sign); return $sign; } private function getSignContent($params) { ksort($params); $stringToBeSigned = ""; $i = 0; foreach ($params as $k => $v) { if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) { if ($i == 0) { $stringToBeSigned .= "$k" . "=" . "$v"; } else { $stringToBeSigned .= "&" . "$k" . "=" . "$v"; } $i++; } } unset ($k, $v); return $stringToBeSigned; } /** * 校验$value是否非空 * if not set ,return true; * if is null , return true; **/ private function checkEmpty($value) { if (!isset($value)) return true; if ($value === null) return true; if (trim($value) === "") return true; return false; } }
支付宝转账 (alipay.fund.trans.uni.transfer)
class AlipayTransfers { protected $appId; //私钥值 protected $rsaPrivateKey; private $charset; private $alipay_root_cert_sn; //支付宝根证书SN private $app_cert_sn; //应用公钥证书SN public function __construct($appid = '', $saPrivateKey = '') { $this->appId = 'appid'; $this->rsaPrivateKey = ''; $this->charset = 'utf-8'; $this->alipay_root_cert_sn = '../data/cert/alipay/alipayRootCert.crt'; $this->app_cert_sn = '../data/cert/alipay/appCertPublicKey_20210021***.crt'; } /** * 转帐 * @param float $totalFee 转账金额,单位:元。 * @param string $outTradeNo 商户转账唯一订单号 * @param string $remark 转帐备注 * @return array */ public function doPay($totalFee, $outTradeNo, $account, $realName, $remark = '') { //请求参数 $requestConfigs = array( 'out_biz_no' => $outTradeNo, 'trans_amount' => $totalFee, //转账金额,单位:元。 'product_code' => 'TRANS_ACCOUNT_NO_PWD', //业务产品码 单笔无密转账到支付宝账户 'biz_scene' => 'DIRECT_TRANSFER', 'payee_info' =>[ 'identity' => $account, 'identity_type' => 'ALIPAY_LOGON_ID', //支付宝登录号,支持邮箱和手机号格式 'name' => $realName, //收款方真实姓名 ], 'remark' => $remark, //转账备注(选填) ); $commonConfigs = array( //公共参数 'app_id' => $this->appId, 'method' => 'alipay.fund.trans.uni.transfer', //接口名称 'format' => 'JSON', 'charset' => $this->charset, 'sign_type' => 'RSA2', 'timestamp' => date('Y-m-d H:i:s'), 'alipay_root_cert_sn' => $this->getRootCertSN($this->alipay_root_cert_sn),//支付宝根证书SN(alipay_root_cert_sn) 'app_cert_sn' => $this->getCertSN($this->app_cert_sn), //应用公钥证书SN(app_cert_sn) 'version' => '1.0', 'biz_content' => json_encode($requestConfigs), ); $commonConfigs["sign"] = $this->generateSign($commonConfigs, $commonConfigs['sign_type']); $result = $this->curlPost('https://openapi.alipay.com/gateway.do', $commonConfigs); $resultArr = json_decode($result, true); if (empty($resultArr)) { $result = iconv('GBK', 'UTF-8//IGNORE', $result); return json_decode($result, true); } return $resultArr; } //支付宝账户余额查询 public function accountQuery() { //请求参数 $requestConfigs = array( 'alipay_user_id' => '', //支付宝会员 id 'account_type' => 'ACCTRANS_ACCOUNT', //查询的账号类型 ); $commonConfigs = array( //公共参数 'app_id' => $this->appId, 'method' => 'alipay.fund.account.query', //接口名称 'format' => 'JSON', 'charset' => $this->charset, 'sign_type' => 'RSA2', 'timestamp' => date('Y-m-d H:i:s'), 'alipay_root_cert_sn' => $this->getRootCertSN($this->alipay_root_cert_sn),//支付宝根证书SN(alipay_root_cert_sn) 'app_cert_sn' => $this->getCertSN($this->app_cert_sn), //应用公钥证书SN(app_cert_sn) 'version' => '1.0', 'biz_content' => json_encode($requestConfigs), ); $commonConfigs["sign"] = $this->generateSign($commonConfigs, $commonConfigs['sign_type']); $result = $this->curlPost('https://openapi.alipay.com/gateway.do', $commonConfigs); $resultArr = json_decode($result, true); var_dump($resultArr);exit(); $responseNode = str_replace(".", "_", $commonConfigs['method']) . "_response"; if ($resultArr[$responseNode]['code'] == '10000') { return $resultArr[$responseNode]['available_amount']; } else { return ''; } } public function generateSign($params, $signType = "RSA") { return $this->sign($this->getSignContent($params), $signType); } // protected function sign($data, $signType = "RSA") // { // $priKey = $this->rsaPrivateKey; // $res = "-----BEGIN RSA PRIVATE KEY-----\n" . // wordwrap($priKey, 64, "\n", true) . // "\n-----END RSA PRIVATE KEY-----"; // ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置'); // if ("RSA2" == $signType) { // openssl_sign($data, $sign, $res, version_compare(PHP_VERSION, '5.4.0', '<') ? SHA256 : OPENSSL_ALGO_SHA256); //OPENSSL_ALGO_SHA256是php5.4.8以上版本才支持 // } else { // openssl_sign($data, $sign, $res); // } // $sign = base64_encode($sign); // return $sign; // } protected function sign($data, $signType = "RSA") { $priKey=$this->rsaPrivateKey; $res = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($priKey, 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; ($res) or die('您使用的私钥格式错误,请检查RSA私钥配置'); if ("RSA2" == $signType) { openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256); } else { openssl_sign($data, $sign, $res); } $sign = base64_encode($sign); return $sign; } /** * 校验$value是否非空 * if not set ,return true; * if is null , return true; **/ protected function checkEmpty($value) { if (!isset($value)) return true; if ($value === null) return true; if (trim($value) === "") return true; return false; } public function getSignContent($params) { ksort($params); $stringToBeSigned = ""; $i = 0; foreach ($params as $k => $v) { if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) { // 转换成目标字符集 $v = $this->characet($v, $this->charset); if ($i == 0) { $stringToBeSigned .= "$k" . "=" . "$v"; } else { $stringToBeSigned .= "&" . "$k" . "=" . "$v"; } $i++; } } unset ($k, $v); return $stringToBeSigned; } /** * 转换字符集编码 * @param $data * @param $targetCharset * @return string */ function characet($data, $targetCharset) { if (!empty($data)) { $fileType = $this->charset; if (strcasecmp($fileType, $targetCharset) != 0) { $data = mb_convert_encoding($data, $targetCharset, $fileType); } } return $data; } public function curlPost($url = '', $postData = '', $options = array()) { if (is_array($postData)) { $postData = http_build_query($postData); // $url = $url . '?' . http_build_query($postData); } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_TIMEOUT, 300); //设置cURL允许执行的最长秒数 if (!empty($options)) { curl_setopt_array($ch, $options); } //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec($ch); //解决 中文乱码问题 if(!mb_check_encoding($data, 'utf-8')) { $data = mb_convert_encoding($data,'UTF-8',['ASCII','UTF-8','GB2312','GBK']); } curl_close($ch); return $data; } /** * 从证书中提取序列号 * @param $cert * @return string */ public function getCertSN($certPath) { $cert = file_get_contents($certPath); $ssl = openssl_x509_parse($cert); $SN = md5($this->array2string(array_reverse($ssl['issuer'])) . $ssl['serialNumber']); return $SN; } /** * 提取根证书序列号 * @param $cert 根证书 * @return string|null */ public 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'] = $this->hex2dec($ssl[$i]['serialNumber']); } if ($ssl[$i]['signatureTypeLN'] == "sha1WithRSAEncryption" || $ssl[$i]['signatureTypeLN'] == "sha256WithRSAEncryption") { if ($SN == null) { $SN = md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']); } else { $SN = $SN . "_" . md5($this->array2string(array_reverse($ssl[$i]['issuer'])) . $ssl[$i]['serialNumber']); } } } return $SN; } /** * 0x转高精度数字 * @param $hex * @return int|string */ protected 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; } protected function array2string($array) { $string = []; if ($array && is_array($array)) { foreach ($array as $key => $value) { $string[] = $key . '=' . $value; } } return implode(',', $string); } }