chore(addon): 添加线下支付及华为支付基本配置
This commit is contained in:
291
src/addon/huaweipay/data/sdk/HuaweiPayClient.php
Normal file
291
src/addon/huaweipay/data/sdk/HuaweiPayClient.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
/**
|
||||
* 华为支付客户端类
|
||||
* 封装华为支付API调用
|
||||
*/
|
||||
|
||||
namespace addon\huaweipay\data\sdk;
|
||||
|
||||
use think\facade\Log;
|
||||
|
||||
class HuaweiPayClient
|
||||
{
|
||||
// 华为支付网关地址
|
||||
private $gatewayUrl = 'https://pay.cloud.huawei.com/gateway/api/pay';
|
||||
|
||||
// 华为支付配置
|
||||
private $config = [];
|
||||
|
||||
// 签名算法
|
||||
private $signType = 'RSA2';
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
* @param array $config 华为支付配置
|
||||
*/
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
// 根据配置设置网关地址
|
||||
if (isset($config['sandbox']) && $config['sandbox']) {
|
||||
$this->gatewayUrl = 'https://pay-drcn.cloud.huawei.com/gateway/api/pay';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名
|
||||
* @param array $params 请求参数
|
||||
* @return string 签名结果
|
||||
*/
|
||||
private function generateSign($params)
|
||||
{
|
||||
// 移除空值和签名参数
|
||||
$params = array_filter($params, function($value) {
|
||||
return $value !== null && $value !== '';
|
||||
});
|
||||
unset($params['sign']);
|
||||
unset($params['sign_type']);
|
||||
|
||||
// 按键名排序
|
||||
ksort($params);
|
||||
|
||||
// 拼接参数
|
||||
$stringToSign = '';
|
||||
foreach ($params as $key => $value) {
|
||||
$stringToSign .= $key . '=' . $value . '&';
|
||||
}
|
||||
$stringToSign = rtrim($stringToSign, '&');
|
||||
|
||||
// 根据签名类型生成签名
|
||||
switch ($this->signType) {
|
||||
case 'RSA2':
|
||||
$privateKey = $this->config['private_key'];
|
||||
$privateKey = "-----BEGIN PRIVATE KEY-----\n" . wordwrap($privateKey, 64, "\n", true) . "\n-----END PRIVATE KEY-----";
|
||||
openssl_sign($stringToSign, $sign, $privateKey, OPENSSL_ALGO_SHA256);
|
||||
break;
|
||||
case 'RSA':
|
||||
$privateKey = $this->config['private_key'];
|
||||
$privateKey = "-----BEGIN PRIVATE KEY-----\n" . wordwrap($privateKey, 64, "\n", true) . "\n-----END PRIVATE KEY-----";
|
||||
openssl_sign($stringToSign, $sign, $privateKey, OPENSSL_ALGO_SHA1);
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('不支持的签名类型');
|
||||
}
|
||||
|
||||
return base64_encode($sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名
|
||||
* @param array $params 响应参数
|
||||
* @return bool 验证结果
|
||||
*/
|
||||
public function verifySign($params)
|
||||
{
|
||||
// 保存签名
|
||||
$sign = $params['sign'] ?? '';
|
||||
unset($params['sign']);
|
||||
unset($params['sign_type']);
|
||||
|
||||
// 移除空值
|
||||
$params = array_filter($params, function($value) {
|
||||
return $value !== null && $value !== '';
|
||||
});
|
||||
|
||||
// 按键名排序
|
||||
ksort($params);
|
||||
|
||||
// 拼接参数
|
||||
$stringToSign = '';
|
||||
foreach ($params as $key => $value) {
|
||||
$stringToSign .= $key . '=' . $value . '&';
|
||||
}
|
||||
$stringToSign = rtrim($stringToSign, '&');
|
||||
|
||||
// 验证签名
|
||||
$huaweiPublicKey = $this->config['huawei_public_key'];
|
||||
$huaweiPublicKey = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($huaweiPublicKey, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
|
||||
|
||||
switch ($this->signType) {
|
||||
case 'RSA2':
|
||||
$result = openssl_verify($stringToSign, base64_decode($sign), $huaweiPublicKey, OPENSSL_ALGO_SHA256);
|
||||
break;
|
||||
case 'RSA':
|
||||
$result = openssl_verify($stringToSign, base64_decode($sign), $huaweiPublicKey, OPENSSL_ALGO_SHA1);
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('不支持的签名类型');
|
||||
}
|
||||
|
||||
return $result === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送HTTP请求
|
||||
* @param string $url 请求地址
|
||||
* @param array $params 请求参数
|
||||
* @param string $method 请求方法
|
||||
* @return array 响应结果
|
||||
*/
|
||||
private function httpRequest($url, $params, $method = 'POST')
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
// 设置请求头
|
||||
$headers = [
|
||||
'Content-Type: application/x-www-form-urlencoded; charset=utf-8',
|
||||
];
|
||||
|
||||
// 生成签名
|
||||
$params['app_id'] = $this->config['app_id'];
|
||||
$params['sign_type'] = $this->signType;
|
||||
$params['sign'] = $this->generateSign($params);
|
||||
|
||||
if ($method === 'POST') {
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
|
||||
} else {
|
||||
$url .= '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
throw new \Exception('HTTP请求错误: ' . curl_error($ch));
|
||||
}
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
// 解析响应
|
||||
parse_str($response, $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* H5支付
|
||||
* @param array $params 支付参数
|
||||
* @param string $returnUrl 同步回调地址
|
||||
* @param string $notifyUrl 异步回调地址
|
||||
* @return array 支付结果
|
||||
*/
|
||||
public function h5Pay($params, $returnUrl, $notifyUrl)
|
||||
{
|
||||
$requestParams = [
|
||||
'method' => 'h5pay.createPayment',
|
||||
'version' => '1.0',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'out_trade_no' => $params['out_trade_no'],
|
||||
'subject' => $params['subject'],
|
||||
'total_amount' => $params['total_amount'],
|
||||
'body' => $params['body'],
|
||||
'return_url' => $returnUrl,
|
||||
'notify_url' => $notifyUrl,
|
||||
'scene' => 'h5',
|
||||
];
|
||||
|
||||
return $this->httpRequest($this->gatewayUrl, $requestParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* APP支付
|
||||
* @param array $params 支付参数
|
||||
* @param string $notifyUrl 异步回调地址
|
||||
* @return array 支付结果
|
||||
*/
|
||||
public function appPay($params, $notifyUrl)
|
||||
{
|
||||
$requestParams = [
|
||||
'method' => 'apppay.createPayment',
|
||||
'version' => '1.0',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'out_trade_no' => $params['out_trade_no'],
|
||||
'subject' => $params['subject'],
|
||||
'total_amount' => $params['total_amount'],
|
||||
'body' => $params['body'],
|
||||
'notify_url' => $notifyUrl,
|
||||
];
|
||||
|
||||
return $this->httpRequest($this->gatewayUrl, $requestParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单
|
||||
* @param array $params 查询参数
|
||||
* @return array 查询结果
|
||||
*/
|
||||
public function queryOrder($params)
|
||||
{
|
||||
$requestParams = [
|
||||
'method' => 'unifiedorder.query',
|
||||
'version' => '1.0',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
// 支持通过商户订单号或华为交易号查询
|
||||
if (isset($params['out_trade_no'])) {
|
||||
$requestParams['out_trade_no'] = $params['out_trade_no'];
|
||||
} elseif (isset($params['trade_no'])) {
|
||||
$requestParams['trade_no'] = $params['trade_no'];
|
||||
} else {
|
||||
throw new \Exception('查询参数错误,必须提供out_trade_no或trade_no');
|
||||
}
|
||||
|
||||
return $this->httpRequest($this->gatewayUrl, $requestParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭订单
|
||||
* @param array $params 关闭参数
|
||||
* @return array 关闭结果
|
||||
*/
|
||||
public function closeOrder($params)
|
||||
{
|
||||
$requestParams = [
|
||||
'method' => 'unifiedorder.close',
|
||||
'version' => '1.0',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'out_trade_no' => $params['out_trade_no'],
|
||||
];
|
||||
|
||||
return $this->httpRequest($this->gatewayUrl, $requestParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退款
|
||||
* @param array $params 退款参数
|
||||
* @return array 退款结果
|
||||
*/
|
||||
public function refund($params)
|
||||
{
|
||||
$requestParams = [
|
||||
'method' => 'refund.apply',
|
||||
'version' => '1.0',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'out_trade_no' => $params['out_trade_no'],
|
||||
'trade_no' => $params['trade_no'],
|
||||
'refund_amount' => $params['refund_amount'],
|
||||
'out_request_no' => $params['out_request_no'],
|
||||
'refund_reason' => $params['refund_reason'] ?? '',
|
||||
];
|
||||
|
||||
return $this->httpRequest($this->gatewayUrl, $requestParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证回调签名
|
||||
* @param array $params 回调参数
|
||||
* @return bool 验证结果
|
||||
*/
|
||||
public function verifyNotify($params)
|
||||
{
|
||||
return $this->verifySign($params);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user