PayPal交易处理函数故障:无法写入订单表及销毁会话
问题排查与修复方案
看起来你遇到的问题是因为代码里几个关键逻辑错误导致的:SQL插入失败、订单重复生成逻辑混乱,以及会话销毁不彻底。我帮你一步步拆解问题并给出修复方案:
核心问题分析
未定义的
$status变量导致SQL执行失败
你注释掉了$status = $_GET['st'];这行代码,但在插入orders表时依然使用了'{$status}',这会让SQL语句中的该值变成undefined,直接触发数据库错误,后续的session_destroy()也会因为代码中断而无法执行。订单插入逻辑完全错误
你把INSERT INTO orders放在了遍历购物车商品的循环内部,这意味着购物车里每有一件商品,就会插入一条重复的订单记录——一个PayPal交易应该对应唯一一条订单,多条商品对应多条reports记录才对。缺少防重复提交的核心校验
仅靠销毁会话不足以彻底防止重复提交,用户可能在会话销毁前刷新页面。正确的做法是利用PayPal返回的唯一交易IDtx,先检查orders表中是否已存在该交易,避免重复插入。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(); } ?>
关键修复点说明
- 恢复并正确使用
$status变量:重新获取PayPal返回的交易状态,确保SQL插入语句的完整性。 - 调整订单插入位置:将订单插入逻辑移到商品遍历循环外部,确保一个交易只生成一条订单记录。
- 添加交易唯一性校验:通过交易ID
tx检查订单是否已存在,从根源上防止重复提交。 - 彻底销毁会话:新增
clear_session()函数,同时清空$_SESSION、删除Cookie和销毁服务器会话,确保会话完全失效。 - 优化代码可读性:简化商品ID的截取逻辑,先收集商品信息再批量插入明细,逻辑更清晰。
内容的提问来源于stack exchange,提问作者weng tee
相关产品推荐
相关产品推荐

