You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PayPal交易处理函数故障:无法写入订单表及销毁会话

问题排查与修复方案

看起来你遇到的问题是因为代码里几个关键逻辑错误导致的:SQL插入失败、订单重复生成逻辑混乱,以及会话销毁不彻底。我帮你一步步拆解问题并给出修复方案:


核心问题分析

  1. 未定义的$status变量导致SQL执行失败
    你注释掉了$status = $_GET['st'];这行代码,但在插入orders表时依然使用了'{$status}',这会让SQL语句中的该值变成undefined,直接触发数据库错误,后续的session_destroy()也会因为代码中断而无法执行。

  2. 订单插入逻辑完全错误
    你把INSERT INTO orders放在了遍历购物车商品的循环内部,这意味着购物车里每有一件商品,就会插入一条重复的订单记录——一个PayPal交易应该对应唯一一条订单,多条商品对应多条reports记录才对。

  3. 缺少防重复提交的核心校验
    仅靠销毁会话不足以彻底防止重复提交,用户可能在会话销毁前刷新页面。正确的做法是利用PayPal返回的唯一交易IDtx,先检查orders表中是否已存在该交易,避免重复插入。

  4. Session销毁不彻底
    session_destroy()只会销毁服务器端的会话数据,但客户端的Session Cookie可能还存在,需要手动清空$_SESSION数组并删除Cookie,才能彻底终止会话。


修复后的process_transaction函数

<?php
function process_transaction() {
    // 先校验PayPal返回的核心参数是否完整
    if(!isset($_GET['tx'], $_GET['amt'], $_GET['cc'], $_GET['st'])) {
        redirect("index.php");
        exit;
    }

    $amount = $_GET['amt'];
    $currency = $_GET['cc'];
    $transaction = $_GET['tx'];
    $status = $_GET['st'];

    // 第一步:检查该交易是否已存在,彻底防止重复提交
    $check_query = query("SELECT order_id FROM orders WHERE order_transaction = '".escape_string($transaction)."'");
    confirm($check_query);
    if(mysqli_num_rows($check_query) > 0) {
        // 交易已存在,直接清除会话并跳转
        clear_session();
        redirect("thank_you.php");
        exit;
    }

    $total = 0;
    $item_quantity = 0;
    $order_items = [];

    // 先收集所有购物车商品信息,避免重复插入订单
    foreach ($_SESSION as $name => $value) {
        if($value > 0 && substr($name, 0, 8) == "product_") {
            $id = substr($name, 8); // 简化写法,无需计算字符串长度
            $query = query("SELECT * FROM products WHERE product_id = " . escape_string($id));
            confirm($query);
            $row = fetch_array($query);
            
            $product_price = $row['product_price'];
            $product_title = $row['product_title'];
            $sub = $product_price * $value;
            $item_quantity += $value;
            $total += $sub;

            // 保存商品信息,后续批量插入reports表
            $order_items[] = [
                'product_id' => $id,
                'product_title' => $product_title,
                'product_price' => $product_price,
                'product_quantity' => $value
            ];
        }
    }

    // 第二步:插入唯一的订单记录
    $send_order = query("INSERT INTO orders (order_amount, order_transaction, order_status, order_currency) 
                        VALUES('".escape_string($amount)."', '".escape_string($transaction)."', '".escape_string($status)."', '".escape_string($currency)."')");
    confirm($send_order);
    $last_id = last_id();

    // 第三步:插入所有商品的交易明细到reports表
    foreach($order_items as $item) {
        $insert_report = query("INSERT INTO reports (product_id, order_id, product_title, product_price, product_quantity) 
                                VALUES ('".escape_string($item['product_id'])."', '".escape_string($last_id)."', '".escape_string($item['product_title'])."', '".escape_string($item['product_price'])."', '".escape_string($item['product_quantity'])."')");
        confirm($insert_report);
    }

    // 彻底销毁会话,防止重复提交
    clear_session();
}

// 新增辅助函数:彻底清除会话(比单独用session_destroy更可靠)
function clear_session() {
    // 清空$_SESSION数组
    $_SESSION = [];
    // 删除客户端的Session Cookie(如果存在)
    if(isset($_COOKIE[session_name()])) {
        setcookie(session_name(), '', time() - 3600, '/');
    }
    // 销毁服务器端的会话数据
    session_destroy();
}
?>

关键修复点说明

  1. 恢复并正确使用$status变量:重新获取PayPal返回的交易状态,确保SQL插入语句的完整性。
  2. 调整订单插入位置:将订单插入逻辑移到商品遍历循环外部,确保一个交易只生成一条订单记录。
  3. 添加交易唯一性校验:通过交易IDtx检查订单是否已存在,从根源上防止重复提交。
  4. 彻底销毁会话:新增clear_session()函数,同时清空$_SESSION、删除Cookie和销毁服务器会话,确保会话完全失效。
  5. 优化代码可读性:简化商品ID的截取逻辑,先收集商品信息再批量插入明细,逻辑更清晰。

内容的提问来源于stack exchange,提问作者weng tee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:00:20