How To Upload And Zip Single Or Multiple Files in PHP

How To Upload And Zip Single Or Multiple Files in PHP

In my article today, I will show you how you can upload both single and multiple files in PHP and save them in a zip file.

I will make use of the ZipArchive() class in PHP for the purpose of this tutorial.

INTRODUCTION

The ZipArchive() class is an inbuilt class in PHP that can be used to archive a file or group of files and compress it with zip.

Now let me show you how you can use this class to upload and zip both single and multiple files.

ABOUT THE CLASS

In order to use this class in your project, you must initialize it using the new keyword

//initialize the zip archive class
$zip = new ZipArchive()

Once you have initialized it, the methods below become available for use

  • open

This method opens an existing zip archive for reading, writing, or modifying or creates an empty zip archive.

  • addFile

This method adds a file from a given path to a ZIP archive.

  • close

This method closes opened or created archives and then saves changes.

Now let us go ahead and understand how we can upload and zip both single and multiple files in PHP

UPLOADING A SINGLE FILE

Assuming I have an HTML form that allows users to upload a single file like this;

<form method="post" action="" enctype="multipart/form-data">
    <input type="file" name="file">
    <button type="submit">Submit</button>
</form>

In PHP, I will check if a file was uploaded using the POST method, then I will process the file, create a new Zip Archive, and add the file to the zip archive.

Now let us talk about what happens when we upload a file.

What Happens When We Upload A File

When we upload a file, its properties become available to the $_FILES global variable.

The $_FILES global variable is an associative array of items uploaded to the current script via the HTTP POST method.

This means that we can see properties like;

  • The name of the file [name].
  • The type of file [type].
  • The temporary location of the file [tmp_name].
  • The error code [error].
  • The size of the file (in bytes) [size].

This is an example of a typical output from the $_FILES array when a single file is uploaded.

image.png

So we can see that the index tmp_name contains the path of the uploaded file which is also its temporary location in the server.

Now let us create a script that will process the incoming file and save it to an archive.

//check if the request method is POST
if($_SERVER['REQUEST_METHOD'] === 'POST'){
    //check if a file was uploaded
    if(isset($_FILES['file']) && !empty($_FILES['file']) && !is_array($_FILES['file'])){
        //initialize the ziparchive class
        $zip = new ZipArchive();
        //set the name of our zip archive
        $zip_file_name = 'MyFile.zip';
        //create the new zip archive using the $file_name above
        if($zip->open($zip_file_name, ZipArchive::CREATE) === true){
            //add the file to the archive
            $zip->addFile($_FILES['file']['tmp_name'], $_FILES['file']['name']);
            //close the archive
            $zip->close();
        }else{
            echo "Couldn't create Zip Archive";
        }
    }
}

If you look at the snippet above, you will notice that we followed a very simple order while creating our zip archive.

First, we created a new zip archive with the name MyFile.zip using the open() method.

Then we added the file coming from the $_FILES array using the addFile() method and lastly, we closed the archive so that it will save our changes using the close() method.

if you should run this code in your local development server and upload a file, you will see the zip archive MyFile.zip right within the root of your folder. Open this archive and you will see the file you just uploaded.

Now let us talk about how we can upload and zip multiple files

UPLOADING MULTIPLE FILES

Uploading multiple files and saving them in a zip file is not too different from the script above.

Let us modify the HTML form responsible for uploading multiple files like so;

<form method="post" action="" enctype="multipart/form-data">
    <input type="file" name="file[]" multiple>
    <button type="submit">Submit</button>
</form>

Before we go into detail, let us see the output of the $_FILES array when we upload multiple files.

image.png

At this point, you may be confused about how to retrieve the file path and names of each of the files, and how to add them to an archive.

Well, you don't have to be confused because we will loop through the $_FILES array, then match the file tmp_names and file names based on their indexes.

//check if the request method is post
if($_SERVER['REQUEST_METHOD'] === 'POST'){
    //check if a file was uploaded
    if(isset($_FILES['file']) && !empty($_FILES['file']) && is_array($_FILES['file'])){
        //initialize the ziparchive class
        $zip = new ZipArchive();
        //set the name of our zip archive
        $zip_file_name = 'MyFile.zip';
        //create the new zip archive using the $file_name above
        if($zip->open($zip_file_name, ZipArchive::CREATE) === true){
            //loop through the tmp_name of the files in $_FILES array
            foreach($_FILES['file']['tmp_name'] as $key => $tmpName){
                //get the name of the file
                $file_name = $_FILES['file']['name'][$key];
                //add the file
                $zip->addFile($tmpName, $file_name);
            }
            //close the archive
            $zip->close();
        }else{
            echo "Couldn't create Zip Archive";
        }
    }
}

Now if you should run this code in your local development server and upload some files, you will notice that the archive is updated with the recent files you just uploaded.

You can easily group the logic to handle both single and multiple file uploads.

//check if request method is post
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    //check if a file was uploaded
    if (isset($_FILES['file']) && !empty($_FILES['file'])) {
        //single file upload
        if (!is_array($_FILES['file'])) {
            //initialize the ziparchive class
            $zip = new ZipArchive();
            //set the name of our zip archive
            $zip_file_name = 'MyFile.zip';
            //create the new zip archive using the $file_name above
            if ($zip->open($zip_file_name, ZipArchive::CREATE) === true) {
                //add the file to the archive
                $zip->addFile($_FILES['file']['tmp_name'], $_FILES['file']['name']);
                //close the archive
                $zip->close();
            } else {
                echo "Couldn't create Zip Archive";
            }
        }
        //multiple file uploads
        elseif (is_array($_FILES['file'])) {
            //initialize the ziparchive class
            $zip = new ZipArchive();
            //set the name of our zip archive
            $zip_file_name = 'MyFile.zip';
            //create the new zip archive using the $file_name above
            if ($zip->open($zip_file_name, ZipArchive::CREATE) === true) {
                //loop through the tmp_name of the files in $_FILES array
                foreach ($_FILES['file']['tmp_name'] as $key => $tmpName) {
                    //the name of the file
                    $file_name = $_FILES['file']['name'][$key];
                    //add the file
                    $zip->addFile($tmpName, $file_name);
                }
                //close the archive
                $zip->close();
            } else {
                echo "Couldn't create Zip Archive";
            }
        }
    }
}

If in your application, users are allowed to upload multiple files that are archived and compressed as zip, you need to make sure that you generate a unique name for the zip archives.

You can use PHP's inbuilt functions uniqid(), rand() to generate a random key for the zip archive name.

//generate a random key for the zip archive name
$randKey  = uniqid().rand(0000,9999);
//zip file name
$zip_file_name = "$randKey.zip";

CONCLUSION

We have talked about the ZipArchive class in PHP, its methods, and how we can use it to create an archive of files and compress them as zip.

We also talked about what happens when we upload a file and how we can extract the name of an uploaded file, its size, and its temporary location from the $_FILES array.

I also showed you the output of the $_FILES array in case of a single or multiple file upload.

Finally, I gave you a hint on how you can generate a random key for your zip archive names if you are zipping the files uploaded by users.

EXTRA

I have developed a validation library that helps to validate your forms in PHP using validation rules, sophisticated regular expressions, and PHP's inbuilt validation.

This Library is Open-source and you can use this library to validate data coming from the $_POST, $_GET, or $_FILES arrays.

Check out the documentation of this library below

Thank you for reading.

Image Credit: Henry & Co on Unsplash