【问题标题】:PHP Error messages work, but file uploads still go throughPHP 错误消息有效,但文件上传仍然通过
【发布时间】:2022-12-02 21:42:54
【问题描述】:

我编写了一个博客应用程序,可以上传图像文件并将文件名保存到数据库中。我包括检查以防止上传大于 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" ?>

includes文件处理post - 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();
  }
?>

我试过添加 exit();到 else if 语句的末尾,但它似乎什么也没做。

【问题讨论】:

  • 您的第一个“if”语句代码始终在执行,这就是上传文件的原因。在 if 语句之前检查文件大小和扩展名类型。我希望你能明白
  • move_uploaded_file 在您检查任何类型的错误之前发生。尝试将文件复制到最终目的地是没有意义的你已经验证了它。
  • 您是否建议将 move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file) 移动到将数据保存到数据库的 else 语句?
  • 那会更有意义是的

标签: php


【解决方案1】:

问题是,您在检查文件大小等之前执行了move_uploaded_file。你在 if 语句中这样做。这意味着只要 $_POST['post-submit']$_SESSION['userId'] 存在,您就已经尝试保存该文件。

您需要先检查所有内容,以防万一,您执行move_uploaded_file。您需要将其移动到将内容保存在数据库中的其他地方。

那已经是主要答案了。

我建议的是稍微改变一下您的思维方式。特别是在文件上传上,它可能很重要。目前,代码就像“一切都很好,只要没有错误,当出现错误时,它可能是这个或这个或这个”。

我会把它改成“没有什么是对的,只要没有证据”。

做得巧妙时,它还可以具有更好的概览。而且你不需要一堆 elseif。

这是我的意思的不同方式的一个例子。 (这不是一个完整的工作代码,它只是为了展示方式。)

<?php
// here you list all the checks you need to do and set al of them to false. this gives an overview that you need to check.
$checks = [
    'emptyValues' => false,
    'fileSize' => false,
    'imageType' => false,
];

// then you do the checks. and set each one on true, when they pass.
if ($_FILES["fileToUpload"]["size"] < 500000) {
    $checks['filesize' = true];
}

// then before you save something, search if there are still some values on false.
$error = array_search(false, $checks, true);

// just in case there is nothing left $error will be false. in every other case it will be the first key of the array where the check didn't succeed. here you need to be a strict check, because it is just really false, in case nothing got found. in case you would use a numeric array, it would deliver false in case check where the key is 0 failed.
if($error === false) {
    //here you save the file and write to database.
} else {
    // when it ends up here, then something went wrong.
    // it could be that a check failed, or that you forgot to do a check, that is listet as todo in your array.
    // because keys of arrays are strings or integer, you can do just one header location call, that delivers the key of the first error.
    header("Location: ../makepost.php?error=".$checkResult);
    exit;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2015-06-21
    • 2020-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    相关资源
    最近更新 更多