PAYATHON 2026

如何根据变量将选中的数据行传递到不同页面

支付小周

结论

return_option 必须先从表单或数据库中获取,不能直接写成:

if (`return_option` == 'Refund')

PHP 中的反引号用于执行系统命令,不表示变量或数据库字段。建议根据用户选中的 return_id 查询数据库,读取对应的 return_option,再将该记录的状态更新为 APPROVED。跳转时只传递记录 ID,由目标模块根据 ID 查询完整数据,并重新检查记录状态。

推荐实现

假设 returntable 包含以下字段:

  • return_id
  • return_option
  • return_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'

备注:内容仅供参考。