如何获取并存储支付回调 URL 中的参数
结论
不需要使用 cURL。支付服务商重定向到 pay_completed.php 后,PHP 会自动解析 URL 中的查询参数,可以直接通过 $_GET 读取:
$transaction = $_GET['transaction'] ?? null;
$orderId = $_GET['order_id'] ?? null;
以这个 URL 为例:
http://mywebsite.sa/pay_completed.php?transaction=284&order_id=
$transaction 的值是字符串 "284"。由于 URL 没有为 order_id 提供实际值,$orderId 是空字符串。
获取并检查参数
执行数据库操作前,先检查参数是否存在且不为空:
<?php
$transaction = trim($_GET['transaction'] ?? '');
$orderId = trim($_GET['order_id'] ?? '');
if ($transaction === '' || $orderId === '') {
http_response_code(400);
exit('缺少 transaction 或 order_id 参数');
}
// 参数有效后再执行后续处理
如果接口规定 transaction 必须是整数,还可以进一步验证:
<?php
$transaction = filter_input(INPUT_GET, 'transaction', FILTER_VALIDATE_INT);
$orderId = trim($_GET['order_id'] ?? '');
if ($transaction === false || $transaction === null) {
http_response_code(400);
exit('transaction 参数无效');
}
if ($orderId === '') {
http_response_code(400);
exit('order_id 参数为空');
}
如果支付服务商的交易号可能包含字母、连字符或其他字符,就不要使用 FILTER_VALIDATE_INT,而要按照接口文档规定的格式进行验证。
更新数据库
使用 PDO 预处理语句写入数据库,不要将 URL 参数直接拼接到 SQL 中:
<?php
$transaction = trim($_GET['transaction'] ?? '');
$orderId = trim($_GET['order_id'] ?? '');
if ($transaction === '' || $orderId === '') {
http_response_code(400);
exit('缺少必要参数');
}
$pdo = new PDO(
'mysql:host=localhost;dbname=payment;charset=utf8mb4',
'db_user',
'db_password',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
$stmt = $pdo->prepare(
'UPDATE orders
SET transaction_id = :transaction_id
WHERE order_id = :order_id'
);
$stmt->execute([
':transaction_id' => $transaction,
':order_id' => $orderId,
]);
if ($stmt->rowCount() === 0) {
// 可能是订单不存在,也可能是数据没有发生变化
http_response_code(404);
exit('未找到对应订单或订单无需更新');
}
echo '支付结果已处理';
请将数据库地址、账号、表名和字段名替换为项目的实际配置。在生产环境中,数据库凭据通常应保存在环境变量或受保护的配置文件中。
为什么不需要 cURL
cURL 用于主动向其他服务器发送 HTTP 请求。例如,服务器调用支付平台的查询接口确认交易状态时,可以使用 cURL。
这里的请求方向不同。支付平台已经向用户浏览器返回重定向地址,浏览器随后访问你的 pay_completed.php。PHP 会将 URL 中的查询参数自动解析到 $_GET,直接读取即可。
不要只凭重定向参数确认支付成功
用户可以修改浏览器地址栏中的参数,例如手动访问:
https://mywebsite.sa/pay_completed.php?transaction=284&order_id=123
所以,不能仅凭 transaction 和 order_id 就将订单标记为已支付。更可靠的处理流程是:
- 接收并验证参数。
- 如果支付平台支持签名验证,校验平台提供的签名。
- 或者由服务器调用支付平台的交易查询 API,核对交易状态、订单号、金额和币种。
- 确认交易成功后,再使用预处理语句更新数据库。
- 确保重复回调或刷新页面时,不会重复扣库存或记账。
如果支付服务商提供服务器端 webhook,应优先通过 webhook 处理支付状态,重定向页面只用于向用户展示结果。
示例 URL 中的 order_id 是空的:
&order_id=
这说明支付服务商没有返回该值,或者提交支付请求时没有正确传递订单号。PHP 无法从空参数中恢复订单号,需要检查支付 API 的请求字段、回调字段配置和支付服务商的接口文档。
备注:内容仅供参考。
