Ultimate Guide to Uploading Multiple Files With PHP [Examples]

PHP Multiple File Uploads Ultimate Guide

This tutorial will explain how to upload one or multiple files from the web browser to the server using PHP. Code examples are included, including the code for limiting file size and type.

Being able to have your users upload files to your app has become expected functionality in most web apps. Photos, filled out PDF forms, videos, recordings – any kind of file can be uploaded, and the process is relatively straight forward.

PHP provides all of the required tools for file uploading and validation, so here’s how it’s done

Enable File Uploads in PHP Configuration

You’ll first need to make sure file uploads are enabled in your PHP configuration (usually they are by default). This can be done by editing the php.ini configuration file.

Once you’ve located the php.ini configuration file, set the file_uploads line to On, as shown below:

file_uploads = On

Creating a HTML Upload Form for Multiple Files

A HTML form is required to select and submit files for upload. Here’s the code:

<!DOCTYPE html>
<html>
<body>

    <form action="upload.php" method="post" enctype="multipart/form-data">
        <h3>Upload Multiple Files</h3>
        <input type="file" name="uploads[]" >
        <br/>
        <input type="file" name="uploads[]" >
        <br/>
        <input type="submit" value="Upload" name="submit">
    </form>

</body>
</html>

The above code example is simple – HTML form is created, and multiple file inputs are created. You can add as many file inputs as you want, or use JavaScript to dynamically add inputs.

Note that the file inputs all have the same name followed by [] – this creates an array of multiple inputs which share a name.

Full PHP Code for Multiple File Uploads

There are a few moving parts to uploading multiple files, so I’ll provide the full code example (which you can copy and paste into your own project), and then break down the different parts.

<?php

// Uncomment the below 3 lines to enable error reporting for debugging
// ini_set('display_errors', '1');
// ini_set('display_startup_errors', '1');
// error_reporting(E_ALL);

// Uncomment the below line to print the list of uploaded files for troubleshooting
// print_r($_FILES);

// Define the name of the form file inputs
$inputName = "uploads";

// Define some file limits
$maxFileSize = 100000; //Bytes
$allowedMimeFormats = ["image/jpg", "image/png", "image/gif"];
$maxFileCount = 4; // Maximum number of files to accept

// Give uploaded files a random name so that they don't conflict
$randomFileNames = true;

// Set the directory to save the uploaded files to - this directory must already exist
$uploadPath = "uploads/";

// Get all uploaded files  - this will be an array containing keys for file attributes (name, size, etc) each with an entry for each file
$uploadedFiles = $_FILES[$inputName];

// Count # of uploaded file input fields in array
$fileCount = count($uploadedFiles['name']);

//Check if files uploaded
if ($fileCount < 1) {
    echo "No files uploaded\n";
}

// Loop through the uploaded files
for ($i = 0; $i < $fileCount; $i++) {

    // Ensure the given file input film was populated by checking the name
    if (strlen($uploadedFiles["name"][$i]) < 1) {
        continue; // Skip the current iteration
    }

    // Check file count limit
    if ($i >= $maxFileCount) {
        echo "Upload failed: " . $uploadedFiles["name"][$i] . "- Maximum file count reached\n";
        continue; // Skip the current iteration
    }

    echo "Attempting to upload " . $uploadedFiles["name"][$i];

    // Check uploaded file size
    if ($uploadedFiles["size"][$i] > $maxFileSize) {
        echo "Upload failed: " . $uploadedFiles["name"][$i] . "- File too large\n";
        continue; // Skip the current iteration
    }

    // Get the format of the uploaded file by it"s file name extension
    $uploadedFileFormat = strtolower($uploadedFiles["type"][$i]);

    // Check if uploaded file format allowed
    if (!in_array($uploadedFileFormat, $allowedMimeFormats)) {
        echo "Upload failed: " . $uploadedFiles["name"][$i] . "- " . $uploadedFileFormat . " Format not allowed\n";
        continue; // Skip the current iteration
    }

    $saveFilePath = $uploadPath . $uploadedFiles["name"][$i];

    // If random file names enabled, use one instead
    if ($randomFileNames) {
        $saveFilePath = $uploadPath . uniqid() . "." . pathinfo($saveFilePath, PATHINFO_EXTENSION);
    }

    // Check if file already exists
    if (file_exists($saveFilePath)) {
        echo "Upload failed: " . $uploadedFiles["name"][$i] . "- File already exists\n";
        continue; // Skip the current iteration
    }

    //Get the temporary uploaded file path - this is where the upload is stored temporarily before it is saved
    $temporaryUploadPath = $uploadedFiles["tmp_name"][$i];

    // Ensure temporary upload file path is valid/exists
    if (file_exists($temporaryUploadPath)) {

        //Move the uploaded file from the temporary path to it"s final destination
        if (move_uploaded_file($temporaryUploadPath, $saveFilePath)) {
            echo "Upload successful: " . $uploadedFiles["name"][$i] . "- Saved to " . $saveFilePath . "\n";
        }
    }
}

?>

Debugging and Troubleshooting

The following lines can be uncommented to help debug and troubleshoot your code, but they aren’t necessary for the file upload functionality.

// Uncomment the below 3 lines to enable error reporting for debugging
// ini_set('display_errors', '1');
// ini_set('display_startup_errors', '1');
// error_reporting(E_ALL);

// Uncomment the below line to print the list of uploaded files for troubleshooting
// print_r($_FILES);

// ...

Accessing Uploaded Files

The below code retrieves the uploaded files, counts them, and checks that files were actually uploaded:

// ...

