PAYATHON 2026

oscommerce PostFinance 集成显示 unknown order/1/s

支付小周

结论

SHA-IN 和 SHA-OUT 使用相同的 passphrase 在技术上可行,但不建议这样配置。它们分别用于两个方向:

  • SHA-IN:验证 osCommerce 发往 PostFinance 的请求。
  • SHA-OUT:验证 PostFinance 返回给 osCommerce 的通知。
  • osCommerce 后台填写的 SHA-IN 和 SHA-OUT passphrase,应分别与 PostFinance 后台的对应配置一致。

后台填写的是 passphrase(密钥),不是计算后得到的 SHASIGN。如果把固定的摘要值当作 signature 填入后台,配置就是错误的。

unknown order/1/s 也不一定是 SHA 配置造成的。它还可能表示 osCommerce 找不到回调中的订单号,或者返回地址、参数传递、字符编码、重写规则破坏了请求。

正确的配置关系

建议为两个方向设置不同的随机字符串:

PostFinance SHA-IN passphrase  = osCommerce SHA-IN passphrase
PostFinance SHA-OUT passphrase = osCommerce SHA-OUT passphrase

不要把固定的 SHA 摘要填入对应字段:

SHA-IN field  = 固定的 SHA 摘要
SHA-OUT field = 固定的 SHA 摘要

SHASIGN 需要根据每次请求的参数动态计算。SHA-IN 和 SHA-OUT 即使暂时使用同一个 passphrase,只要双方配置完全一致,通常也不会因此单独失败。不过,使用不同密钥更方便判断问题出在哪个方向,也符合密钥隔离原则。

检查 SHA 算法

PostFinance 后台选择的摘要算法必须与 osCommerce 模块使用的算法一致。常见选项包括:

SHA-1
SHA-256
SHA-512

如果 PostFinance 配置的是 SHA-512,而模块仍调用 sha1(),生成的 SHASIGN 一定无法通过验证。

旧版 osCommerce/PostFinance 模块可能只实现了 SHA-1。实际支持哪些算法取决于模块版本,不能只修改后台配置而不检查模块代码。

SHA-IN 的计算方式

传统 PostFinance/Ogone 集成通常不会直接执行:

sha1($queryString . $passphrase);

一般需要先按参数名排序,再在每个非空参数后追加 SHA-IN passphrase。例如:

<?php

$params = [
    'AMOUNT'     => '1999',
    'CURRENCY'   => 'EUR',
    'LANGUAGE'   => 'en_US',
    'ORDERID'    => '100123',
    'PSPID'      => 'your_pspid',
];

$shaInPassphrase = 'your_sha_in_passphrase';

uksort($params, 'strnatcasecmp');

$plainText = '';

foreach ($params as $name => $value) {
    if ($value === '' || $value === null) {
        continue;
    }

    $plainText .= strtoupper($name) . '=' . $value . $shaInPassphrase;
}

$shaSign = strtoupper(hash('sha256', $plainText));

这里的 sha256 只是示例,必须换成 PostFinance 后台实际选择的算法:

$shaSign = strtoupper(hash('sha1', $plainText));
$shaSign = strtoupper(hash('sha256', $plainText));
$shaSign = strtoupper(hash('sha512', $plainText));

还要确认模块只计算 PostFinance 规定参与签名的字段。加入本地字段、空字段或实际没有发送的字段,都可能造成签名不一致。

SHA-OUT 的验证方式

收到 PostFinance 回调后,应该使用 SHA-OUT passphrase 重新计算摘要,再与返回的 SHASIGN 比较:

<?php

$shaOutPassphrase = 'your_sha_out_passphrase';
$receivedShaSign  = strtoupper($_POST['SHASIGN'] ?? '');

$params = $_POST;
unset($params['SHASIGN']);

uksort($params, 'strnatcasecmp');

$plainText = '';

