156 lines
5.3 KiB
PHP
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;
|
|
}
|
|
} |