pay/plugins/sandpay/inc/SandpayClient.php
2025-11-28 10:08:12 +08:00

156 lines
5.3 KiB
PHP

<?php
/**
* https://api.sandpay.com.cn/
*/
class SandpayClient
{
private $accessMid;
private $version = '4.0.0';
private $signType = 'RSA';
private $encryptType = 'AES';
// 公钥文件
private $publicKeyPath = PLUGIN_ROOT.'sandpay/cert/sand.cer';
// 私钥文件
private $privateKeyPath = PLUGIN_ROOT.'sandpay/cert/client.pfx';
// 私钥证书密码
private $privateKeyPwd;
private $publicKey;
private $privateKey;
private $apiUrl = 'https://openapi.sandpay.com.cn';
public $request_body;
public $response_body;
public function __construct($accessMid, $privateKeyPwd, $isTest = 0){
$this->accessMid = $accessMid;
$this->privateKeyPwd = $privateKeyPwd;
if(file_exists(PLUGIN_ROOT.'sandpay/cert/'.$accessMid.'.pfx')){
$this->privateKeyPath = PLUGIN_ROOT.'sandpay/cert/'.$accessMid.'.pfx';
}
if($isTest == 1){
$this->apiUrl = 'https://openapi-uat01.sand.com.cn';
}
$this->publicKey = $this->getPublicKey();
$this->privateKey = $this->getPrivateKey();
}
//执行请求
public function execute($path, $params){
$aesKey = random(16);
ksort($params);
$data = json_encode($params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$this->request_body = $data;
$bizData = $this->aesEncrypt($data, $aesKey);
$encryptKey = $this->rsaPublicEncrypt($aesKey);
$publicParams = [
'accessMid' => $this->accessMid,
'timestamp' => date('Y-m-d H:i:s'),
'version' => $this->version,
'signType' => $this->signType,
'encryptType' => $this->encryptType,
'encryptKey' => $encryptKey,
'bizData' => $bizData,
];
$publicParams['sign'] = $this->rsaPrivateSign($publicParams['bizData']);
$json = json_encode($publicParams, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$response = get_curl($this->apiUrl.$path, $json, 0, 0, 0, 0, 0, ['Content-Type: application/json; charset=utf-8']);
$result = json_decode($response, true);
if($result['respCode']=='success'){
if(!$this->rsaPubilcVerify($result['bizData'], $result['sign'])){
throw new \Exception('返回数据验签失败');
}
$decryptAesKey = $this->rsaPrivateDecrypt($result['encryptKey']);
if(!$decryptAesKey){
throw new \Exception('AES密钥解密失败');
}
$decryptPlainText = $this->aesDecrypt($result['bizData'], $decryptAesKey);
if(!$decryptPlainText){
throw new \Exception('AES解密失败');
}
$this->response_body = $decryptPlainText;
$arr = json_decode($decryptPlainText, true);
if(!$arr){
throw new \Exception('bizData解析失败');
}
if($arr['resultStatus'] == 'fail'){
throw new \Exception('['.$arr['errorCode'].']'.$arr['errorDesc']);
}
return $arr;
}elseif($result['respCode']=='fail'){
throw new \Exception($result['respDesc']);
}else{
throw new \Exception('返回数据解析失败');
}
}
public function verify($data, $sign){
if(empty($sign)) return false;
return $this->rsaPubilcVerify($data, $sign);
}
//AES加密
private function aesEncrypt($data, $key){
return openssl_encrypt($data, 'AES-128-ECB', $key);
}
//AES解密
private function aesDecrypt($data, $key){
return openssl_decrypt($data, 'AES-128-ECB', $key);
}
//杉德公钥
private function getPublicKey()
{
$file = file_get_contents($this->publicKeyPath);
$cert = chunk_split(base64_encode($file), 64, "\n");
$cert = "-----BEGIN CERTIFICATE-----\n" . $cert . "-----END CERTIFICATE-----\n";
$res = openssl_pkey_get_public($cert);
if (!$res) {
throw new \Exception('从杉德公钥证书获取公钥失败');
}
return $res;
}
//商户私钥
private function getPrivateKey()
{
$file = file_get_contents($this->privateKeyPath);
if (!openssl_pkcs12_read($file, $cert, $this->privateKeyPwd)) {
throw new \Exception('商户私钥证书解析失败');
}
return openssl_pkey_get_private($cert['pkey']);
}
//私钥加签
private function rsaPrivateSign($data)
{
$result = openssl_sign($data, $sign, $this->privateKey, OPENSSL_ALGO_SHA256);
if (!$result) throw new \Exception('sign error');
return base64_encode($sign);
}
//公钥验签
public function rsaPubilcVerify($data, $sign)
{
$result = openssl_verify($data, base64_decode($sign), $this->publicKey, OPENSSL_ALGO_SHA256);
return $result === 1;
}
//公钥加密
public function rsaPublicEncrypt($data) {
$encrypted = '';
openssl_public_encrypt($data, $encrypted, $this->publicKey, OPENSSL_PKCS1_PADDING);
return base64_encode($encrypted);
}
//私钥解密
public function rsaPrivateDecrypt($data) {
$decrypted = '';
openssl_private_decrypt(base64_decode($data), $decrypted, $this->privateKey, OPENSSL_PKCS1_PADDING);
return $decrypted;
}
}