簡體   English   中英

上傳多張圖片到 MySql 數據庫

[英]Uploading multiple images to MySql database

我正在嘗試為電子商務網站的產品上傳多張圖片。 這個想法是將服務名稱保存在服務表中,而圖像保存在 service_images 表中,但是每當我運行 php 文件時,它會將服務上傳到服務表但只將一張圖像上傳到 service_images 表而不是全部圖像。 我怎樣才能讓它在服務表中上傳一項服務,並在 service_images 表中上傳該服務的多個圖像?

下面是我的代碼:

add-service.inc.php

<?php

if (isset($_POST['add-service'])) {

    require 'config.php';

    $shop_name = mysqli_real_escape_string($conn, $_POST['shop_name']);
    $service_cat = mysqli_real_escape_string($conn, $_POST['service_cat']);
    $service_name = mysqli_real_escape_string($conn, $_POST['service_name']);
    $service_desc = mysqli_real_escape_string($conn, $_POST['service_desc']);
    $service_price = mysqli_real_escape_string($conn, $_POST['service_price']);
    $service_type = mysqli_real_escape_string($conn, $_POST['service_type']);
    $service_images = $_FILES['service_images'];
    
    if (empty($shop_name) || empty($service_cat) || empty($service_name) || empty($service_desc) || empty($service_price) || empty($service_type)) {
        header('Location: ../services.php?error=emptyFields');
        exit();
    } elseif (!preg_match('/^[a-zA-Z0-9]*$/', $shop_name) && !preg_match('/^[a-zA-Z0-9\s]*$/', $service_name) && !preg_match('/^[a-zA-Z0-9\s \. \-]*$/', $service_desc) && !preg_match('/^[0-9\.]*$/', $service_price) && !preg_match('/^[a-zA-Z0-9\s \.]*$/', $service_type)) {
        header('Location: ../services.php?error=invalidInputs');
        exit();
    } elseif (!preg_match('/^[a-zA-Z0-9]*$/', $shop_name)) {
        header('Location: ../services.php?error=invalidShopName');
        exit();
    } elseif (!preg_match('/^[a-zA-Z0-9\s]*$/', $service_name)) {
        header('Location: ../services.php?error=invalidserviceName');
        exit();
    } elseif (!preg_match('/^[a-zA-Z0-9\s \. \-]*$/', $service_desc)) {
        header('Location: ../services.php?error=invalidDescription');
        exit();
    } elseif (!preg_match('/^[0-9\.]*$/', $service_price)) {
        header('Location: ../services.php?error=invalidPrice');
        exit();
    } elseif (!preg_match('/^[a-zA-Z0-9\s \.]*$/', $service_type)) {
        header('Location: ../services.php?error=invalidStyle');
        exit();
    } else {
        foreach ($_FILES["service_images"]["tmp_name"] as $key => $tmp_name) {
            $file_name = $_FILES["service_images"]["name"][$key];
            $file_type = $_FILES["service_images"]["type"][$key];
            $file_tempName = $_FILES["service_images"]["tmp_name"][$key];
            $file_error = $_FILES["service_images"]["error"][$key];
            $file_size = $_FILES["service_images"]["size"][$key];
    
            $a = count($_FILES['service_images']['name']);
            for ($i = 0; $i < $a; $i++) {
                $fileExt = explode('.', $file_name);
                $fileActualExt = strtolower(end($fileExt));
    
                $allowed = array('jpg', 'png', 'jpeg');
    
                if (in_array($fileActualExt, $allowed)) {
                    if ($file_error === 0) {
                        if ($file_size <= 15000000) {
    
                            $newFileName = preg_replace('/\s+/', '', $service_name) . $i . '.' . $fileActualExt;
                            echo $newFileName . "<br>";
                            $fileDestination = '../../services/' . $newFileName;

                            $sql_images = "INSERT INTO service_images (shop_name, service_name) VALUES ('$shop_name', '$service_name')";
                            $result = mysqli_query($conn, $sql_images);

                            $sql = "INSERT INTO services (shop_name, service_cat, service_name, service_desc, service_price, service_type) VALUES (?,?,?,?,?,?)";
                            $stmt = mysqli_stmt_init($conn);
                            if (!mysqli_stmt_prepare($stmt, $sql)) {
                                header("Location: ../services.php?error=SaveError");
                                exit();
                            } else {
                                mysqli_stmt_bind_param($stmt, 'ssssss', $shop_name, $service_cat, $service_name, $service_desc, $service_price, $service_type);
                                mysqli_stmt_execute($stmt);

                            // move_uploaded_file($file_tempName = $_FILES["service_images"]["tmp_name"][$i], $fileDestination);
                                header("Location: ../services.php?success");
                                exit();
                            }
    
                        } else {
                            header('Location: ../services.php?error=invalidSize');
                            exit();
                        }
                    } else {
                        header('Location: ../services.php?error=invalidImage');
                        exit();
                    }
                } else {
                    header('Location: ../services.php?error=invalidImageType');
                    exit();
                }
            }
        }
    }

}

