INSERT ON DUPLICATE KEY插入异常:仅app_id写入,其余字段失效
问题分析与修复方案
咱们直接拆解你遇到的问题:INSERT时仅app_id字段写入数据,UPDATE功能正常,核心问题出在变量作用域、代码执行顺序上,还有几处隐藏小bug需要修正,下面一步步来梳理:
1. 核心问题:$pptimg变量的作用域与执行逻辑
看你的代码结构,INSERT/UPDATE语句写在了if($_POST)代码块的外面——这意味着不管用户有没有提交表单(有没有上传文件),这条SQL都会执行:
- 当首次插入(app_id不存在):如果用户是直接打开页面(无POST请求),或者上传过程出错导致
$pptimg未被赋值,此时$pptimg要么是未定义的空值,要么是空字符串,所以INSERT时只有app_id有值,pptimg字段为空。 - 当更新(app_id已存在):用户是通过上传表单提交POST请求,此时
$pptimg在if($_POST)块内被正确赋值,所以UPDATE能正常写入pptimg字段。
2. 其他隐藏bug
- 文件大小检查时,你写的是
$_FILES["fileToUpload"]["size"],但全程文件变量都是$_FILES["file"],变量名写错会导致大小检查永远失效。 - 存在严重SQL注入风险:直接把
$appid和$pptimg拼接到SQL语句中,恶意用户可构造参数攻击数据库。 - 上传文件名直接用原文件名,若用户上传同名文件会覆盖原有文件,存在数据丢失风险。
修复后的完整代码
<?php session_start(); $appid = $_GET['appid'] ?? ''; // 增加空值判断,避免未定义变量警告 include("connect.php"); // 仅当有POST提交且存在上传文件时,才执行后续逻辑 if($_POST && isset($_FILES["file"])) { $target_dir = "upload/"; // 给文件名添加时间戳,避免同名文件覆盖 $file_name = time() . "_" . basename($_FILES["file"]["name"]); $target_file = $target_dir . $file_name; $uploadOk = 1; $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION)); // 验证是否为真实图片 if(isset($_POST["submit"])) { $check = getimagesize($_FILES["file"]["tmp_name"]); if($check !== false) { echo "File is an image - " . $check["mime"] . "."; $uploadOk = 1; } else { echo "File is not an image."; $uploadOk = 0; } } // 检查文件是否已存在 if (file_exists($target_file)) { echo "Sorry, file already exists."; $uploadOk = 0; } // 检查文件大小(修正变量名错误) if ($_FILES["file"]["size"] > 500000) { echo "Sorry, your file is too large."; $uploadOk = 0; } // 限制允许的文件格式 if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg" && $imageFileType != "gif" ) { echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed."; $uploadOk = 0; } // 执行上传与数据库操作 if ($uploadOk == 0) { echo "Sorry, your file was not uploaded."; } else { if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) { echo "The file ". basename( $_FILES["file"]["name"]). " has been uploaded."; $pptimg = $file_name; $_SESSION['pptimg'] = $pptimg; // 使用预处理语句,彻底避免SQL注入 $query = "INSERT INTO payments (app_id, pptimg) VALUES(?, ?) ON DUPLICATE KEY UPDATE pptimg=?"; $stmt = mysqli_prepare($connect, $query); mysqli_stmt_bind_param($stmt, "sss", $appid, $pptimg, $pptimg); if (mysqli_stmt_execute($stmt)){ echo "Image were updated successfully."; header("Location: preview.php?appid=".$appid); exit; // 跳转后终止脚本,避免后续代码执行 }else{ echo "Photo not uploaded: ".mysqli_error($connect); } mysqli_stmt_close($stmt); } else { echo "Sorry, there was an error uploading your file."; } } } ?>
修复说明
- 将数据库操作移至
if($_POST)块内部,且仅在文件上传成功后执行,确保$pptimg始终有有效值。 - 修正了文件大小检查的变量名错误。
- 使用mysqli预处理语句绑定参数,彻底解决SQL注入风险。
- 给上传文件名添加时间戳,避免同名文件覆盖。
- 增加
exit语句,防止跳转后脚本继续执行引发问题。 - 给
$appid增加空值判断,避免未定义变量警告。
内容的提问来源于stack exchange,提问作者imgrv