// Define the name of the form file inputs
$inputName = "uploads";

// ...

// Get all uploaded files  - this will be an array containing keys for file attributes (name, size, etc) each with an entry for each file
$uploadedFiles = $_FILES[$inputName];

// Count # of uploaded file input fields in array
$fileCount = count($uploadedFiles['name']);

//Check if files uploaded
if ($fileCount < 1) {
    echo "No files uploaded\n";
}

// ...

The $_FILES[] array in PHP always includes the details of any files uploaded with the current request. This code gets only the files uploaded to the form input matching $inputName.

This array contains sub-arrays for the details of each file. This array contains file information line namesize and type. The contents of each array will be in the same order, so the first item in the name array will have the corresponding entry in the size array at the same index.

Due to this, the count of the uploaded files can be quickly calculated by calculating the number of entries in the name sub-array of the $_FILES[] array.

Skipping Unpopulated File Inputs

As multiple files must be processed, a for loop is used.

// ...

// Loop through the uploaded files
for ($i = 0; $i < $fileCount; $i++) {

    // Ensure the given file input film was populated by checking the name
    if (strlen($uploadedFiles["name"][$i]) < 1) {
        continue; // Skip the current iteration
    }

// ...

Multiple file upload inputs may have been provided to the user, but they may not have selected a file for each input. By checking whether the name attribute is blank, we can tell whether an input was populated or not, and skip it.

Limiting the Number of Uploaded Files

To limit the number of files the user can upload, check the current iteration count in the loop, and compare it to a set maximum.

The PHP continue statement is used to skip to the next file by skipping the current iteration of the loop.

$maxFileCount = 4; // Maximum number of files to accept

// ...

// Check file count limit
if ($i >= $maxFileCount) {
    echo "Upload failed: " . $uploadedFiles["name"][$i] . "- Maximum file count reached\n";
    continue; // Skip the current iteration
}

// ...

Limiting the Size of Uploaded Files

The size array will provide the size of any uploaded files in Bytes and can be used to limit the size of any uploaded files.

$maxFileSize = 100000; //Bytes

// ...

// Check uploaded file size
if ($uploadedFiles["size"][$i] > $maxFileSize) {
    echo "Upload failed: " . $uploadedFiles["name"][$i] . "- File too large\n";
    continue; // Skip the current iteration
}

// ...

Limiting the Type/Format of Uploaded Files

The type array provides the MIME type of any uploaded file, which can be compared to a list of allowed types to restrict what formats can be uploaded.

$allowedMimeFormats = ["image/jpg", "image/png", "image/gif"];

// ...

// Check if uploaded file format allowed
if (!in_array($uploadedFileFormat, $allowedMimeFormats)) {
    echo "Upload failed: " . $uploadedFiles["name"][$i] . "- " . $uploadedFileFormat . " Format not allowed\n";
    continue; // Skip the current iteration
}

// ...

Configuring the Directory to Save the Uploaded Files

The directory you wish to save uploaded files to must already exist and must be writable by PHP.

// ...

// Set the directory to save the uploaded files to - this directory must already exist
$uploadPath = "uploads/";

// ...

$saveFilePath = $uploadPath . $uploadedFiles["name"][$i];

// ...

Generating Random File Names

It often makes sense to assign random file names to uploaded files – the user may have used characters in the file name which are not supported on your server, and using random names reduces the chance of two filenames conflicting.

The uniqid() PHP function is used below to generate a random name, and the file extension is taken from the existing file name.

// ...

// If random file names enabled, use one instead
if ($randomFileNames) {
    $saveFilePath = $uploadPath . uniqid() . "." . pathinfo($saveFilePath, PATHINFO_EXTENSION);
}

// ...

If you did want to retain the original file name, you could store them in a database separately with a record of which original file name belongs to which randomly generated file name.

Checking for Existing Files With the Same Name

The file_exists() function can be used to check if a file already exists

// ...

// Check if file already exists
if (file_exists($saveFilePath)) {
    echo "Upload failed: " . $uploadedFiles["name"][$i] . "- File already exists\n";
    continue; // Skip the current iteration
}

// ...

Saving the Uploaded File

Files uploaded to PHP will first be stored in a temporary location until you move or rename them. The temporary path for uploaded files is stored in the tmp_name array.

// Get the temporary uploaded file path - this is where the upload is stored temporarily before it is saved
$temporaryUploadPath = $uploadedFiles["tmp_name"][$i];

// Ensure temporary upload file path is valid/exists
if (file_exists($temporaryUploadPath)) {

    //Move the uploaded file from the temporary path to it"s final destination
    if (move_uploaded_file($temporaryUploadPath, $saveFilePath)) {
        echo "Upload successful: " . $uploadedFiles["name"][$i] . "- Saved to " . $saveFilePath . "\n";
    }
}

The file_exists() function is used to first check that the temporarily uploaded file exists at the given path.

The move_uploaded_file() function will save the temporary uploaded file to a new location for permanent storage.

Removing the Temporary Uploaded File

Wondering what happens to the uploaded files you don’t move or save? Don’t worry about them – PHP automatically cleans them up.

What Next?

Congratulations, your files have been uploaded. Here are a few things to try next:

SHARE:
nv-author-image

Brad Morton

I'm Brad, and I'm nearing 20 years of experience with Linux. I've worked in just about every IT role there is before taking the leap into software development. Currently, I'm building desktop and web-based solutions with NodeJS and PHP hosted on Linux infrastructure. Visit my blog or find me on Twitter to see what I'm up to.

Leave a Reply

Your email address will not be published. Required fields are marked *