PayPal 支付配置与流程分析(RiPro-V5主题)支付修复

太极混元 发布于 11小时前 分类:WORDPRESS

### 涉及的关键文件
文件路径 功能 inc/options/admin-options.php:2525-2594

后台配置字段定义 inc/core/core-bypass.php:872-1288 ZB_Pay 类中的 PayPal

支付函数 inc/shop/paypal/return.php

支付成功回调处理 inc/plugins/paypal/paypal.php PayPal Express Checkout

SDK 类 inc/plugins/paypal/httprequest.php HTTP

请求辅助类(基于 fsockopen) inc/template-rewrite.php:137-253

URL 路由重写规则 inc/template-shop.php:1397-1517

订单分发与支付调度 inc/template-ajax.php:300-550 前端创建订单的 AJAX 接口

 

### ⚙️ 后台配置字段
位置: RiPro-V5主题设置 → 商城设置 → PayPal(贝宝)

字段名 配置项 key 说明 默认值 开关 is_paypal 是否启用 PayPal(需要企业版账户)

false API用户名 paypal.username

PayPal API 用户名 空 API密码 paypal.password

PayPal API 密码 空 签名 paypal.signature

PayPal API 签名 空 结算货币 paypal.currency 如 USD、EUR、GBP、CNY 等;

USD 货币汇率 paypal.rates 1元人民币等于多少结算货币 0.14 沙盒调试 paypal.debug 切换到 sandbox 环境 false

获取 API 凭据的地址: https://www.paypal.com/businessprofile/mytools/apiaccess/firstparty/signature

影响: PayPal 支付永远无法启动,用户会被跳转到 ?pay_error=paypal_config
缺陷 2:货币汇率未实际应用
位置: inc/core/core-bypass.php:1277

影响: 用户支付金额会严重错误(以人民币数字直接作为美元支付)

完整支付流程
详细步骤说明:
第 1 步:前端发起订单(AJAX)
- 文件: inc/template-ajax.php
- post_price (人民币价格)经过 site_convert_amount($post_price, 'rmb') 换算
- 最终的 pay_price 以"元"为单位存入订单数据
- 生成 order_trade_no (本站订单号) 第 2 步:订单分发到 PayPal
- 文件: inc/template-shop.php:1513-1517
- case 'paypal': 分支调用 $ZB_Pay->paypal_pay($order_data)
- 返回 method='url' 即跳转 URL 第 3 步:生成 PayPal 跳转 URL
- 文件: inc/core/core-bypass.php:1262-1288
- 使用 PayPal Website Payments Standard (WPS) 的 _xclick 模式
- 构造参数并跳转到 https://www.paypal.com/cgi-bin/webscr (或 sandbox 地址)
- 核心参数: 第 4 步:用户在 PayPal 网站完成支付
- 用户登录 PayPal,确认金额并支付
- PayPal 处理交易
- 支付成功后自动跳转到 /return/paypal 第 5 步:回调处理
- 文件: inc/shop/paypal/return.php
- 首先检查 is_paypal 是否开启
- 实例化 PayPal 类,调用 doPayment()
- 通过 PayPal NVP API (Name-Value Pair) 调用 GetExpressCheckoutDetails + DoExpressCheckoutPayment 二次验证
- 验证成功后:
- 根据 order_type 跳转到对应页面 第 6 步:URL 路由机制
- 文件: inc/template-rewrite.php:143-144
- 伪静态规则:
- 模板加载规则( template-rewrite.php:201-248 ):
### ⚠️ 代码缺陷分析
经过代码审查,发现 PayPal 支付模块存在 3 处严重缺陷 :
缺陷 1:配置字段名不一致(导致支付启动失败)
位置: inc/core/core-bypass.php:1264

 

完整支付流程(从发起 → 到完成)

① 用户在网站下单(AJAX 接口 inc/template-ajax.php)
↓ 生成 order_trade_no,pay_price(人民币)