形式

<form action="../admin/includes/add-service.inc.php" method="post" enctype="multipart/form-data">
   <input type="text" name="shop_name" id="shopName" class="form-input" placeholder="Shop Name">
   <select name="service_cat" id="serviceCat" class="form-input">
      <option> -- select category -- </option>
      <?php
         $sql = "SELECT * FROM service_category";
         $result = mysqli_query($conn, $sql);
         if (mysqli_num_rows($result) > 0) {
            while ($row = mysqli_fetch_assoc($result)) {
     ?>
            <option value="<?php echo $row['service_cat'] ?>"><?php echo $row['service_cat'] ?></option>
     <?php
           }
         }
     ?>
   </select>
   <input type="text" name="service_name" id="serviceName" class="form-input" placeholder="Service Name">
   <textarea name="service_desc" id="service_desc" cols="1" rows="5" placeholder="Description" class="form-input"></textarea>
   <input type="text" name="service_price" id="servicePrice" class="form-input" placeholder="Service Price">
   <input type="text" name="service_type" id="serviceType" class="form-input" placeholder="Service Type">
   <hr>
   <label for="serviceImages">*Select all pictures for your service</label>
   <input type="file" name="service_images[]" id="serviceImages" class="form-input" multiple>
   <button type="submit" class="btn-add" name="add-service">Add Service</button>
</form>

首先,您有兩次相同的循環。 首先是 foreach,然后是 for。 由於您需要來自這種奇怪的 $_FILES 數組類型的數字鍵,因此您最好的方法是僅使用 for 循環。 這些雙循環已經非常混亂,如果其中一個文件出現問題,可能會導致意外問題。

但是,您的主要問題是,您基本上只檢查一張圖像然后上傳它。 如果驗證過程或成功通過,它有exit(); 在最后。 它不僅會殺死循環,還會殺死整個腳本。 您不允許第二個圖像循環繼續,因為第一個會殺死它..無論是成功還是錯誤。

解決方案是等待循環完成(在循環括號后添加代碼)並將成功相關的代碼放在那里。 如果在循環內檢測到錯誤,則腳本永遠不會走那么遠。

在此處輸入圖像描述

我不知道您實際上是如何將圖像鏈接到服務的,但我試圖清理您的代碼並使順序正確。 我也盡力解釋為什么和在哪里。 希望你能更好地理解這個問題,甚至更好地找到更好的選項來優化你的代碼:

// TESTING: Lets see what is inside post values:
echo '<b>$_POST values</b><pre>'; print_r($_POST); echo '</pre>';

// TESTING: Lets see what is inside the files values:
echo '<b>$_FILES values</b><pre>'; print_r($_FILES); echo '</pre>';

// Above is for testing only..

// Probably better place to load important configs:
require 'config.php';

// Since these are the conditions for uploads, then they are global:
// no need for them to be inside the loop:
$allowed = array('jpg', 'png', 'jpeg');

