Upload Multiple Files In PHP?


14th May 2020 6 mins read
Share On        


Hello Friends! In this article you will learn how to upload multiple files in PHP.


This article covers


  1. HTML File Upload Page
  2. Database Design To Store The Image Names
  3. Database Connection In PHP
  4. Rearrange Files Data When Form Submitted
  5. Simple Multiple File Upload
  6. File Upload With Validation


NOTE: I have added the complete code in GitHub repository. You can find it here Multiple File Upload

Prerequisites


Basic knowledge of PHP, HTML & I hope you already know how to do file upload if not then refer this article


How To Uploads Files In PHP?

How To Upload Image In PHP?


1) HTML File Upload Page


The following is the basic HTML code for multiple file uploads make sure you have enctype="multipart/form-data" in form tag,  product_images[] is an array in input type=file tag & multiple must be added to input element.


In the following example I would like to upload multiple product images, this might not be the realistic example but hope it servers for your understanding.


<form action="store_product.php" method="post" enctype="multipart/form-data">
    <div>
        <label for="product_images">Select Product</label> <br>
        <!-- 
            Basically you get the product list from database.
            For the sake of demonstration I am hard coding
         -->
        <select name="product_id" id="product_id">
            <option value="1">Product 1</option>
            <option value="2">Product 2</option>
        </select>
    </div> <br>
    <div>
        <label for="product_images">Product Images</label> <br>
        <input type="file" name="product_images[]" id="product_images" multiple>
    </div> <br>
    <div>
        <input type="submit" value="Upload Product Images">
    </div>
</form>

2) Database Design To Store Product & It's Image Names


NOTE: I would like to store the images/files in disk ie., specific path and not in my database. By saving the images or any files as BLOB in database will increase the complexity, consumes lot of space & even reduces the efficiency of CRUD operations.


Following is the simple design of the products & product_images table inside invoice database.


/** Creating database with name invoice */
CREATE DATABASE `invoice`;

/** Once we create we want to switch to invoice so that we can add products table */
USE `invoice`;

