如何根据变量将选中的数据行传递到不同页面
结论
return_option 必须先从表单或数据库中获取,不能直接写成:
if (`return_option` == 'Refund')
PHP 中的反引号用于执行系统命令,不表示变量或数据库字段。建议根据用户选中的 return_id 查询数据库,读取对应的 return_option,再将该记录的状态更新为 APPROVED。跳转时只传递记录 ID,由目标模块根据 ID 查询完整数据,并重新检查记录状态。
推荐实现
假设 returntable 包含以下字段:
return_idreturn_optionreturn_status
可以通过事务和预处理语句完成查询、更新及跳转:
<?php
if (isset($_POST['btnApprove'])) {
$selectedItem = filter_input(INPUT_POST, 'selectitemradio', FILTER_VALIDATE_INT);
if (!$selectedItem) {
exit('请选择有效的数据行');
}
mysqli_begin_transaction($db);
try {
// 锁定并读取选中的记录,避免处理过程中数据被其他请求修改
$selectStmt = mysqli_prepare(
$db,
'SELECT return_option
FROM returntable
WHERE return_id = ?
FOR UPDATE'
);
mysqli_stmt_bind_param($selectStmt, 'i', $selectedItem);
mysqli_stmt_execute($selectStmt);
mysqli_stmt_bind_result($selectStmt, $returnOption);
if (!mysqli_stmt_fetch($selectStmt)) {
throw new RuntimeException('找不到选中的数据行');
}
mysqli_stmt_close($selectStmt);
// 只允许预期的业务类型
if (!in_array($returnOption, ['Refund', 'Replacement'], true)) {
throw new RuntimeException('无效的 return_option');
}
$updateStmt = mysqli_prepare(
$db,
"UPDATE returntable
SET return_status = 'APPROVED'
WHERE return_id = ?"
);
mysqli_stmt_bind_param($updateStmt, 'i', $selectedItem);
mysqli_stmt_execute($updateStmt);
if (mysqli_stmt_affected_rows($updateStmt) < 1) {
throw new RuntimeException('记录未更新,可能已经是 APPROVED 状态');
}
mysqli_stmt_close($updateStmt);
mysqli_commit($db);
// 只传递记录 ID,目标模块自行读取完整数据
if ($returnOption === 'Refund') {
header(
'Location: payment-module.php?return_id=' .
urlencode((string) $selectedItem)
);
exit;
}
header(
'Location: delivery-module.php?return_id=' .
urlencode((string) $selectedItem)
);
exit;
} catch (Throwable $e) {
mysqli_rollback($db);
// 生产环境中建议记录详细异常,只向用户显示通用信息
error_log($e->getMessage());
exit('审批处理失败');
}
}
payment-module.php 和 delivery-module.php 是示例路径,请替换为项目中的实际地址。
目标模块如何接收数据
不建议在 URL 中传递整行数据。只需传递 return_id,目标模块再从数据库中读取最新记录。
Payment Module 可以按下面的方式处理:
<?php
$returnId = filter_input(INPUT_GET, 'return_id', FILTER_VALIDATE_INT);
if (!$returnId) {
exit('无效的 return_id');
}
$stmt = mysqli_prepare(
$db,
"SELECT return_id, return_option, return_status
FROM returntable
WHERE return_id = ?
AND return_status = 'APPROVED'
AND return_option = 'Refund'"
);
mysqli_stmt_bind_param($stmt, 'i', $returnId);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result(
$stmt,
$id,
$returnOption,
$returnStatus
);
if (!mysqli_stmt_fetch($stmt)) {
exit('记录不存在、尚未审批或不属于退款流程');
}
mysqli_stmt_close($stmt);
// 在这里执行 Payment Module 的后续处理
Delivery Module 的处理方式相同,但查询条件需要改为:
return_status = 'APPROVED'
AND return_option = 'Replacement'
即使 URL 中包含有效的 ID,目标模块也不能直接执行付款或发货,仍需重新检查记录状态和业务类型。
如果 selected_option 来自表单
如果页面已经提交了 selected_option,可以这样读取:
$selectedOption = $_POST['selected_option'] ?? null;
if ($selectedOption === 'Refund') {
// 跳转到 Payment Module
} elseif ($selectedOption === 'Replacement') {
// 跳转到 Delivery Module
} else {
exit('无效的 selected_option');
}
对应的表单控件可以写成:
<select name="selected_option" required>
<option value="Refund">Refund</option>
<option value="Replacement">Replacement</option>
</select>
但用户可以修改表单提交的数据。如果 return_option 已经保存在数据库中,审批时应以数据库记录为准,不能完全信任 $_POST['selected_option']。
原代码中的主要问题
return_option 不是有效的 PHP 变量
下面的写法是错误的:
if (`return_option` == 'Refund')
如果它是 PHP 变量,应写为:
if ($returnOption === 'Refund')
如果它是数据库字段,则要先通过 SELECT 查询取得字段值,然后再进行判断。
SQL 存在注入风险
直接拼接 SQL:
WHERE return_id = '$selectedItem'
可能引发 SQL 注入,也无法可靠处理非法输入。应改用预处理语句和参数绑定。
header() 前不能输出内容
原代码中的这行输出:
echo $selectedItem;
会让响应内容提前发送。之后再调用 header('Location: ...'),可能出现 “headers already sent” 错误。如果需要重定向,就不要在 header() 之前使用 echo、输出 HTML,或留下意外空白。
发送跳转响应后,还应立即执行:
exit;
不要使用极短时间的 refresh
下面的写法没有必要,也不可靠:
header("refresh: 0.0000000000000000000000001");
直接发送明确的重定向即可:
header('Location: payment-module.php?return_id=123');
exit;
付款、退款和发货属于敏感操作,还应加入登录权限检查、CSRF 防护、重复处理保护及操作日志。如果同一条记录只能审批一次,可以在 UPDATE 中加入原状态条件,防止重复审批:
UPDATE returntable
SET return_status = 'APPROVED'
WHERE return_id = ?
AND return_status = 'PENDING'
备注:内容仅供参考。
