代码优化

This commit is contained in:
Billy 2025-10-27 17:12:05 +08:00
parent cd983a25c3
commit 267a76bd2c
3 changed files with 21 additions and 153 deletions

View File

@ -88,19 +88,19 @@ return [
/** /**
* 支付位图 - 控制支付方式 * 支付位图 - 控制支付方式
* 格式: 6位字符串,每位对应一个支付方式(1=开启,0=关闭) * 格式: ⚠️ 必须是10位数字字符串(文档强制要求)
* 位置: [生活钱包][龙支付][微信][数字人民币][信用付][快贷] * 位置: [生活钱包][龙支付][微信][数字人民币][信用付][快贷][保留][保留][保留][保留]
* 示例: '111111' = 开启, '110000' = 仅生活钱包和龙支付 * 示例: '1111110000' = 前6种支付方式全开启, '1100000000' = 仅生活钱包和龙支付
*/ */
'pay_bitmap' => Env::get('ccb.pay_bitmap', '110000'), 'pay_bitmap' => Env::get('ccb.pay_bitmap',''),
/** /**
* 账户位图 - 控制支付账户类型 * 账户位图 - 控制支付账户类型
* 格式: 5位字符串,每位对应一个账户类型(1=开启,0=关闭) * 格式: ⚠️ 必须是10位数字字符串(文档强制要求)
* 位置: [建行借记卡][建行贷记卡][他行借记卡][他行贷记卡][建行钱包] * 位置: [建行借记卡][建行贷记卡][他行借记卡][他行贷记卡][建行钱包][保留][保留][保留][保留][保留]
* 示例: '11111' = 开启, '11000' = 仅建行 * 示例: '1111100000' = 前5种账户全开启, '1100000000' = 仅建行借记卡和贷记
*/ */
'account_bitmap' => Env::get('ccb.account_bitmap', '11000'), 'account_bitmap' => Env::get('ccb.account_bitmap',''),
/** /**
* 分期付款期数 * 分期付款期数

View File

@ -46,110 +46,6 @@ class CcbMD5
return $expectedSignature === strtoupper($signature); return $expectedSignature === strtoupper($signature);
} }
/**
* 生成支付字符串签名
*
* ⚠️ 注意建行收银台支付串签名使用小写MD5
* 签名规则MD5(支付参数按顺序拼接 + 商户私钥) 保持小写
*
* 示例:
* paymentString = 'MERCHANTID=xxx&POSID=xxx&...&TIMEOUT=xxx' + privateKey
* mac = md5(paymentString) // 小写
*
* @param array $params 支付参数
* @param string $privateKey 商户私钥
* @return string 小写的32位MD5签名
*/
public static function signPaymentString($params, $privateKey)
{
// 构建支付字符串(按照建行要求的顺序)
$fields = [
'MERCHANTID',
'POSID',
'BRANCHID',
'ORDERID',
'PAYMENT',
'CURCODE',
'TXCODE',
'REMARK1',
'REMARK2',
'TIMEOUT'
];
$parts = [];
foreach ($fields as $field) {
$value = isset($params[$field]) ? $params[$field] : '';
$parts[] = $field . '=' . $value;
}
// 拼接支付字符串并添加私钥
$paymentString = implode('&', $parts) . $privateKey;
// 计算MD5保持小写建行要求
return md5($paymentString);
}
/**
* 根据完整技术方案生成标准支付字符串签名
* 按照文档要求的格式生成签名
*
* @param string $merchantId 商户号
* @param string $posId POS号
* @param string $branchId 分行号
* @param string $orderId 订单号
* @param string $payment 支付金额
* @param string $privateKey 商户私钥
* @param string $curCode 币种默认01人民币
* @param string $txCode 交易码默认530550
* @param string $timeout 超时时间,默认空
* @return array 包含支付字符串和签名
*/
public static function generatePaymentSignature($merchantId, $posId, $branchId, $orderId, $payment, $privateKey, $curCode = '01', $txCode = '530550', $timeout = '')
{
// 构建支付参数
$params = [
'MERCHANTID' => $merchantId,
'POSID' => $posId,
'BRANCHID' => $branchId,
'ORDERID' => $orderId,
'PAYMENT' => $payment,
'CURCODE' => $curCode,
'TXCODE' => $txCode,
'REMARK1' => '',
'REMARK2' => '',
'TIMEOUT' => $timeout
];
// 生成签名
$mac = self::signPaymentString($params, $privateKey);
// 构建完整的支付字符串(不包含私钥)
$fields = [];
foreach ($params as $key => $value) {
$fields[] = $key . '=' . $value;
}
$paymentString = implode('&', $fields);
return [
'payment_string' => $paymentString,
'mac' => $mac,
'params' => $params
];
}
/**
* 验证支付字符串签名
*
* @param array $params 支付参数
* @param string $mac 待验证的MAC值
* @param string $privateKey 商户私钥
* @return bool 签名是否有效
*/
public static function verifyPaymentSignature($params, $mac, $privateKey)
{
$expectedMac = self::signPaymentString($params, $privateKey);
return $expectedMac === strtolower($mac);
}
/** /**
* 生成交易流水号 * 生成交易流水号

View File

@ -115,8 +115,8 @@ class CcbPaymentService
$macParams['REGINFO'] = ''; // 客户注册信息(空字符串) $macParams['REGINFO'] = ''; // 客户注册信息(空字符串)
// 商品信息escape编码 // 商品信息escape编码
$proinfo = $this->buildProductInfo($order); // $proinfo = $this->buildProductInfo($order);
$macParams['PROINFO'] = $proinfo; $macParams['PROINFO'] = '';
$macParams['REFERER'] = ''; // 商户URL空字符串 $macParams['REFERER'] = ''; // 商户URL空字符串
@ -252,6 +252,17 @@ class CcbPaymentService
// 4. 生成MAC签名32位小写MD5 // 4. 生成MAC签名32位小写MD5
$mac = strtolower(md5($macSignString)); $mac = strtolower(md5($macSignString));
// ⚠️ 调试输出:输出完整签名字符串用于排查
Log::info('[建行支付] ========== 完整MAC签名字符串 ==========');
Log::info('[建行支付] ' . $macSignString);
Log::info('[建行支付] ========== 生成的MAC签名 ==========');
Log::info('[建行支付] ' . $mac);
Log::info('[建行支付] ========== 参数详情 ==========');
Log::info('[建行支付] 参数数量: ' . count($macParams));
foreach ($macParams as $key => $value) {
Log::info('[建行支付] ' . $key . ' = ' . (strlen($value) > 100 ? substr($value, 0, 100) . '...(共' . strlen($value) . '字符)' : $value));
}
Log::info('[建行支付] MAC签名字符串(前500字符): ' . mb_substr($macSignString, 0, 500)); Log::info('[建行支付] MAC签名字符串(前500字符): ' . mb_substr($macSignString, 0, 500));
Log::info('[建行支付] 生成MAC: ' . $mac); Log::info('[建行支付] 生成MAC: ' . $mac);
@ -482,45 +493,6 @@ class CcbPaymentService
} }
} }
/**
* 格式化公钥为PEM格式
*
* 支持三种输入格式:
* 1. PEM格式已包含BEGIN/END标记
* 2. BASE64格式不含PEM头尾
* 3. 十六进制格式DER编码的十六进制字符串
*
* @param string $publicKey 公钥PEM/BASE64/HEX格式
* @return string PEM格式的公钥
*/
private function formatPublicKeyToPem($publicKey)
{
// 移除可能存在的空格和换行
$publicKey = preg_replace('/\s+/', '', $publicKey);
// 如果已经是PEM格式直接返回
if (strpos($publicKey, '-----BEGIN PUBLIC KEY-----') !== false) {
return $publicKey;
}
// ✅ 判断是否为十六进制格式只包含0-9a-fA-F字符
if (ctype_xdigit($publicKey)) {
// 十六进制格式 → 解码为二进制 → 转BASE64
$binaryKey = hex2bin($publicKey);
if ($binaryKey === false) {
throw new \Exception('十六进制公钥解码失败');
}
$publicKey = base64_encode($binaryKey);
}
// 转换为PEM格式
$pem = "-----BEGIN PUBLIC KEY-----\n";
$pem .= rtrim(chunk_split($publicKey, 64, "\n"), "\n") . "\n";
$pem .= "-----END PUBLIC KEY-----\n";
return $pem;
}
/** /**
* 处理支付回调 * 处理支付回调
* 建行支付完成后的同步回调 * 建行支付完成后的同步回调