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 '✗ 格式异常'; } }