You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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请求,此时$pptimgif($_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

火山引擎 最新活动