PAYATHON 2026

无法将 PHP 变量传递给 E-payment 隐藏输入字段

支付小周

结论

PHP 变量可以直接写入隐藏字段,写法如下:

<input
    type="hidden"
    name="Amount"
    value="<?= htmlspecialchars($Amount, ENT_QUOTES, 'UTF-8') ?>"
>

如果服务器收到的金额仍为空,可以依次检查:

  • $Amount 是否在输出表单前完成赋值;
  • name="Amount" 与 $_POST['Amount'] 的大小写是否完全一致;
  • 页面是否由 PHP 解析,而不是直接作为普通 HTML 文件打开;
  • 表单是否分两次提交,第一次提交给当前 PHP 页面进行验证,第二次才提交给支付网关;
  • 支付接口要求的字段名、表单 action 和签名参数是否正确。

/payment/null 这个 404 通常表示支付平台收到的某个必填路由参数、订单参数或跳转参数是 null,未必由金额字段直接引起。具体原因要结合支付接口文档和浏览器实际提交的数据判断。

正确输出 PHP 变量

不能把变量名当作普通字符串写进 HTML:

<input type="hidden" name="Amount" value="$Amount">

这里的 $Amount 不会自动执行。需要使用 PHP 输出语法:

<input
    type="hidden"
    name="Amount"
    value="<?= htmlspecialchars($Amount, ENT_QUOTES, 'UTF-8') ?>"
>

也可以使用完整写法:

<input
    type="hidden"
    name="Amount"
    value="<?php echo htmlspecialchars($Amount, ENT_QUOTES, 'UTF-8'); ?>"
>

htmlspecialchars() 可以防止变量中的引号或特殊字符破坏 HTML 属性。即使金额已被限制为整数,输出时保留转义也更稳妥。

注意变量名大小写

PHP 变量区分大小写:

$Amount
$amount

这是两个不同的变量。HTML 表单字段名和服务器端读取的名称也要一致:

$_POST['Amount']

对应:

<input name="Amount">

如果表单中使用:

<input name="amount">

服务器端就要读取:

$_POST['amount']

最好统一命名方式,例如全部使用小写:

$amount = '';
$amountError = '';

$inputAmount = trim($_POST['amount'] ?? '');

完整处理示例

假设用户先将金额提交到当前页面,验证通过后再显示支付表单,可以这样处理:

<?php

$amount = '';
$amountError = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $inputAmount = trim($_POST['amount'] ?? '');

    if ($inputAmount === '') {
        $amountError = 'Please enter the amount.';
    } elseif (!ctype_digit($inputAmount) || (int) $inputAmount <= 0) {
        $amountError = 'Please enter a positive integer value.';
    } else {
        $amount = $inputAmount;
    }
}

?>

金额输入表单:

<form method="post" action="">
    <label for="amount">Amount</label>

    <input
        id="amount"
        type="text"
        name="amount"
        value="<?= htmlspecialchars($amount, ENT_QUOTES, 'UTF-8') ?>"
    >

    <?php if ($amountError !== ''): ?>
        <p><?= htmlspecialchars($amountError, ENT_QUOTES, 'UTF-8') ?></p>
    <?php endif; ?>

    <button type="submit">Continue</button>
</form>

验证成功后,再输出或启用提交到支付平台的表单:

<?php if ($amountError === '' && $amount !== ''): ?>
    <form method="post" action="https://payment.example.com/payment">
        <input
            type="hidden"
            name="Amount"
            value="<?= htmlspecialchars($amount, ENT_QUOTES, 'UTF-8') ?>"
        >

        <input
            type="hidden"
            name="MerchantId"
            value="<?= htmlspecialchars($merchantId, ENT_QUOTES, 'UTF-8') ?>"
        >

        <input
            type="hidden"
            name="OrderId"
            value="<?= htmlspecialchars($orderId, ENT_QUOTES, 'UTF-8') ?>"
        >

        <input
            type="hidden"
            name="Signature"
            value="<?= htmlspecialchars($signature, ENT_QUOTES, 'UTF-8') ?>"
        >

        <button type="submit">Pay</button>
    </form>
<?php endif; ?>

这里的字段名称仅作示例。实际字段的大小写、金额单位和必填参数,都要以支付平台的接口文档为准。

为什么可能出现 /payment/null

下面的错误:

HTTP Status 404 - /b2cDemo/eng/payment/null

表示支付平台最终访问了一个以 null 结尾的地址。常见原因有:

  1. 用于生成支付路径的某个必填参数没有提交;
  2. 隐藏字段的 name 与接口要求不一致;
  3. 字段值为空,或者 PHP 变量尚未初始化;
  4. 表单 action 拼接了一个空变量;
  5. 支付平台要求订单号、商户号、交易类型或签名,但请求中缺少相应参数;
  6. 字段大小写与接口约定不一致。

可以在浏览器开发者工具的“网络”面板中查看实际发送的表单数据,同时检查渲染后的 HTML。隐藏字段最终应类似:

<input type="hidden" name="Amount" value="100">

如果源代码中仍能看到 PHP 代码:

value="<?= $amount ?>"

说明文件没有经过 PHP 解释器处理。请确认文件使用 .php 扩展名,并通过支持 PHP 的 Web 服务器访问。

不要信任隐藏字段中的金额

隐藏字段只是在界面上不可见。用户仍可通过开发者工具、代理软件或直接构造 HTTP 请求修改它,因此不能把其中的金额当作最终可信金额。

更安全的做法是只向浏览器传递订单标识:

<input
    type="hidden"
    name="order_id"
    value="<?= htmlspecialchars($orderId, ENT_QUOTES, 'UTF-8') ?>"
>

提交支付请求前,服务器根据订单标识重新查询真实金额:

$order = findOrderById($orderId);

if ($order === null || $order['user_id'] !== $currentUserId) {
    throw new RuntimeException('Invalid order.');
}

$amount = $order['amount'];

金额还应以整数形式保存为最小货币单位。例如,10.25 元可以表示为 1025 分,以免遇到浮点数精度问题。

支付完成后,也不能只相信浏览器跳转页面中的“支付成功”参数。服务器还要验证支付平台的服务端回调、签名、订单号、商户号、金额和支付状态,并对重复回调进行幂等处理。

商户信息能否出现在 HTML 中

是否安全,要看具体的信息类型。

通常可以放在前端的内容包括:

  • 商户编号;
  • 订单编号;
  • 支付金额;
  • 支付接口地址;
  • 支付平台明确规定为公开参数的字段。

不能放入 HTML 的内容包括:

  • 商户私钥;
  • API Secret;
  • 签名密钥;
  • 数据库密码;
  • 支付平台后台密码;
  • 可以直接换取访问令牌的凭证。

即使商户编号可以公开,也不能依靠“隐藏字段”保护它。发送到浏览器的所有内容都应视为公开信息。签名需要在服务器端使用密钥生成,浏览器只接收生成后的签名值:

$signature = createPaymentSignature($paymentData, $merchantSecret);

$merchantSecret 必须保存在服务器端配置或安全的密钥管理系统中,不能输出到页面。签名结果能否出现在表单中,则要以支付网关的协议为准。

备注:内容仅供参考。