How To Upload And Zip Single Or Multiple Files in PHP
Tags: tutorial, php, webdev, programming
Published: 2022-12-11 20:23:05

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

```php
//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;

```html
<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](https://cdn.hashnode.com/res/hashnode/image/upload/v1670767630926/jz_YMbb6z.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.

```php
//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;

```html
<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](https://cdn.hashnode.com/res/hashnode/image/upload/v1670769522619/FAUQN_Jks.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.

```php
//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.

```php
//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. 

```php
//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

{% embed https://octagon-simon.github.io/projects/octavalidate/php/index.html %}

Thank you for reading.

Image Credit: Henry & Co on Unsplash