如果你的网站是独立开发的 PHP 项目,接入过程并不复杂:创建支付,将客户跳转到 Payora,然后把支付结果带回自己的订单系统。无需 WooCommerce,也不用在一堆插件中折腾。
本指南将介绍如何把 Payora 接入自定义 PHP 网站,同时避免让结账流程变成一项复杂工程。作为一份PHP 网站 Payora 支付集成教程,你会了解 PHP 应该在什么位置发起支付、在哪个位置接收返回结果,以及应用应如何判断订单是已支付、待处理还是失败。
1. 确认自定义 PHP 网站的集成方式
首先要决定一件事:你要做的是简单的结账链接、服务端支付请求,还是带订单跟踪的完整支付流程?这几种方式并不相同。单页捐赠网站或许只需一个支付链接,而有 20 种商品的网店通常需要在客户离开网站前,由服务端创建订单。
对于自定义 PHP 网站,最清晰的做法通常是:先在本地创建订单,再由 PHP 创建 Payora 支付,然后将客户重定向到 Payora,最后接收返回结果并等待服务端确认。这样在资金转移前,你就已经有了订单记录。购物车和发票逻辑也能留在应用内部,放在它们该在的地方。
如果结账流程很简单,你可能只需要将客户重定向到 Payora 托管的支付页面。如果需要传递商品明细、客户备注或订单 ID,就应该在重定向前由 PHP 发送这些数据。简单,但不简陋。
来看一个实际例子:数字代理公司销售包含 3 个步骤的维护套餐,可以通过 PHP 创建订单、附上客户邮箱,并将客户跳转到带有发票编号的 Payora 支付页面。业余项目如果只销售一个许可证密钥,可能只需要支付链接和返回页面。两者的区别在于需要保留多少状态,而不在于代码量有多少。
2. 梳理具体页面、端点和会话流程
动手写代码前,先列出所需页面。至少需要三个:结账页面、返回页面,以及用于确认支付的服务端端点。如果跳过这一步,最后就只能靠猜来判断是哪一个请求改变了订单状态。猜错的代价可不小。
浏览器流程可以使用常规 PHP 会话,但不要只依赖会话。客户切换设备、关闭标签页,或过一段时间才从 Payora 返回时,会话状态都可能丢失。也要将订单 ID 存入数据库,这样即使浏览器会话不在了,PHP 代码仍能找到交易记录。
典型流程如下:
- 结账页面收集商品、邮箱和数量。
- PHP 创建本地订单,并将状态设为待处理。
- PHP 将客户跳转到 Payora。
- Payora 将浏览器带回你的网站返回 URL。
- 你的服务器检查支付状态后,再将订单标记为已支付。
这样一来,浏览器返回页面和服务端的实际状态就彼此独立了。很好,它们本来就应该分开。浏览器只能告诉你客户看到了什么;订单状态应该由服务器来判定。
养成一个小习惯,日后能省下好几个小时:创建支付后,立即将 Payora 支付参考号和订单 ID 一起保存。如果等到重定向之后再保存,网络错误或客户急着刷新页面,都可能导致订单已创建,却没有 Payora 参考号。到那时,你就得在生产环境里当侦探了。
3. 准备精简的 PHP 支付请求层
不要把支付代码写进模板。一个小型 PHP 类或辅助函数就足够了:一个方法构建请求数据,一个方法发送 HTTP 请求,还有一个方法解析响应。将这些逻辑分开很重要,因为支付逻辑的变动通常比页面标记更频繁。
例如,辅助函数可以接收包含 amount、currency、order_id 和 return_url 的数组,再从环境变量中读取 Payora 凭据并添加到请求里。结账页面不应该知道 API 令牌存在哪里,它只需要知道用户点了哪个按钮。
下面展示的是代码逻辑的大致结构,并非完整实现:
- 从数据库读取订单。
- 构建 Payora 请求数组。
- 使用 cURL 或类似的 HTTP 客户端发送请求。
- 保存 Payora 返回的支付参考号。
- 将客户重定向到 Payora 支付页面。
让这个辅助模块保持简单。简单的代码更容易测试。下个月调整商品价格或添加第二个结账表单时,简单的代码也不容易出问题。
如果应用中已经有支付抽象层,就直接使用。如果没有,可以新建一个命名清晰的文件,例如 PayoraClient.php。该文件只负责凭据、API 调用和响应解析,不要放其他内容。不要放 HTML、CSS,也不要放感谢消息。
4. 从自定义结账页面将客户跳转到 Payora
本地订单创建后,提交 Payora 支付请求,并将客户跳转到 Payora 支付页面。只有服务器保存订单后才能进行跳转,因为重定向一开始,用户就可能关闭标签页。
只传递实际需要的订单信息,通常包括订单 ID、金额、币种和客户邮箱。你也可以发送商品名称或内部账户 ID 等元数据,但不要因为数据库里有某个字段,就把它也一股脑塞进请求中。多余数据只会让支持人员之后核对记录时更困惑。
自定义结账页面通常会使用带有“立即支付”按钮的 POST 表单。表单提交到 PHP 端点后,由端点创建 Payora 支付,再返回重定向响应。客户不会看到 API 响应,只会看到 Payora 页面。
还要注意一点:不要相信客户端计算出的总价。如果商品页面显示 49 美元,而浏览器发送的是 39 美元,服务器必须拒绝不匹配的金额。创建支付请求时,应使用服务端订单总额,而不是表单中隐藏的数值。这条规则每次都适用。
如果你想更全面地了解支付设置方式,可以阅读《电商加密货币支付网关》指南,其中有一些实用背景信息,不会重复介绍这里的 PHP 流程。
5. 在自己的应用中接收并验证支付结果
浏览器返回 URL 很有用,但它不能作为最终依据。它可以告诉你客户访问过支付页面,也可能携带状态值,但在服务端确认之前,PHP 应用仍应将该结果视为暂定状态。待处理不等于已支付。
设计返回页面时要处理三种情况:成功、待处理和失败。如果 Payora 返回成功,就显示感谢页面,并告知用户订单正在确认。如果状态是待处理,就如实说明。如果支付失败,则邀请客户重试,同时保留订单记录。清晰的措辞能减少支持工单。
这里有一条实用原则:返回页面绝不能单独将订单创建或标记为已支付。它只应显示当前状态,必要时可以提供返回订单页面的链接。数据库更新应在验证之后进行,而不是在浏览器重定向后立即进行。这样的区别能避免意外重复更新。
返回端点应尽量简单明了,让人一眼就能看懂。如果收到 Payora 支付参考号,就根据它查询记录;如果缺少参考号,就记录请求并停止处理。如果订单已经支付,就显示友好提示,不要再做任何更改。这就是幂等流程能够从容应对重复刷新的方式。
如果团队还想对比结账侧的其他做法,可以阅读《如何接受加密货币付款》一文,其中有一些实用的账单处理说明,尤其适用于销售周期性服务或需要人工审批的业务。
6. 在标记订单为已支付前,由服务器确认交易
这是更安全的做法。PHP 应用应从服务端查询 Payora,并确认交易状态后再将订单设为已支付。浏览器重定向可能会遗漏信息,而服务端检查不会在意客户是否关闭了标签页、刷新了两次,或使用了另一台设备。要了解如何验证 Payora 支付状态,关键就是使用保存的支付参考号从服务端查询交易,并依据返回状态更新订单。
使用之前保存的 Payora 支付参考号,查询当前交易状态。将返回的状态与履约所需的状态进行比对。如果交易已结算或已确认,就更新订单;如果仍在处理中,就让订单保持待处理;如果交易失败或取消,则不要更改订单。
补充一点:很多自定义 PHP 网站正是在这一步掉以轻心。他们选择信任返回页面,因为这样写起来更快。确实更快,但并不更安全。花 5 秒钟验证一下,总比之后来回处理支持邮件要好。
如果 Payora 提供签名回调或服务端到服务端的确认机制,请将其与状态查询结合使用。这样就有两重检查:一重来自客户流程,另一重来自服务端流程。如果实现中需要逐步检查签名,可以参阅《如何测试加密货币支付》,了解上线前进行严格验证的做法。
只有服务器确认后,才能将订单标记为已支付。不要因为客户说已付款就更新,也不要因为浏览器这么说就更新。数据库应反映 Payora 确认的支付状态,因为之后履约和会计团队都要依赖这一状态。
7. 保存支付记录并处理重复提交
在数据库中保存 Payora 交易参考号、本地订单 ID、金额、币种和最终状态。如果可以,尽量一次性写入。日后客户发邮件说“我付了两次”时,你需要的是清晰的记录,而不是三次只完成了一半的更新。
重复提交通常是由一些很常见的原因引起的:客户点了两次、使用了浏览器的后退按钮,或者浏览器重试了请求。PHP 代码应检查订单是否已有 Payora 参考号;除非之前的交易失败或已过期,否则不要为同一订单再次创建支付。这正是幂等性的核心。
一个简单的规则就很好用:一个本地订单对应一笔有效的 Payora 交易。如果同一订单在第一笔交易仍待处理时收到第二个请求,就显示现有的 Payora 结账链接,而不是再创建一笔交易。如果订单已经支付,就什么也不做。安静地处理,本身就是一种优点。
数据库字段应当明确具体。例如,分别设置 payora_reference、payment_status、paid_at 和 last_checked_at。这些字段对支持、会计和调试都很有帮助。以后如果需要对账,只看这四个字段,就能回答大部分问题,不必花一个小时翻日志。
如果你在搭建的是客户发票流程,而不是网店结账流程,也可以阅读《自由职业者加密货币支付网关》一文,其中同样介绍了记录管理方式,尤其适用于发票编号比购物车更重要的场景。
8. 在网站的预发布副本上测试完整流程
上线前,先将网站复制到预发布环境,测试整个流程:创建订单、重定向到 Payora、返回页面、服务端验证,以及处理重复点击。如果只测试重定向,你只测完了问题的三分之一。
至少完成以下检查:
- 创建新订单,并确认 Payora 支付请求已生成。
- 将返回页面刷新 2 次,确认订单不会再次发生变化。
- 连续提交结账表单两次,确认只有 1 笔有效交易。
- 模拟待处理或失败结果,确认订单仍未支付。
- 检查保存的 Payora 参考号是否与数据库记录一致。
测试时要使用计划上线的准确 PHP 版本和服务器配置。在本地电脑上运行正常的流程,到了 SSL 配置更严格或 cURL 设置不同的生产服务器上可能就会失败。这种情况并不少见,确实会发生。
最后做一项实用测试:在无痕窗口中打开订单并完成支付,然后再用第二个浏览器打开同一个返回 URL。应用不应再次更新支付状态。如果出现了重复更新,就先修好再上线,没有例外。
如果团队除了其他支付方式外,还提供 USDC 结账选项,可以参考《如何接受 USDC 付款》中的说明,了解客户对此类支付方式的预期,再决定是否将 PHP 流程部署到生产环境。
最后要确认的是:同一个订单在经历一次重定向、一次刷新和一次服务端确认后,状态仍能保持同步。如果这一点没问题,你的自定义 PHP 结账流程就可以迎接第一笔真实支付了。




Comments