// Maximum allowed filesize:
$max_allowed_file_size = 15000000; // which is 15mb


// We detect the submit buttons trigger name:
if (isset($_POST['add-service'])) {
    
    // Do the escape thingy:
    // NOTE: You should be using some mysqli class for database handling:
    $shop_name = mysqli_real_escape_string($conn, $_POST['shop_name']);
    $service_cat = mysqli_real_escape_string($conn, $_POST['service_cat']);
    $service_name = mysqli_real_escape_string($conn, $_POST['service_name']);
    $service_desc = mysqli_real_escape_string($conn, $_POST['service_desc']);
    $service_price = mysqli_real_escape_string($conn, $_POST['service_price']);
    $service_type = mysqli_real_escape_string($conn, $_POST['service_type']);
    $service_images = $_FILES['service_images'];
    
    // Lets deal with the errors before going forward with the rest of the script:
    // You don't need elseif here, because your callback is to redirect and exit anyways..
    if (empty($shop_name) || empty($service_cat) || empty($service_name) || empty($service_desc) || empty($service_price) || empty($service_type)) {
        header('Location: ../services.php?error=emptyFields');
        exit();
    }
    
    if (!preg_match('/^[a-zA-Z0-9]*$/', $shop_name) && !preg_match('/^[a-zA-Z0-9\s]*$/', $service_name) && !preg_match('/^[a-zA-Z0-9\s \. \-]*$/', $service_desc) && !preg_match('/^[0-9\.]*$/', $service_price) && !preg_match('/^[a-zA-Z0-9\s \.]*$/', $service_type)) {
        header('Location: ../services.php?error=invalidInputs');
        exit();
    }
    
    if (!preg_match('/^[a-zA-Z0-9]*$/', $shop_name)) {
        header('Location: ../services.php?error=invalidShopName');
        exit();
    }
    
    if (!preg_match('/^[a-zA-Z0-9\s]*$/', $service_name)) {
        header('Location: ../services.php?error=invalidserviceName');
        exit();
    }
    
    if (!preg_match('/^[a-zA-Z0-9\s \. \-]*$/', $service_desc)) {
        header('Location: ../services.php?error=invalidDescription');
        exit();
    }
    
    if (!preg_match('/^[0-9\.]*$/', $service_price)) {
        header('Location: ../services.php?error=invalidPrice');
        exit();
    }
    
    if (!preg_match('/^[a-zA-Z0-9\s \.]*$/', $service_type)) {
        header('Location: ../services.php?error=invalidStyle');
        exit();
    }
    // Nothing happened above, so that means the form validation should be fine and we can go forward with the images:
    
    
    // So as in your script, we count the images:
    $a = count($_FILES['service_images']['name']);
    
    // Now we do a "numeric loop", not an array loop, which is foreach:
    for ($i = 0; $i < $a; $i++) {
        
        // Since we have the key as numeric now, we can do what you did before, but without the foreach loop:
        $file_name = $_FILES['service_images']['name'][$i];
        $file_type = $_FILES['service_images']['type'][$i];
        $file_tempName = $_FILES['service_images']['tmp_name'][$i];
        $file_error = $_FILES['service_images']['error'][$i];
        $file_size = $_FILES['service_images']['size'][$i];
        
        // Get the file extension:
        // NOTE: This is not good, as you should really check the mime type of the file, not the extension.
        $fileActualExt = strtolower(end(explode('.', $file_name)));
        
        // TESTING: We check print out the data to make sure, that all looks fine:
        echo 'File with the key: ' . $i .' -- $file_name: ' . $file_name . '; $file_type: ' . $file_type . '; $file_tempName: ' . $file_tempName . '; $file_error: ' . $file_error . '; $file_size: ' . $file_size . '<br>';
        
        // Instead of making the code ugly, lets deal with errors, by killing the script before
        // NOTE: This is not good approach, you should be using Exceptions:
        // https://www.php.net/manual/en/language.exceptions.php
        // Check if the file extension is NOT in the allowed array
        if (!in_array($fileActualExt, $allowed)) {
            
            // Redirect:
            header('Location: ../services.php?error=invalidImageType');
            
            // Kill the script:
            exit('invalidImageType');
        }
        
        // Check if the file had an error:
        if ($file_error) {
            
            // Redirect:
            header('Location: ../services.php?error=invalidImage');
            
            // Kill the script:
            exit('invalidImage');
        }
        
        // Check if the image bytes are BIGGER > then max allowed file size variable:
        if ($file_size > $max_allowed_file_size) {
            
            // Redirect:
            header('Location: ../services.php?error=invalidSize');
            
            // Kill the script:
            exit();
        }
        
        // At this stage, hopefully, there has not been any errors above and we can deal with file freely:
        
        // Make new file name:
        $newFileName = preg_replace('/\s+/', '', $service_name) . $i . '.' . $fileActualExt;
        
        // echo $newFileName . "<br>";
        
        // Set the new destination:
        $fileDestination = '../../services/' . $newFileName;
        
        // Lets move the file already.
        // NOTE: Make sure that you have some bash code from server side, that deletes outdated / old temp files, so they dont take space:
        move_uploaded_file($file_tempName = $_FILES["service_images"]["tmp_name"][$i], $fileDestination);
        
        // Insert the image to database:
        // NOTE: Im not sure about your specific code, but just this is there location for that:
        $sql_images = "INSERT INTO service_images (shop_name, service_name) VALUES ('$shop_name', '$service_name')";
        $result = mysqli_query($conn, $sql_images);
            
        // PROBLEM: This is where you originally had the success message redirect and exit.
        // This means, you KILL the script and there for the loop.
        // But you have to understand, that you have two images or more, so the loop has to continue freely,
        // and you can do this sort of stuff at after the loop!
        //
        // header("Location: ../services.php?success");
        // exit();
        
    }
    // If nothing happened above, then the image uploads went trough nicely and we can deal with success messages or adding the service itself:
    
    // I have not used mysqli stmpt before, so I have no idea what is going on in this area..:
    // .. but this the locatin to deal with the services as this is the parent and the children are above.
    $sql = "INSERT INTO services (shop_name, service_cat, service_name, service_desc, service_price, service_type) VALUES (?,?,?,?,?,?)";
    $stmt = mysqli_stmt_init($conn);
    
    // I don't think you need this at all, but whatever:
    // Shouldnt this be above 
    if (!mysqli_stmt_prepare($stmt, $sql)) {
        
        // Redirect:
        header("Location: ../services.php?error=SaveError");
        
        // Kill the script:
        exit();
    }
    
    // This is adding the service I assume, it has to be outside the loop, as single submit = single service. But images are multiple.
    mysqli_stmt_bind_param($stmt, 'ssssss', $shop_name, $service_cat, $service_name, $service_desc, $service_price, $service_type);
    mysqli_stmt_execute($stmt);

    // This is where you can have the success redirect and exit, as this is after the loop:
    header("Location: ../services.php?success");
    exit();
}

筆記:

  1. 您應該使用異常來處理錯誤。
  2. 了解 foreach 和 for 循環之間的區別。
  3. 文件擴展名可能會被欺騙,請查看文件 mime 類型
  4. 循環內允許的文件類型數組不是很聰明,因為您將在所有循環循環中多次使用它。 最好將其保留在腳本的頂部,以便將來更容易設置。 文件大小變量也是如此。
  5. 在文件到達您的服務器之前,通過 javascript 檢測文件類型和大小會更有意義。 這樣,您基本上可以節省臨時文件夾空間問題和帶寬。
  6. 我不明白你在哪里實際使用 mysql 的 $result。 或者您在哪里將 service_images 表中的圖像鏈接到實際服務。
  7. 在表單中使用<input type="file" name="service_images[]" multiple accept=".jpg, .png, .jpeg">多個 accept=".jpg, .png, .jpeg" )允許用戶選擇任何其他擴展。 您還可以對所有圖像使用“圖像”值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM