chore(addon/huaweipay): 更新huaweipay

This commit is contained in:
2025-12-04 10:32:00 +08:00
parent 09ed1bd427
commit a793ed541b
14 changed files with 1093 additions and 498 deletions

View File

@@ -3,263 +3,417 @@
* 华为支付模型测试类
*/
namespace addon\huaweipay\tests;
// 设置错误报告
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
use addon\huaweipay\model\Pay;
use addon\huaweipay\model\Config;
use think\facade\Log;
// 添加自动加载路径
$root_path = dirname(__DIR__, 3);
require_once $root_path . '/vendor/autoload.php';
// 定义常量
if (!defined('ROOT_PATH')) {
define('ROOT_PATH', $root_path . '/');
}
// 模拟app()函数,解决框架依赖问题
function app() {
return new class {
public function getRootPath() {
return dirname(__DIR__, 3) . '\\';
}
};
}
class PayModelTest
{
/**
* 测试站点ID
* @var int
*/
protected $siteId = 1;
/**
* 测试配置数据
* @var array
*/
protected $configData;
protected $config = [];
protected $pay_model = null;
/**
* 构造函数,加载配置文件
* 构造函数
*/
public function __construct()
{
// 加载配置文件
$yamlPath = __DIR__ . '/mock/data.yml';
if (file_exists($yamlPath)) {
if (function_exists('yaml_parse_file')) {
$this->configData = yaml_parse_file($yamlPath);
} else {
// 如果没有yaml_parse_file函数手动解析
$this->configData = $this->parseYamlFile($yamlPath);
}
} else {
throw new Exception("配置文件不存在: {$yamlPath}");
}
// 加载测试配置
$this->config = $this->parseYamlFile(__DIR__ . '/mock/data.yml');
echo "配置加载完成\n";
// print_r($this->config);
}
/**
* 手动解析YAML文件
* @param string $filePath
* 解析YAML文件
* @param string $file_path YAML文件路径
* @return array
*/
private function parseYamlFile($filePath)
protected function parseYamlFile($file_path)
{
$content = file_get_contents($filePath);
$lines = explode("\n", $content);
$result = [];
$currentKey = '';
$isMultiline = false;
$multilineValue = '';
if (!file_exists($file_path)) {
throw new Exception("YAML文件不存在: {$file_path}");
}
$yaml_content = file_get_contents($file_path);
if ($yaml_content === false) {
throw new Exception("读取YAML文件失败: {$file_path}");
}
// 使用正则替换YAML中的\n为实际换行符
$yaml_content = preg_replace_callback('/\\\\n/', function($matches) {
return "\n";
}, $yaml_content);
// 简单的YAML解析仅支持当前测试文件的格式
$config = [];
$lines = explode("\n", $yaml_content);
$current_key = '';
$in_block = false;
$block_content = '';
foreach ($lines as $line) {
$line = trim($line);
// 跳过注释和空行
if (empty($line) || strpos($line, '#') === 0) {
continue;
}
// 处理多行值
if ($isMultiline) {
if (strpos($line, '-----END') === 0) {
$multilineValue .= $line . "\n";
$result[$currentKey] = rtrim($multilineValue);
$isMultiline = false;
$multilineValue = '';
} else {
$multilineValue .= $line . "\n";
if ($in_block) {
if (strpos($line, '---') === 0) {
continue;
}
if (preg_match('/^\w+:/', $line)) {
$config[$current_key] = $block_content;
$in_block = false;
$block_content = '';
} else {
$block_content .= $line . "\n";
continue;
}
continue;
}
// 处理单行键值对
if (strpos($line, ':') !== false) {
list($key, $value) = explode(':', $line, 2);
$key = trim($key);
$value = trim($value);
// 处理多行值开始
if ($value === '|') {
$isMultiline = true;
$currentKey = $key;
if (strpos($value, '|') !== false) {
$in_block = true;
$current_key = $key;
continue;
}
// 处理普通值
if (!empty($value)) {
$result[$key] = $value;
$config[$key] = $value;
}
}
}
return $result;
if ($in_block && !empty($current_key)) {
$config[$current_key] = $block_content;
}
return $config;
}
/**
* 运行所有测试
* 运行测试
*/
public function runTests()
{
echo "开始测试华为支付模型...\n";
echo "开始运行华为支付模型测试...\n";
try {
// 1. 测试支付方法
echo "1. 测试支付方法...\n";
$this->testPayMethod();
$this->testNotifyMethod();
$this->testCloseOrderMethod();
$this->testRefundMethod();
$this->testQueryOrderMethod();
echo "1. 支付方法测试通过\n";
echo "\n✅ 所有测试通过!\n";
return true;
} catch (\Exception $e) {
echo "\n❌ 测试失败:" . $e->getMessage() . "\n";
echo "错误位置:" . $e->getFile() . "" . $e->getLine() . "\n";
// 2. 测试关闭订单方法
echo "2. 测试关闭订单方法...\n";
$this->testCloseOrderMethod();
echo "2. 关闭订单方法测试通过\n";
// 3. 测试退款方法
echo "3. 测试退款方法...\n";
$this->testRefundMethod();
echo "3. 退款方法测试通过\n";
// 4. 测试查询订单方法
echo "4. 测试查询订单方法...\n";
$this->testQueryOrderMethod();
echo "4. 查询订单方法测试通过\n";
// 5. 测试回调验证方法
echo "5. 测试回调验证方法...\n";
$this->testCallbackVerification();
echo "5. 回调验证方法测试通过\n";
echo "\n所有测试通过!\n";
} catch (Exception $e) {
echo "\n测试失败:" . $e->getMessage() . "\n";
echo "错误堆栈:" . $e->getTraceAsString() . "\n";
return false;
}
return true;
}
/**
* 测试支付方法
*/
public function testPayMethod()
protected function testPayMethod()
{
echo "测试支付方法...";
// 创建支付模型实例
require_once dirname(__DIR__) . '/model/Pay.php';
require_once dirname(__DIR__) . '/data/sdk/utils.php';
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
// 添加必要的配置
$site_id = '1';
$config_data = $this->config;
$config_data['site_id'] = $site_id;
// 使用文本模式的密钥,而不是证书文件
unset($config_data['private_key']);
unset($config_data['huawei_public_key']);
try {
// 模拟配置
$this->mockConfig();
// 创建实际的华为支付客户端实例
$project_root = dirname(__DIR__, 4); // 获取项目根目录
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
echo " - 华为支付客户端实例创建成功\n";
// 创建测试订单数据
$orderInfo = [
'out_trade_no' => 'test_order_' . time(),
'total_amount' => 100,
'subject' => '测试商品',
'notify_url' => $this->configData['notifyUrl'],
'return_url' => $this->configData['returnUrl'],
'buyer_id' => '1',
'type' => 'h5'
// 测试H5支付
$h5_params = [
'out_trade_no' => 'TEST_H5_' . time(),
'subject' => '测试H5支付商品',
'body' => '测试H5支付商品描述',
'total_amount' => 0.01,
'client_ip' => '127.0.0.1'
];
// 尝试创建Pay实例
$payModel = new Pay($this->siteId);
// 调用真实的H5支付方法
$h5_result = $huawei_pay_client->h5Pay($h5_params, $config_data['returnUrl'], $config_data['notifyUrl']);
echo " - H5支付方法调用成功\n";
echo " 结果: " . json_encode($h5_result, JSON_UNESCAPED_UNICODE) . "\n";
// 由于需要实际的支付客户端,这里只测试模型初始化
echo " ⚠️ 跳过实际支付测试,仅测试模型初始化\n";
} catch (\Exception $e) {
echo " ⚠️ 模型初始化测试跳过: " . $e->getMessage() . "\n";
}
}
/**
* 测试通知方法
*/
public function testNotifyMethod()
{
echo "测试通知方法...";
try {
// 模拟配置
$this->mockConfig();
// 创建模拟通知数据
$notifyData = [
'app_id' => $this->configData['app_id'],
'merc_no' => $this->configData['mch_id'],
'order_id' => 'test_order_001',
'trade_status' => 'SUCCESS',
'sign' => 'mock_signature'
// 测试APP支付
$app_params = [
'out_trade_no' => 'TEST_APP_' . time(),
'subject' => '测试APP支付商品',
'body' => '测试APP支付商品描述',
'total_amount' => 0.01
];
// 尝试创建Pay实例
$payModel = new Pay($this->siteId);
// 调用真实的APP支付方法
$app_result = $huawei_pay_client->appPay($app_params, $config_data['notifyUrl']);
echo " - APP支付方法调用成功\n";
echo " 结果: " . json_encode($app_result, JSON_UNESCAPED_UNICODE) . "\n";
echo " ⚠️ 跳过实际通知处理测试\n";
} catch (\Exception $e) {
echo " ⚠️ 通知测试跳过: " . $e->getMessage() . "\n";
} catch (Exception $e) {
echo " - 支付测试失败: " . $e->getMessage() . "\n";
throw $e;
}
}
/**
* 测试关闭订单方法
*/
public function testCloseOrderMethod()
protected function testCloseOrderMethod()
{
echo "测试关闭订单方法...";
require_once dirname(__DIR__) . '/data/sdk/utils.php';
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
// 添加必要的配置
$site_id = '1';
$config_data = $this->config;
$config_data['site_id'] = $site_id;
// 使用文本模式的密钥,而不是证书文件
unset($config_data['private_key']);
unset($config_data['huawei_public_key']);
try {
// 模拟配置
$this->mockConfig();
// 创建实际的华为支付客户端实例
$project_root = dirname(__DIR__, 4); // 获取项目根目录
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
echo " - 华为支付客户端实例创建成功\n";
// 尝试创建Pay实例
$payModel = new Pay($this->siteId);
// 测试关闭订单
$params = [
'out_trade_no' => 'TEST_CLOSE_' . time()
];
echo " ⚠️ 跳过实际关闭订单测试\n";
} catch (\Exception $e) {
echo " ⚠️ 关闭订单测试跳过: " . $e->getMessage() . "\n";
// 调用真实的关闭订单方法
$close_result = $huawei_pay_client->closeOrder($params);
echo " - 关闭订单方法调用成功\n";
echo " 结果: " . json_encode($close_result, JSON_UNESCAPED_UNICODE) . "\n";
} catch (Exception $e) {
echo " - 关闭订单测试失败: " . $e->getMessage() . "\n";
throw $e;
}
}
/**
* 测试退款方法
*/
public function testRefundMethod()
protected function testRefundMethod()
{
echo "测试退款方法...";
require_once dirname(__DIR__) . '/data/sdk/utils.php';
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
// 添加必要的配置
$site_id = '1';
$config_data = $this->config;
$config_data['site_id'] = $site_id;
// 使用文本模式的密钥,而不是证书文件
unset($config_data['private_key']);
unset($config_data['huawei_public_key']);
try {
// 模拟配置
$this->mockConfig();
// 创建实际的华为支付客户端实例
$project_root = dirname(__DIR__, 4); // 获取项目根目录
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
echo " - 华为支付客户端实例创建成功\n";
// 尝试创建Pay实例
$payModel = new Pay($this->siteId);
// 测试退款
$params = [
'out_trade_no' => 'TEST_REFUND_' . time(),
'out_request_no' => 'REFUND_' . time(),
'refund_amount' => 0.01,
'refund_reason' => '测试退款'
];
echo " ⚠️ 跳过实际退款测试\n";
} catch (\Exception $e) {
echo " ⚠️ 退款测试跳过: " . $e->getMessage() . "\n";
// 调用真实的退款方法
$refund_result = $huawei_pay_client->refund($params);
echo " - 退款方法调用成功\n";
echo " 结果: " . json_encode($refund_result, JSON_UNESCAPED_UNICODE) . "\n";
} catch (Exception $e) {
echo " - 退款测试失败: " . $e->getMessage() . "\n";
throw $e;
}
}
/**
* 测试查询订单方法
*/
public function testQueryOrderMethod()
protected function testQueryOrderMethod()
{
echo "测试查询订单方法...";
require_once dirname(__DIR__) . '/data/sdk/utils.php';
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
// 添加必要的配置
$site_id = '1';
$config_data = $this->config;
$config_data['site_id'] = $site_id;
// 使用文本模式的密钥,而不是证书文件
unset($config_data['private_key']);
unset($config_data['huawei_public_key']);
try {
// 模拟配置
$this->mockConfig();
// 创建实际的华为支付客户端实例
$project_root = dirname(__DIR__, 4); // 获取项目根目录
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
echo " - 华为支付客户端实例创建成功\n";
// 尝试创建Pay实例
$payModel = new Pay($this->siteId);
// 测试查询订单
$params = [
'out_trade_no' => 'TEST_QUERY_' . time()
];
echo " ⚠️ 跳过实际查询订单测试\n";
} catch (\Exception $e) {
echo " ⚠️ 查询订单测试跳过: " . $e->getMessage() . "\n";
// 调用真实的查询订单方法
$query_result = $huawei_pay_client->queryOrder($params);
echo " - 查询订单方法调用成功\n";
echo " 结果: " . json_encode($query_result, JSON_UNESCAPED_UNICODE) . "\n";
} catch (Exception $e) {
echo " - 查询订单测试失败: " . $e->getMessage() . "\n";
throw $e;
}
}
/**
* 模拟配置
* 测试回调验证方法
*/
private function mockConfig()
protected function testCallbackVerification()
{
// 这里可以添加更高级的模拟技术例如使用PHPUnit的mock对象
// 目前我们只需要确保配置数据能正确加载
echo "\n使用配置数据:\n";
echo "App ID: {$this->configData['app_id']}\n";
echo "商户号: {$this->configData['mch_id']}\n";
echo "证书ID: {$this->configData['mch_auth_id']}\n";
require_once dirname(__DIR__) . '/data/sdk/utils.php';
require_once dirname(__DIR__) . '/data/sdk/HuaweiPayClient.php';
// 添加必要的配置
$site_id = '1';
$config_data = $this->config;
$config_data['site_id'] = $site_id;
// 使用文本模式的密钥,而不是证书文件
unset($config_data['private_key']);
unset($config_data['huawei_public_key']);
try {
// 创建实际的华为支付客户端实例
$project_root = dirname(__DIR__, 4); // 获取项目根目录
$huawei_pay_client = new \addon\huaweipay\data\sdk\HuaweiPayClient($config_data, $project_root);
echo " - 华为支付客户端实例创建成功\n";
// 生成模拟回调参数并签名
$timestamp = date('Y-m-d H:i:s');
$callback_params = [
'out_trade_no' => 'TEST_CALLBACK_' . time(),
'trade_no' => 'HWPAY_' . time(),
'total_amount' => '0.01',
'trade_status' => 'SUCCESS',
'timestamp' => $timestamp,
'app_id' => $config_data['app_id'],
'merc_no' => $config_data['merc_no'],
'sign_type' => 'RSA2'
];
// 生成签名
$sign = '';
$signParams = $callback_params;
unset($signParams['sign']);
unset($signParams['sign_type']);
ksort($signParams);
$stringToSign = '';
foreach ($signParams as $key => $value) {
$stringToSign .= $key . '=' . $value . '&';
}
$stringToSign = rtrim($stringToSign, '&');
// 使用文本模式的私钥生成签名
$private_key_content = $config_data['private_key_text'];
// 对私钥进行格式化确保openssl_sign能够正确处理
$cleanContent = preg_replace('/\s+/', '', $private_key_content);
$cleanContent = preg_replace('/-----BEGIN.*?-----/', '', $cleanContent);
$cleanContent = preg_replace('/-----END.*?-----/', '', $cleanContent);
$formattedKey = "-----BEGIN PRIVATE KEY-----\n";
$length = strlen($cleanContent);
for ($i = 0; $i < $length; $i += 64) {
$formattedKey .= substr($cleanContent, $i, 64) . "\n";
}
$formattedKey .= "-----END PRIVATE KEY-----";
openssl_sign($stringToSign, $sign, $formattedKey, OPENSSL_ALGO_SHA256);
$callback_params['sign'] = base64_encode($sign);
// 使用华为支付客户端验证签名
$verify_result = $huawei_pay_client->verifySign($callback_params);
if ($verify_result) {
echo " - 回调签名验证通过\n";
echo " - 回调参数:" . json_encode($callback_params, JSON_UNESCAPED_UNICODE) . "\n";
echo " - 交易状态:{$callback_params['trade_status']}\n";
} else {
throw new Exception("回调签名验证失败");
}
} catch (Exception $e) {
echo " - 回调验证测试失败: " . $e->getMessage() . "\n";
throw $e;
}
}
}
// 如果直接运行此文件,则执行测试
if (basename(__FILE__) == basename($_SERVER['PHP_SELF'])) {
$test = new PayModelTest();
$test->runTests();
}
// 行测试
$test = new PayModelTest();
$test->runTests();