foreach ($params as $name => $value) {
    if ($value === '' || $value === null) {
        continue;
    }

    // 实际项目中应只保留 PostFinance 规定参与 SHA-OUT 的字段
    $plainText .= strtoupper($name) . '=' . $value . $shaOutPassphrase;
}

$calculatedShaSign = strtoupper(hash('sha256', $plainText));

if (!hash_equals($calculatedShaSign, $receivedShaSign)) {
    throw new RuntimeException('Invalid PostFinance SHA-OUT signature');
}

不要直接对全部 $_POST 字段签名。不同接口版本允许参与 SHA-OUT 计算的字段可能不同,应以当前账户配置、模块实现和对应的接口文档为准。

排查 unknown order/1/s

1. 确认跳转前已经将订单写入数据库

有些模块在顾客跳转到 PostFinance 之前并未真正创建订单,回调时自然无法通过 ORDERID 查到记录。

先确认发送给 PostFinance 的订单号确实存在:

SELECT orders_id, customers_id, orders_status
FROM orders
WHERE orders_id = 100123;

如果 PostFinance 收到的订单号带有前缀或后缀,例如:

100123-1690000000

而回调代码直接使用整个字符串查询 orders_id,同样会出现 unknown order。发送订单号和解析订单号必须遵循同一套规则。

2. 记录原始回调参数

排查时可以记录参数名和订单号,但不要记录 passphrase、完整签名或支付卡数据:

error_log('PostFinance callback method: ' . $_SERVER['REQUEST_METHOD']);
error_log('PostFinance ORDERID: ' . ($_POST['orderID'] ?? $_GET['orderID'] ?? 'missing'));
error_log('PostFinance STATUS: ' . ($_POST['STATUS'] ?? $_GET['STATUS'] ?? 'missing'));

主要检查以下内容:

  • ORDERID 是否存在;
  • 参数是通过 POST 还是 GET 返回的;
  • 返回的订单号是否与发起支付时完全一致;
  • osCommerce 模块读取的参数名大小写是否正确;
  • 回调代码是否在验证签名前修改了参数值。

3. 检查返回 URL

PostFinance 后台配置的接受、拒绝、取消、异常和服务器通知 URL,都必须指向真正处理回调的 osCommerce 地址。

需要检查:

  • HTTP 和 HTTPS 是否一致;
  • 域名是否发生跳转;
  • URL 是否经过登录页或 Cookie 检查;
  • URL 重写是否删除了查询参数;
  • 反向代理是否改变了请求方法;
  • 动态回调地址是否被重定向到首页。

支付服务器通知不能依赖顾客浏览器中的 session。即使顾客关闭页面,服务器回调也应该能通过 ORDERID 独立找到订单。

4. 检查字符编码和参数规范化

计算 SHA 时使用的值必须与实际发送的值一致。以下任何变化都可能导致摘要不同:

空格与 +
& 与 &amp;
UTF-8 与其他编码
大小写变化
URL 编码前后的值
金额的小数格式
换行符

不要先对参数调用 htmlspecialchars() 再计算 SHA。例如,参数值中的 & 一旦变成 &amp;,签名也会随之改变。

5. 检查测试和生产环境

测试账户和生产账户通常使用独立配置。以下内容必须属于同一个环境:

  • PSPID;
  • SHA-IN passphrase;
  • SHA-OUT passphrase;
  • 摘要算法;
  • 支付提交地址;
  • 返回地址和服务器通知地址。

测试后台设置的 passphrase 不会自动同步到生产环境,不能假定两边配置相同。

推荐处理顺序

先在 PostFinance 后台分别设置新的 SHA-IN 和 SHA-OUT passphrase,再把对应值填入 osCommerce 模块,同时确认双方使用相同的摘要算法。然后创建一笔新的测试订单,记录发送的 ORDERID 以及回调收到的 ORDERID。

如果签名已经验证成功,但仍然出现 unknown order/1/s,接下来应检查订单创建时机、订单号解析和回调 URL,而不是继续反复修改 SHA 密钥。

备注:内容仅供参考。