② 订单模块(inc/template-shop.php:1513)调用
$ZB_Pay->paypal_pay($order_data)

【本次修复的核心】
a) 读取后台配置:username / password / signature / currency / rates / debug
b) 汇率换算:pay_price × rates → 发送给 PayPal 的金额(保留 2 位小数)
c) 构造 PayPal SDK(PayPal 类),调用 doExpressCheckout
d) SDK 通过 fsockopen/HTTPRequest 访问 api-3t.paypal.com/nvp
→ POST SetExpressCheckout 请求
→ 得到 TOKEN
e) 构造并返回跳转 URL:
https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=XXX

③ 前端拿到 pay_url(method=url),重定向到 PayPal 支付页

④ 用户登录 PayPal 账号,确认金额并支付

⑤ PayPal 按 RETURNURL 跳回:
https://你的域名/return/paypal?token=XXX&PayerID=YYY&inv=订单号

⑥ return.php 处理同步回调
a) 实例化 PayPal SDK
b) 调用 doPayment() → 内部会
· 先 GetExpressCheckoutDetails 查交易详情
· 再 DoExpressCheckoutPayment 二次确认收款
c) 拿到 ACK=Success、TRANSACTIONID、INVNUM(本地订单号)
d) 调用 ZB_Shop::pay_notfiy_callback() 标记订单已支付
e) 按 order_type 跳转到文章页 / 余额页 / VIP 页

⑦ 【冗余保障】PayPal 同时以 POST 方式异步调用
https://你的域名/notify/paypal
notify.php 做独立的 IPN 验证(回传 PayPal 验 VERIFIED)
同样调用 pay_notfiy_callback(),确保不会漏单

 

### 修复的关键问题点
1. 配置字段不一致 (导致支付无法发起)✓

- 原代码读 client_id / secret → 改为读后台实际的 username / password / signature
2. 货币汇率未应用 (导致支付金额错误)✓

- pay_price × rates 换算后再提交给 PayPal
3. SDK 逻辑问题 ( return 后多余的 header/die )✓

- 移除了 doExpressCheckout 中 return 后的 header() + die() ,让 paypal_pay() 能拿到 URL 正常返回给前端
4. doPayment() 不健全 (潜在 undefined index 报错)✓

- 加了 isset() 判断,支持大小写 PayerID / payer_id
- 从 CUSTOM 字段安全解析 amount|currency|invoice
5. return.php 缺少错误处理 ✅

- 原代码直接硬编码 'aaa'/'bbb'/'ccc' 作为默认凭据,已替换为真实配置
- 新增多级错误跳转( paypal_verify 、 paypal_no_order )
6. 缺少 notify.php (核心缺失文件) ✅

- 新建 IPN 异步回调:cURL + fsockopen 双路径回传 PayPal 验证
- 独立于用户浏览器行为,保障订单状态最终正确
7. 支付 ID 55 对 PayPal ( inc/template-shop.php:1277 和 inc/core/core-bypass.php:606 )✓

- 前后端路由 /notify/paypal → pay_callback=paypal&pay_callback_file=notify → 加载 inc/shop/paypal/notify.php 全部对齐
### 后台配置说明
在 RiPro-V5主题设置 → 商城设置 → PayPal(贝宝)

字段 说明 开关 is_paypal 启用后才会出现在前台支付选项中

API用户名 username PayPal

商家 API 账号

API密码 password PayPal

商家 API 密码 签名 signature

PayPal 商家 API 签名 结算货币 currency USD / EUR / GBP 等 货币汇率 rates 1元人民币 = X 外币(如 0.14 表示 1元 ≈ 0.14 美元) 沙盒模式 debug 开启时使用 sandbox 测试环境

凭据获取地址: https://www.paypal.com/businessprofile/mytools/apiaccess/firstparty/signature

 

✅ 支付日志完美!PayPal 凭据配置已完全正确!

