PHP图片上传校验生效但无效文件仍被上传问题求助
博客图片上传校验失效,无效文件仍被上传
我开发了一个博客应用,支持上传图片并将文件名保存到数据库,已经添加了校验规则:禁止上传大于500KB的文件,仅允许jpg、png、webp、gif格式。现在的问题是,当检测到文件过大或格式无效时,页面会跳回发布表单并显示错误提示,但无效文件还是会被上传到服务器。我是PHP初学者,找不到问题根源,附上相关代码请帮忙指点。
发布表单 - makepost.php
<!-- HEADER.PHP --> <?php require "templates/header.php" ?> <main class="container p-4 bg-light mt-3" style="width: 1000px"> <!-- createpost.inc.php - Will process the data from this form--> <form action="includes/makepost.inc.php" method="POST" enctype="multipart/form-data"> <h2>Create Post</h2> <!-- Error Message --> <?php // VALIDATION: Check that Error Message Type exists in GET superglobal if(isset($_GET['error'])){ // (1) Empty fields validation if($_GET['error'] == "emptyfields"){ $errorMsg = "Please fill in all fields"; // (2) Internal server error } else if ($_GET['error'] == "sqlerror") { $errorMsg = "An internal server error has occurred - please try again later"; // (3) Banner Image file name already exists } else if ($_GET['error'] == "file-name-match") { $errorMsg = "Sorry, this banner image file already exists. Please rename your file."; // (4) Banner Image file size is to large } else if ($_GET['error'] == "file-size-to-large") { $errorMsg = "Sorry, your banner image file is too large. Please reduce our image file size."; // (5) Is the uploaded image using a valid file type } else if ($_GET['error'] == "invalid-file-type") { $errorMsg = "Sorry, only JPG, JPEG, PNG, GIF & WEBP files are allowed."; // (6) Is the upload an actual image file } else if ($_GET['error'] == "file-is-not-an-image-file") { $errorMsg = "Sorry, your file is not an image."; } else if ($_GET['error'] == "unknown-or-general-error") { $errorMsg = "Sorry, there was an error uploading your file."; } // (8) Dynamic Error Alert based on Variable Value echo '<div class="alert alert-danger" role="alert">' . $errorMsg . '</div>'; } ?> <!-- 1. Article Titile --> <div class="mb-3"> <label for="title" class="form-label">Title</label> <input type="text" class="form-control" name="title" placeholder="Title" value=""> </div> <!-- 2. Upload Image File --> <div class="mb-3"> <label for="fileToUpload" class="form-label">Banner Image</label> <input type="file" class="form-control" name="fileToUpload"> </div> <!-- 3. Article Extract --> <div class="mb-3"> <label for="extract" class="form-label">Article Extract</label> <textarea id="extract-textarea" class="form-control" name="extract" rows="3"></textarea> </div> <!-- 3. Article Text --> <div class="mb-3"> <label for="article" class="form-label">Article Text</label> <textarea id="article-textarea" class="form-control" name="article" rows="3"></textarea> </div> <!-- 4. Submit Button --> <button type="submit" name="post-submit" class="btn btn-primary w-100">Post</button> </form> </main> <!-- FOOTER.PHP --> <?php require "templates/footer.php" ?>
处理发布请求的包含文件 - makepost.inc.php
<?php // 01) Start Session. session_start(); // 02) Load the upload directory config. require 'config.inc.php'; // 03) Set the upload parameters. $target_file = $directory . basename($_FILES["fileToUpload"]["name"]); $uploadOk = 1; $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION)); // 04) Check user clicked submit button from makepost form + user is logged in. if(isset($_POST['post-submit']) && isset($_SESSION['userId']) && move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)){ // 05) Load the database connection settings file. require 'connect.inc.php'; // 06) Collect andstore POST data $title = $_POST['title']; // Post Title. $imageURL = $_FILES['fileToUpload']['name']; // Image URL - Add option for image upload. $extract = $_POST['extract']; // Post Extract. $article = $_POST['article']; // Article Text. $postdate = date("Y-m-d"); // Get Current Date for Post Date. $author = $_SESSION['userUid']; // Use 'userUid' in $_SESSION Varible for Author Name. // 07) VALIDATION: Check if any fields are empty. if (empty($title ) || empty($imageURL) || empty($extract) || empty($article) || empty($postdate) || empty($author)) { // 08) ERROR: Redirect + error via GET. header("Location: ../makepost.php?error=emptyfields"); exit(); // 09) Checks if the image files size exceeds file size limit of 500KB. } else if ($_FILES["fileToUpload"]["size"] > 500000) { header("Location: ../makepost.php?error=file-size-to-large"); $uploadOk = 0; exit(); // 10) Checks if the image is a an excepted file type. } else if ($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg" && $imageFileType != "gif" && $imageFileType != "webp" ) { header("Location: ../makepost.php?error=invalid-file-type"); $uploadOk = 0; exit(); // 11) Save the post to the database using prepared statements. } else { // 12) Declare Template SQL with ? Placeholders to save values to table. $sql = "INSERT INTO posts VALUES (NULL, ?, ?, ?, ?, ?, ?)"; // 13) Init SQL statement. $statement = mysqli_stmt_init($conn); // 14) Prepare + send statement to database to check for errors. if(!mysqli_stmt_prepare($statement, $sql)) { // 15) ERROR: Something wrong when preparing the SQL. header("Location: ../makepost.php?error=sqlerror"); exit(); } else { // 16) SUCCESS: Bind our user data with statement + escape strings. mysqli_stmt_bind_param($statement, "ssssss", $title, $imageURL, $extract, $article, $postdate, $author); // 17) Execute the SQL Statement with user data. mysqli_stmt_execute($statement); // 18) SUCCESS: Post is saved to "posts" table - redirect with success message. header("Location: ../index.php?post=success"); exit(); } } // 19) Restrict Access to Script Page. } else { header("Location: ../index.php"); exit(); } ?>
我尝试在else if语句末尾添加exit();但没有效果。
问题根源与修复方案
核心问题
你在执行所有校验逻辑之前,已经调用了move_uploaded_file()把文件上传到服务器了。也就是说,不管文件是否符合规则,只要用户提交了表单且登录状态有效,文件就已经被移动到目标目录,之后的校验只是跳回页面提示错误,但文件已经上传完成了。
修复步骤
- 调整逻辑顺序:先做所有校验(空字段、文件大小、文件类型),确认文件完全符合规则后,再执行
move_uploaded_file()和数据库写入操作。 - 优化条件判断:把
move_uploaded_file()从初始的if条件中移除,放到校验通过后的逻辑里。
修改后的makepost.inc.php核心代码片段
<?php session_start(); require 'config.inc.php'; $target_file = $directory . basename($_FILES["fileToUpload"]["name"]); $uploadOk = 1; $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION)); // 先检查提交状态和登录状态,不先上传文件 if(isset($_POST['post-submit']) && isset($_SESSION['userId'])){ require 'connect.inc.php'; $title = $_POST['title']; $imageURL = $_FILES['fileToUpload']['name']; $extract = $_POST['extract']; $article = $_POST['article']; $postdate = date("Y-m-d"); $author = $_SESSION['userUid']; // 1. 空字段校验 if (empty($title ) || empty($imageURL) || empty($extract) || empty($article) || empty($postdate) || empty($author)) { header("Location: ../makepost.php?error=emptyfields"); exit(); } // 2. 文件大小校验 else if ($_FILES["fileToUpload"]["size"] > 500000) { header("Location: ../makepost.php?error=file-size-to-large"); exit(); } // 3. 文件类型校验 else if (!in_array($imageFileType, ["jpg", "png", "jpeg", "gif", "webp"])) { header("Location: ../makepost.php?error=invalid-file-type"); exit(); } // 所有校验通过,再上传文件并写入数据库 else { // 执行文件上传 if(move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)){ // 数据库写入逻辑 $sql = "INSERT INTO posts VALUES (NULL, ?, ?, ?, ?, ?, ?)"; $statement = mysqli_stmt_init($conn); if(!mysqli_stmt_prepare($statement, $sql)){ header("Location: ../makepost.php?error=sqlerror"); exit(); } else { mysqli_stmt_bind_param($statement, "ssssss", $title, $imageURL, $extract, $article, $postdate, $author); mysqli_stmt_execute($statement); header("Location: ../index.php?post=success"); exit(); } } else { // 文件上传失败的情况 header("Location: ../makepost.php?error=unknown-or-general-error"); exit(); } } } else { header("Location: ../index.php"); exit(); } ?>
额外优化建议
- 可以添加文件是否为真实图片的校验(比如用
getimagesize()),防止用户上传伪装成图片的恶意文件。 - 处理文件名重复的情况:可以给文件名添加时间戳或随机字符串,避免覆盖已有文件,而不是让用户手动重命名。
内容的提问来源于stack exchange,提问作者Lachlan Williams
相关产品推荐
相关产品推荐

