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

149 lines
4.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
class DinpayClient
{
private $gateway_url = 'https://payment.dinpay.com/trx';
private $sign_method = 'SM3WITHSM2';
private $mchid;
//平台公钥证书路径
private $platform_cert_path;
//商户私钥证书路径
private $merchant_cert_path;
//商户私钥证书密码
private $merchant_private_pwd;
private $platform_public_key;
private $merchant_private_key;
//SM4算法IVbase64编码
public $sm4Iv = "T172oxqWwkr8wqB9D7aR7g==";
//SM2算法userId
public $sm2userId = "1234567812345678";
public function __construct($mchid, $platform_public_key, $merchant_private_key, $isTest = false)
{
if(!function_exists('gmp_init')) throw new Exception('请先安装GMP扩展');
$this->mchid = $mchid;
if($isTest) $this->gateway_url = 'https://paymenttest.dinpay.com/trx';
$this->platform_public_key = $platform_public_key;
$this->merchant_private_key = $merchant_private_key;
}
//发起API请求
public function execute($path, $data, $file = null, $download = false){
//生成16位SM4随机秘钥
$sm4Key = random(16);
//加密后的SM4密钥
$encrytionKey = base64_encode(hex2bin('04'.$this->sm2DoEncrypt($sm4Key)));
$json = json_encode($data);
$enc_data = $this->sm4DoEncrypt($json, $sm4Key);
$sign = trim($this->sm2DoSign($enc_data));
$params = [
'merchantId' => $this->mchid,
'timestamp' => date('YmdHis'),
'data' => $enc_data,
'encryptionKey' => $encrytionKey,
'signatureMethod' => $this->sign_method,
'sign' => $sign,
];
if($file){
if($file instanceof \CURLFile){
$params['file'] = $file;
}
$response = get_curl($this->gateway_url.$path, $params);
}else{
$response = get_curl($this->gateway_url.$path, json_encode($params), 0, 0, 0, 0, 0, ['Content-Type: application/json; charset=utf-8']);
}
if($download) return $response;
$result = json_decode($response, true);
if(isset($result['code']) && ($result['code'] == '0000' || $result['code'] == '0001')){
if(!empty($result['sign'])){
if(!$this->sm2DoVerifySign($result['data'], $result['sign'])){
throw new Exception('返回数据验签失败');
}
}
return json_decode($result['data'], true);
}elseif(isset($result['msg'])){
throw new Exception($result['msg']);
}else{
throw new Exception('返回数据解析失败');
}
}
//使用商户私钥对数据进行sm2签名
private function sm2DoSign($signStr){
$sm2 = new Rtgm\sm\RtSm2('base64', true);
return $sm2->doSign($signStr, $this->merchant_private_key, $this->sm2userId);
}
//使用平台公钥对数据进行sm2验签
public function sm2DoVerifySign($signStr,$sign){
$sm2 = new Rtgm\sm\RtSm2('base64', true);
$isSign = $sm2->verifySign($signStr, $sign, $this->platform_public_key, $this->sm2userId);
return $isSign;
}
//使用平台公钥对数据进行sm2加密
private function sm2DoEncrypt($plaintext){
$sm2 = new Rtgm\sm\RtSm2('base64');
return $sm2->doEncrypt($plaintext, $this->platform_public_key);
}
//使用商户私钥对数据进行sm2解密
private function sm2DoDecrypt($ciphertext){
$sm2 = new Rtgm\sm\RtSm2('base64');
return $sm2->doDecrypt($ciphertext, $this->merchant_private_key);
}
//sm4加密
private function sm4DoEncrypt($plaintext, $key){
$sm4 = new Rtgm\sm\RtSm4($key);
return $sm4->encrypt($plaintext,'sm4',base64_decode($this->sm4Iv),'base64');
}
public function sm3ToHex($str){
$sm3 = new Rtgm\sm\RtSm3();
return $sm3->digest($str);
}
//获取平台公钥
private function getDinpayPublicKey(){
$cer_public_content = file_get_contents($this->platform_cert_path);
$cer_public_content = str_replace(PHP_EOL,'',$cer_public_content);
$certificateContent = '-----BEGIN CERTIFICATE-----' . PHP_EOL
. chunk_split($cer_public_content, 64, PHP_EOL)
. '-----END CERTIFICATE-----'.PHP_EOL;
$cer_public_key = openssl_pkey_get_public($certificateContent);
if(!$cer_public_key){
throw new Exception('读取平台公钥失败:'.openssl_error_string());
}
$key_detail = openssl_pkey_get_details($cer_public_key);
$cerPublicKey = bin2hex($key_detail['ec']['x']).bin2hex($key_detail['ec']['y']); //公钥的ec格式
return $cerPublicKey;
}
//获取商户私钥
private function getMerchantPrivateKey(){
$cert_store = file_get_contents($this->merchant_cert_path);
$status = openssl_pkcs12_read($cert_store, $cert_info, $this->merchant_private_pwd);
if (!$status) {
throw new Exception('读取商户私钥失败:'.openssl_error_string());
}
$fpx_private_key = $cert_info['pkey'];
$private_key = openssl_pkey_get_private($fpx_private_key);
$key_detail = openssl_pkey_get_details($private_key);
$privateKey = bin2hex($key_detail['ec']['d']);
return $privateKey;
}
}