将多个图像上传到MySql数据库

时间:2020-08-01 16:22:32

标签: php mysql

我正在尝试为电子商务网站的产品上传多张图片。想法是在将图像保存在service_images表中的同时将服务名称保存在services表中,但是每当我运行php文件时,它都会将服务上载到services表,但是只将一个图像上载到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>

1 个答案:

答案 0 :(得分:0)

首先,您有两次相同的循环。首先是foreach,然后是for。由于您需要$ _FILES这种奇怪的数组类型中的数字键,因此最好的方法是仅使用for循环。 这些双循环已经非常混乱,例如,如果其中一个文件有问题,可能会导致意外问题。

但是,您的主要问题是,您基本上只检查一张图像,然后将其上传。如果验证过程或成功失败了,它的末尾将有exit();。它不仅杀死循环,而且杀死整个脚本。您不允许第二个图像循环继续进行,因为第一个图像循环会杀死它..无论是成功还是错误。

解决方案是等待循环完成(在循环括号后添加代码),然后在其中放置与成功相关的代码。如果在循环内检测到错误,则脚本永远不会走那么远。

enter image description here

我不知道您实际上是如何将图像链接到服务的,但是我试图清理您的代码并使顺序正确。我也尽力解释了原因和地点。希望您对此有所了解,甚至更好,找到更好的选项来优化代码:

// 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. 您应该使用Exceptions进行错误处理。
  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” )形式,不允许用户选择其他任何扩展名。 您还可以对所有图像使用“图像”值。
相关问题