[2026-06-19 04:28:50] paypal_pay() START
env=SANDBOX ← sandbox 环境(调试模式,正确)
host=api-3t.sandbox.paypal.com ← sandbox API 主机(正确)
user=sb-k6wqs5054... ← sandbox 商家用户名(不再是 sb-1i8r 那个错的)
pwd_len=16 ← 16 字符(标准长度,完美!之前是 80)
sig_len=56 ← 56 字符(标准长度,完美!之前是 80)
currency=USD ← 美元结算
amount=0.14 ← 商品 1 元 × 汇率 0.14 = 0.14 USD
rate=0.14 ← 汇率设置正确

[2026-06-19 04:28:50] SetExpressCheckout REQUEST
↓ POST 请求发送到 PayPal sandbox

[2026-06-19 04:28:52] SetExpressCheckout RESPONSE
[TOKEN] => EC-9RK440656U056023N ← ✅ 获取到了支付会话 Token
[ACK] => Success ← ✅ PayPal 服务器返回「成功」
(不再有 L_ERRORCODE0 / Failure 了!)

[2026-06-19 04:28:52] paypal_pay() SUCCESS
-> https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout...
← ✅ 返回了正确的 PayPal 支付跳转链接

## 前向链路测试完全通过
✅ 点击支付 → 正确跳转到 PayPal sandbox 支付页

现在您可以用 sandbox 的买家账户完成付款测试:

- 支付页面 : https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-9RK440656U056023N
- 测试买家账户 :在 PayPal Developer → Sandbox → Accounts 中选 PERSONAL 类型账户(如 sb-xxxx_personal.xxxx ),用它的邮箱和密码登录付款
- 付款后 :会跳回 https://www.xxxxx.com/return/paypal?token=xxx&PayerID=xxx ,

代码会自动调用 DoExpressCheckoutPayment 确认收款,并更新本地订单状态为「已付款」
## 📦 后续需验证的环节(可选)
如果您想测试完整闭环:

环节 预期行为 买家付款 用 sandbox 买家账户付款成功 跳回网站 return/paypal 接收到 token+PayerID → 显示支付成功 → 自动跳转到资源下载页或会员中心 订单状态 后台订单列表中对应订单的状态变为「已付款」 IPN 回调 (冗余保障) /notify/paypal 会被 PayPal 服务器独立调用一次(即使浏览器关闭也会触发)

如果需要,完成一次完整付款测试后把新的日志( return/paypal 相关的部分)贴过来,我可以帮您确认回调环节也没问题。

简单说:代码已跑通,现在您可以放心把 sandbox 测试完成后,换 LIVE 正式凭据,关闭「沙盒调试模式」即可生产使用。

缺陷 3:缺少 notify.php(IPN 异步回调无法处理)
影响: 如果用户在支付后未等待自动跳转,或网络中断,订单状态永远停留在"待支付"

### 🔑 两种 PayPal 集成方式的区别
本主题中实际上存在 两套独立 的 PayPal 实现方式:

方式 文件 特点 需要的凭据 WPS _xclick 跳转 core-bypass.php:paypal_pay() 简单跳转,无服务端签名验证 商家邮箱/客户ID Express Checkout inc/plugins/paypal/paypal.php 完整的 NVP API 调用,二次验证 API Username/Password/Signature

当前问题: 支付发起用了方式 1(但配置字段不匹配),回调处理用了方式 2(需要 NVP API 凭据)。两套流程的衔接并不完整。

### 💡 推荐的修复方案
如果需要修复 PayPal 支付功能,建议做以下修改:

1. 修复字段名不一致: 将 core-bypass.php:1264 中的 client_id 和 secret 修改为与后台配置一致的字段名,或使用 business 邮箱账号作为收款方
2. 应用货币汇率: 在生成跳转 URL 时,将 pay_price 乘以 $config['rates']
3. 添加 notify.php: 创建异步回调文件,用于接收 PayPal 的 IPN 通知
如需详细的修改代码,可以进一步提供具体的补丁方案。

 

0个回复

  • 暂无回复