526 lines
17 KiB
PHP
Raw Normal View History

2025-10-17 17:18:15 +08:00
<?php
namespace addons\shopro\controller;
use addons\shopro\controller\Common;
use addons\shopro\library\ccblife\CcbRSA;
use addons\shopro\library\ccblife\CcbMD5;
use addons\shopro\library\ccblife\CcbUrlDecrypt;
use addons\shopro\library\ccblife\CcbHttpClient;
use addons\shopro\library\ccblife\CcbOrderService;
use addons\shopro\library\ccblife\CcbPaymentService;
use app\admin\model\shopro\order\Order as OrderModel;
use think\Db;
use think\Exception;
/**
* 建行生活测试控制器
*
* 用于测试和验证各个功能模块是否正常工作
*
* @author Billy
* @date 2025-01-17
*/
class Ccbtest extends Common
{
/**
* 不需要登录的方法
* @var array
*/
protected $noNeedLogin = ['*'];
/**
* 不需要权限的方法
* @var array
*/
protected $noNeedRight = ['*'];
/**
* 测试主页
* 展示所有可用的测试接口
*/
public function index()
{
$baseUrl = $this->request->domain() . '/addons/shopro/ccbtest';
$tests = [
'基础功能测试' => [
[
'name' => '测试RSA加密解密',
'url' => $baseUrl . '/testRsa',
'method' => 'GET',
'desc' => '测试RSA加密和解密功能是否正常'
],
[
'name' => '测试MD5签名',
'url' => $baseUrl . '/testMd5',
'method' => 'GET',
'desc' => '测试MD5签名生成功能'
],
[
'name' => '测试URL参数解密',
'url' => $baseUrl . '/testUrlDecrypt',
'method' => 'GET',
'desc' => '测试建行URL参数解密功能'
],
],
'订单功能测试' => [
[
'name' => '测试订单推送',
'url' => $baseUrl . '/testOrderPush?order_id=1',
'method' => 'GET',
'desc' => '测试推送订单到建行需要提供order_id'
],
[
'name' => '测试订单查询',
'url' => $baseUrl . '/testOrderQuery?order_sn=ORDER123',
'method' => 'GET',
'desc' => '测试查询建行订单状态需要提供order_sn'
],
[
'name' => '测试批量同步',
'url' => $baseUrl . '/testBatchSync',
'method' => 'GET',
'desc' => '测试批量同步未同步的订单'
],
],
'支付功能测试' => [
[
'name' => '测试生成支付串',
'url' => $baseUrl . '/testPaymentString?order_id=1',
'method' => 'GET',
'desc' => '测试生成建行支付串需要提供order_id'
],
[
'name' => '测试支付验证',
'url' => $baseUrl . '/testVerifyPayment?order_sn=ORDER123',
'method' => 'GET',
'desc' => '测试验证支付结果需要提供order_sn'
],
],
'用户功能测试' => [
[
'name' => '模拟用户登录',
'url' => $baseUrl . '/testUserLogin',
'method' => 'POST',
'desc' => '模拟建行用户登录流程',
'params' => [
'ccb_user_id' => 'ccb_test_user_001',
'mobile' => '13800138000'
]
],
],
'环境检查' => [
[
'name' => '检查配置',
'url' => $baseUrl . '/checkConfig',
'method' => 'GET',
'desc' => '检查建行配置是否正确'
],
[
'name' => '检查数据库',
'url' => $baseUrl . '/checkDatabase',
'method' => 'GET',
'desc' => '检查数据库表结构是否正确'
],
]
];
$this->success('建行生活接口测试', $tests);
}
/**
* 测试RSA加密解密
*/
public function testRsa()
{
try {
$config = config('ccblife');
// 测试数据
$testData = '这是一个测试字符串用于验证RSA加密解密功能是否正常工作。包含中文、English、数字123456和特殊字符!@#$%^&*()';
// 加密
$encrypted = CcbRSA::encrypt($testData, $config['public_key']);
// 解密
$decrypted = CcbRSA::decrypt($encrypted, $config['private_key']);
// 验证
$isSuccess = ($decrypted === $testData);
$result = [
'测试结果' => $isSuccess ? '成功' : '失败',
'原始数据' => $testData,
'加密后数据BASE64' => substr($encrypted, 0, 100) . '...',
'加密后长度' => strlen($encrypted),
'解密后数据' => $decrypted,
'数据一致性' => $isSuccess ? '✓ 一致' : '✗ 不一致'
];
$this->success('RSA加密解密测试完成', $result);
} catch (Exception $e) {
$this->error('RSA测试失败' . $e->getMessage());
}
}
/**
* 测试MD5签名
*/
public function testMd5()
{
try {
$config = config('ccblife');
// 测试API消息签名
$apiMessage = '{"TX_CODE":"A3341TP01","USER_ID":"test_user"}';
$apiSign = CcbMD5::signApiMessage($apiMessage, $config['private_key']);
// 测试支付串签名
$paymentResult = CcbMD5::generatePaymentSignature(
$config['merchant_id'],
$config['pos_id'],
$config['branch_id'],
'TEST_ORDER_' . time(),
'100.00',
$config['private_key'],
'01',
'530550'
);
$result = [
'API消息签名' => [
'原始消息' => $apiMessage,
'签名结果' => $apiSign,
'签名长度' => strlen($apiSign)
],
'支付串签名' => [
'支付串' => $paymentResult['payment_string'],
'MAC签名' => $paymentResult['mac'],
'参数列表' => $paymentResult['params']
]
];
$this->success('MD5签名测试完成', $result);
} catch (Exception $e) {
$this->error('MD5测试失败' . $e->getMessage());
}
}
/**
* 测试URL参数解密
*/
public function testUrlDecrypt()
{
try {
$config = config('ccblife');
// 模拟建行传递的加密参数
// 注意这里需要真实的ccbParamSJ参数才能测试
$ccbParamSJ = $this->request->get('ccbParamSJ', '');
if (empty($ccbParamSJ)) {
// 如果没有提供参数,生成一个测试用的
$testParams = [
'userid' => 'test_ccb_user_001',
'mobile' => '13800138000',
'openid' => 'test_openid_001'
];
$result = [
'提示' => '未提供ccbParamSJ参数无法进行实际解密测试',
'说明' => '请从建行App跳转时携带ccbParamSJ参数',
'服务方编号' => $config['service_id'],
'DES密钥前8位' => substr($config['service_id'], 0, 8),
'模拟数据' => $testParams
];
} else {
// 尝试解密
$decryptedParams = CcbUrlDecrypt::decrypt($ccbParamSJ, $config['service_id']);
$result = [
'解密结果' => $decryptedParams ? '成功' : '失败',
'原始参数' => $ccbParamSJ,
'解密数据' => $decryptedParams,
'服务方编号' => $config['service_id']
];
}
$this->success('URL参数解密测试', $result);
} catch (Exception $e) {
$this->error('URL解密测试失败' . $e->getMessage());
}
}
/**
* 测试订单推送
*/
public function testOrderPush()
{
try {
$orderId = $this->request->get('order_id', 1);
$orderService = new CcbOrderService();
$result = $orderService->pushOrder($orderId);
$this->success('订单推送测试完成', $result);
} catch (Exception $e) {
$this->error('订单推送失败:' . $e->getMessage());
}
}
/**
* 测试订单查询
*/
public function testOrderQuery()
{
try {
$orderSn = $this->request->get('order_sn', '');
if (empty($orderSn)) {
$this->error('请提供订单号参数 order_sn');
}
$orderService = new CcbOrderService();
$result = $orderService->queryOrder($orderSn);
$this->success('订单查询测试完成', $result);
} catch (Exception $e) {
$this->error('订单查询失败:' . $e->getMessage());
}
}
/**
* 测试批量同步
*/
public function testBatchSync()
{
try {
$orderService = new CcbOrderService();
$result = $orderService->batchSync(5); // 同步5个订单
$this->success('批量同步测试完成', $result);
} catch (Exception $e) {
$this->error('批量同步失败:' . $e->getMessage());
}
}
/**
* 测试生成支付串
*/
public function testPaymentString()
{
try {
$orderId = $this->request->get('order_id', 1);
$paymentService = new CcbPaymentService();
$result = $paymentService->generatePaymentString($orderId);
$this->success('支付串生成测试完成', $result);
} catch (Exception $e) {
$this->error('支付串生成失败:' . $e->getMessage());
}
}
/**
* 测试支付验证
*/
public function testVerifyPayment()
{
try {
$orderSn = $this->request->get('order_sn', '');
if (empty($orderSn)) {
$this->error('请提供订单号参数 order_sn');
}
$paymentService = new CcbPaymentService();
$isSuccess = $paymentService->verifyPayment($orderSn);
$result = [
'订单号' => $orderSn,
'支付状态' => $isSuccess ? '已支付' : '未支付',
'验证结果' => $isSuccess
];
$this->success('支付验证测试完成', $result);
} catch (Exception $e) {
$this->error('支付验证失败:' . $e->getMessage());
}
}
/**
* 模拟用户登录
*/
public function testUserLogin()
{
try {
$ccbUserId = $this->request->post('ccb_user_id', 'ccb_test_user_001');
$mobile = $this->request->post('mobile', '13800138000');
// 查询或创建用户
$user = Db::name('user')->where('ccb_user_id', $ccbUserId)->find();
if (!$user) {
// 创建测试用户
$userData = [
'ccb_user_id' => $ccbUserId,
'username' => 'test_' . substr(md5($ccbUserId), 0, 8),
'nickname' => '测试用户' . substr($ccbUserId, -4),
'mobile' => $mobile,
'avatar' => '/assets/img/avatar.png',
'status' => 'normal',
'salt' => \fast\Random::alnum(),
'password' => '',
'joinip' => $this->request->ip(),
'jointime' => time(),
'logintime' => time(),
'loginip' => $this->request->ip(),
'createtime' => time(),
'updatetime' => time()
];
// 设置随机密码
$userData['password'] = md5(md5(\fast\Random::alnum(32)) . $userData['salt']);
$userId = Db::name('user')->insertGetId($userData);
$user = Db::name('user')->where('id', $userId)->find();
}
// 生成Token
$this->auth->direct($user['id']);
$token = $this->auth->getToken();
$result = [
'用户ID' => $user['id'],
'建行用户ID' => $ccbUserId,
'手机号' => $mobile,
'Token' => $token,
'是否新用户' => !isset($userId) ? '否' : '是'
];
$this->success('用户登录测试成功', $result);
} catch (Exception $e) {
$this->error('用户登录测试失败:' . $e->getMessage());
}
}
/**
* 检查配置
*/
public function checkConfig()
{
try {
$config = config('ccblife');
$checks = [
'基础配置' => [
'收银台地址' => $config['cashier_url'] ?? '未配置',
'服务方编号' => $config['service_id'] ?? '未配置',
],
'商户信息' => [
'商户号' => $config['merchant_id'] ?? '未配置',
'POS号' => $config['pos_id'] ?? '未配置',
'分行号' => $config['branch_id'] ?? '未配置',
],
'密钥配置' => [
'私钥长度' => strlen($config['private_key'] ?? '') . ' 字符',
'公钥长度' => strlen($config['public_key'] ?? '') . ' 字符',
'私钥格式' => $this->validateKey($config['private_key'] ?? ''),
'公钥格式' => $this->validateKey($config['public_key'] ?? ''),
],
'交易代码' => $config['tx_codes'] ?? [],
'HTTP配置' => $config['http'] ?? [],
'安全配置' => $config['security'] ?? []
];
$this->success('配置检查完成', $checks);
} catch (Exception $e) {
$this->error('配置检查失败:' . $e->getMessage());
}
}
/**
* 检查数据库
*/
public function checkDatabase()
{
try {
$checks = [];
// 检查用户表
$userColumns = Db::query("SHOW COLUMNS FROM fa_user LIKE 'ccb_user_id'");
$checks['用户表(fa_user)'] = [
'ccb_user_id字段' => !empty($userColumns) ? '✓ 存在' : '✗ 不存在'
];
// 检查订单表
$orderColumns = Db::query("SHOW COLUMNS FROM fa_shopro_order WHERE Field IN ('ccb_user_id', 'ccb_pay_flow_id', 'ccb_sync_status', 'ccb_sync_time')");
$orderFields = array_column($orderColumns, 'Field');
$checks['订单表(fa_shopro_order)'] = [
'ccb_user_id字段' => in_array('ccb_user_id', $orderFields) ? '✓ 存在' : '✗ 不存在',
'ccb_pay_flow_id字段' => in_array('ccb_pay_flow_id', $orderFields) ? '✓ 存在' : '✗ 不存在',
'ccb_sync_status字段' => in_array('ccb_sync_status', $orderFields) ? '✓ 存在' : '✗ 不存在',
'ccb_sync_time字段' => in_array('ccb_sync_time', $orderFields) ? '✓ 存在' : '✗ 不存在',
];
// 检查支付日志表
$paymentLogExists = Db::query("SHOW TABLES LIKE 'fa_ccb_payment_log'");
$checks['支付日志表(fa_ccb_payment_log)'] = [
'表是否存在' => !empty($paymentLogExists) ? '✓ 存在' : '✗ 不存在'
];
// 检查同步日志表
$syncLogExists = Db::query("SHOW TABLES LIKE 'fa_ccb_sync_log'");
$checks['同步日志表(fa_ccb_sync_log)'] = [
'表是否存在' => !empty($syncLogExists) ? '✓ 存在' : '✗ 不存在'
];
// 统计数据
if (!empty($syncLogExists)) {
$syncStats = Db::name('ccb_sync_log')
->field('sync_status, COUNT(*) as count')
->group('sync_status')
->select();
$checks['同步统计'] = [];
foreach ($syncStats as $stat) {
$status = $stat['sync_status'] == 1 ? '成功' : '失败';
$checks['同步统计'][$status] = $stat['count'] . ' 条';
}
}
$this->success('数据库检查完成', $checks);
} catch (Exception $e) {
$this->error('数据库检查失败:' . $e->getMessage());
}
}
/**
* 验证密钥格式
*/
private function validateKey($key)
{
if (empty($key)) {
return '✗ 未配置';
}
// 检查是否为BASE64格式
if (base64_encode(base64_decode($key)) === $key) {
return '✓ BASE64格式';
}
return '✗ 格式异常';
}
}