From 267a76bd2c5d1642966f3691c86b2c71a039ea9c Mon Sep 17 00:00:00 2001 From: Billy <641833868@qq.com> Date: Mon, 27 Oct 2025 17:12:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/shopro/config/ccblife.php | 16 +-- addons/shopro/library/ccblife/CcbMD5.php | 104 ------------------ .../library/ccblife/CcbPaymentService.php | 54 +++------ 3 files changed, 21 insertions(+), 153 deletions(-) diff --git a/addons/shopro/config/ccblife.php b/addons/shopro/config/ccblife.php index 0f96fd1..ee3a67a 100644 --- a/addons/shopro/config/ccblife.php +++ b/addons/shopro/config/ccblife.php @@ -88,19 +88,19 @@ return [ /** * 支付位图 - 控制支付方式 - * 格式: 6位字符串,每位对应一个支付方式(1=开启,0=关闭) - * 位置: [生活钱包][龙支付][微信][数字人民币][信用付][快贷] - * 示例: '111111' = 全部开启, '110000' = 仅生活钱包和龙支付 + * 格式: ⚠️ 必须是10位数字字符串(文档强制要求) + * 位置: [生活钱包][龙支付][微信][数字人民币][信用付][快贷][保留][保留][保留][保留] + * 示例: '1111110000' = 前6种支付方式全开启, '1100000000' = 仅生活钱包和龙支付 */ - 'pay_bitmap' => Env::get('ccb.pay_bitmap', '110000'), + 'pay_bitmap' => Env::get('ccb.pay_bitmap',''), /** * 账户位图 - 控制支付账户类型 - * 格式: 5位字符串,每位对应一个账户类型(1=开启,0=关闭) - * 位置: [建行借记卡][建行贷记卡][他行借记卡][他行贷记卡][建行钱包] - * 示例: '11111' = 全部开启, '11000' = 仅建行卡 + * 格式: ⚠️ 必须是10位数字字符串(文档强制要求) + * 位置: [建行借记卡][建行贷记卡][他行借记卡][他行贷记卡][建行钱包][保留][保留][保留][保留][保留] + * 示例: '1111100000' = 前5种账户全开启, '1100000000' = 仅建行借记卡和贷记卡 */ - 'account_bitmap' => Env::get('ccb.account_bitmap', '11000'), + 'account_bitmap' => Env::get('ccb.account_bitmap',''), /** * 分期付款期数 diff --git a/addons/shopro/library/ccblife/CcbMD5.php b/addons/shopro/library/ccblife/CcbMD5.php index fcab0e1..3694812 100644 --- a/addons/shopro/library/ccblife/CcbMD5.php +++ b/addons/shopro/library/ccblife/CcbMD5.php @@ -46,110 +46,6 @@ class CcbMD5 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); - } /** * 生成交易流水号 diff --git a/addons/shopro/library/ccblife/CcbPaymentService.php b/addons/shopro/library/ccblife/CcbPaymentService.php index d185d01..a4eafa0 100644 --- a/addons/shopro/library/ccblife/CcbPaymentService.php +++ b/addons/shopro/library/ccblife/CcbPaymentService.php @@ -115,8 +115,8 @@ class CcbPaymentService $macParams['REGINFO'] = ''; // 客户注册信息(空字符串) // 商品信息(escape编码) - $proinfo = $this->buildProductInfo($order); - $macParams['PROINFO'] = $proinfo; +// $proinfo = $this->buildProductInfo($order); + $macParams['PROINFO'] = ''; $macParams['REFERER'] = ''; // 商户URL(空字符串) @@ -252,6 +252,17 @@ class CcbPaymentService // 4. 生成MAC签名(32位小写MD5) $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: ' . $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; - } - /** * 处理支付回调 * 建行支付完成后的同步回调