无法将 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 结尾的地址。常见原因有:
- 用于生成支付路径的某个必填参数没有提交;
- 隐藏字段的
name与接口要求不一致; - 字段值为空,或者 PHP 变量尚未初始化;
- 表单
action拼接了一个空变量; - 支付平台要求订单号、商户号、交易类型或签名,但请求中缺少相应参数;
- 字段大小写与接口约定不一致。
可以在浏览器开发者工具的“网络”面板中查看实际发送的表单数据,同时检查渲染后的 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 必须保存在服务器端配置或安全的密钥管理系统中,不能输出到页面。签名结果能否出现在表单中,则要以支付网关的协议为准。
备注:内容仅供参考。