/** Products table to hold the products data */
CREATE TABLE `products` (
	`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(30),
	`product_invoice` VARCHAR(255),
	PRIMARY KEY (`id`)
);
/** Product Images */
CREATE TABLE `product_images` (
	id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
	product_id INT(11) UNSIGNED NOT NULL,
	product_image VARCHAR(100) NOT NULL,
	PRIMARY KEY (`id`),
	FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
);


For the sake of demonstration I have the following 2 rows inside products table


INSERT INTO `products` (`id`, `name`, `product_image`)
VALUES
	(1, 'Product 1', '98767461589180160d435607145066fc9c3b5069d336f11a9.jpg'),
	(2, 'Product 2', '61545675589180160d435607145066fc9c3b5069d336f11a9.jpg');

3) Database Connection In PHP


The following is the code to connect to the database which we created above. I am using PDO connection, which is very advanced than mysql or mysqli functions.


<?php
$host           = 'localhost';
$db_name        = 'invoice';
$db_username    = 'root';
$db_password    = 'root';
$dsn            = 'mysql:host='. $host .';dbname='. $db_name;
$options        = [
                    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
                    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                    PDO::ATTR_EMULATE_PREPARES   => false,
                ];
try {
    /** $pdo is the connection object which I will be using for all my datbase operations */
    $pdo = new PDO($dsn, $db_username, $db_password);
} catch (PDOException $e) {
    exit($e->getMessage());
}

4) Rearrange Files Data When Form Submitted


Once you fill the form and submit you will get somewhat similar to the following output.


store_product.php


Lets debug the form uploaded


echo '<pre>';
print_r($_FILES['product_images']);
exit;


Output


Array
(
    [name] => Array
        (
            [0] => tempro1991266572.png
            [1] => tempro1913737454.png
        )

    [type] => Array
        (
            [0] => image/png
            [1] => image/png
        )

    [tmp_name] => Array
        (
            [0] => /Applications/MAMP/tmp/php/php70g7x1
            [1] => /Applications/MAMP/tmp/php/phppHPzVH
        )

    [error] => Array
        (
            [0] => 0
            [1] => 0
        )

    [size] => Array
        (
            [0] => 874
            [1] => 880
        )

)


Since looping into them and parsing might be difficult lets format the above. In the below code I am just looping the files and just arranging based on keys ie name, tmp_name etc.


function rearrange_files($files)
{
    $file_array = [];
    foreach ($files as $file_key => $file) {
        foreach ($file as $index => $file_value) {
            $file_array[$index][$file_key] = $file_value;
        }
    }
    return $file_array;
}


Using the above function we will get the rearranged files as follows


Array
(
    [0] => Array
        (
            [name] => tempro1991266572.png
            [type] => image/png
            [tmp_name] => /Applications/MAMP/tmp/php/php3YrETt
            [error] => 0
            [size] => 874
        )

    [1] => Array
        (
            [name] => tempro1913737454.png
            [type] => image/png
            [tmp_name] => /Applications/MAMP/tmp/php/phpm1vF67
            [error] => 0
            [size] => 880
        )

)


Ah! This looks clean, very understandable and more easy to work on.


5) Simple Multiple File Upload


Now lets add the bits and pieces to make the basic multiple form upload work


<?php
session_start();
require_once 'db.php';


function rearrange_files($files)
{
    /** above I have added function code  **/
}


if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    /** array variable to hold errors */
    $errors = [];


    $product_id      = $_POST['product_id'];
    $product_images  = $_FILES['product_images'];
    /** Add form validation */
    if (empty($product_images)) {
        $errors[] = 'Product invoice file required';
    }
    if (empty($product_id)) {
        $errors[] = 'Select product you want to add image';
    }
    /** Check if the product exists in your database */
    $product_stmt = $pdo->prepare("
        SELECT
            id, name
        FROM
            `products`
        WHERE
            id = :product_id
    ");

    $product_stmt->execute([
        ':product_id'     => $product_id,
    ]);

    $product = $product_stmt->fetchObject();

    if (!$product) {
        $errors[] = 'Selected product does not exist!';
    }

    /** If there are any form errors then redirect back */
    if (count($errors) > 0) {
        $_SESSION['errors'] = $errors;
        header('Location: index.php');
    }


    /** $_FILES will have the upload file details in PHP */
    $arranged_files = rearrange_files($_FILES['product_images']);
    
    foreach ($arranged_files as $product_image) {
        /** I am using pathinfo to fetch the details of the PHP File */
        $file_name          = $product_image['name'];
        $file_size          = $product_image['size'];
        $file_tmp           = $product_image['tmp_name'];
        $pathinfo           = pathinfo($file_name);
        $extension          = $pathinfo['extension'];
        $file_extensions   = ['pdf', 'xls', 'jpeg', 'jpg', 'png', 'svg', 'webp'];
        
        /** Since I want to rename the File I need its extension
         * which will be obtained with above $phpinfo variable
         * */
        /** generate random inage name */
        $new_file_name = rand(0, 10000000).time().md5(time()).'.'.$extension;

        move_uploaded_file($file_tmp, './uploads/product_images/'. $new_file_name);
        
        $product_image = $pdo->prepare("
            INSERT INTO 
                `product_images` (`product_id`, `product_image`)
            VALUES
                (:product_id, :product_image)
        ")
        ->execute([
            ':product_id'       => $product->id,
            ':product_image'    => $new_file_name,
        ]);
    }
    $_SESSION['success'] = 'Products added successfully';
    header('location: index.php');
    exit;
} else {
    header('location: index.php');
    exit;
}

6) File Upload With Validation


In the above code the validation is not added for all the files while doing upload we can perform simple validation as follows


/** File strict validations */
    
/** File exists */
if (!file_exists($file_tmp)) {
    $errors[] = 'File your trying to upload not exists';
}

/** Check if the was uploaded only */
if (!is_uploaded_file($file_tmp)) {
    $errors[] = 'File not uploaded properly';
}

/** Check for the file size 1024 * 1024 is 1 MB & 1024 KB */
if ($file_size > (1024 * 1024)) {
    $errors[] = 'Uploaded file is greater than 1MB';
}

/** Check File extensions */
if (!in_array($extension, $file_extensions)) {
    $errors[] = 'File allowed extensions '. implode(', ', $file_extensions);
}

if (count($errors) > 0) {
    $_SESSION['errors'] = $errors;
    header('location: index.php');
    exit;
}


The simple validation can be performed within foreach loop as shown below


foreach ($arranged_files as $product_image) {
    /** The above validation code */
}

Conclusion


Hope you got some idea on upload multiple files in PHP.




AUTHOR

Channaveer Hakari

I am a full-stack developer working at WifiDabba India Pvt Ltd. I started this blog so that I can share my knowledge and enhance my skills with constant learning.

Never stop learning. If you stop learning, you stop growing