Create ZIP file with password – PHP

To create a ZIP file with password in PHP, there isn’t any need for third-party library. PHP provides a large variety of built-in functions to create a ZIP file. Also PHP has an in-built option for setting the password on ZIP files.

We will creating a simple script to allow user to upload multiple files, then will compress those files in ZIP and asking the password from user. And apply that password on that ZIP file.

We will be creating just 2 files, 1 for client (index.php) and 1 for server (upload.php). So, start off by creating a simple HTML form in file index.php:

Create form to select multiple files (index.php)

1
2
<form method="POST" enctype="multipart/form-data" action="upload.php">
</form>

enctype=”multipart/form-data” and method=”POST” are important in <form> tag to upload file.

1
2
<input type="file" name="files[]" required multiple />
<input type="submit" name="upload" />

multiple attribute will be used to allow user to select multiple files.

Upload, compress files to ZIP (upload.php)

1
2
3
<?php
    $zip = new ZipArchive();
?>

Creates a built-in ZipArchive class object and save it in variabled called $zip.

Call open() function from $zip object to create a new empty ZIP file in memory.

1
$zip->open("file.zip", ZIPARCHIVE::CREATE);
  • First parameter is the name of ZIP file you want to set.
  • Second is the action you want to perform, you can use OPEN, CREATE methods to read or write the file respectively.

As we are allowing user to select multiple files, we need to create a loop on user selected files:

1
2
3
4
for ($a = 0; $a < count($_FILES["files"]["name"]); $a++)
{
    //
}

Inside this loop, we have to get the content of each file separately:

1
$content = file_get_contents($_FILES["files"]["tmp_name"][$a]);

Then you have to call the addFromString() method on $zip object. It accepts 2 parameters, 1st is the name of file inside the ZIP archive, 2nd is the content of file. In this case, 2nd parameter is stored in variable called $content.

1
$zip->addFromString($_FILES["files"]["name"][$a], $content);

After the loop, we have to call the close() to free-up the space in memory.

1
$zip->close();

At this point, your index.php file will look like this:

1
2
3
4
<form method="POST" enctype="multipart/form-data" action="upload.php">
    <input type="file" name="files[]" required multiple />
    <input type="submit" name="upload" />
</form>

And your upload.php file will look like this:

1
2
3
4
5
6
7
8
9
10
<?php
    $zip = new ZipArchive();
    $zip->open("file.zip", ZIPARCHIVE::CREATE);
    for ($a = 0; $a < count($_FILES["files"]["name"]); $a++)
    {
        $content = file_get_contents($_FILES["files"]["tmp_name"][$a]);
        $zip->addFromString($_FILES["files"]["name"][$a], $content);
    }
    $zip->close();
?>

Applying password to archive (upload.php)

Create simple password input field in index.php file:

1
<input type="password" name="password" required />

And in upload.php file, after the open() method, call the setPassword() method and send user selected password as parameter:

1
$zip->setPassword($_POST["password"]);

And in loop, after addFromString() method, call setEncryptionName() method to apply password on each file in the ZIP:

1
$zip->setEncryptionName($_FILES["files"]["name"][$a], ZipArchive::EM_AES_256);
  • 1st parameter is the name of file.
  • 2nd parameter is the type of encryption algorithm used.

Below is the complete source code of both files:

index.php

1
2
3
4
5
<form method="POST" enctype="multipart/form-data" action="upload.php">
    <input type="file" name="files[]" required multiple />
    <input type="password" name="password" required />
    <input type="submit" name="upload" />
</form>

upload.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
    $zip = new ZipArchive();
    $zip->open("file.zip", ZIPARCHIVE::CREATE);
    $zip->setPassword($_POST["password"]);
 
    for ($a = 0; $a < count($_FILES["files"]["name"]); $a++)
    {
        $content = file_get_contents($_FILES["files"]["tmp_name"][$a]);
        $zip->addFromString($_FILES["files"]["name"][$a], $content);
        $zip->setEncryptionName($_FILES["files"]["name"][$a], ZipArchive::EM_AES_256);
    }
    $zip->close();
?>

Run the index.php file, upload some files and set the password. Your selected files will be archived to 1 and password will be applied.

Download

Now, we will discuss how you can download that zip file in your computer. First, we will create a button which when clicked, will call a Javascript function.

1
<button type="button" onclick="download();">Download</button>

After that, we will create that Javascript function. It will call an AJAX and set the response type as BLOB.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function download() {
    const ajax = new XMLHttpRequest();
    ajax.open("POST", "download.php", true);
    ajax.responseType = "blob";
     
    ajax.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
             
            // [process blob here]
 
        }
    };
 
    ajax.send();
}

Next, we will create a file named “download.php” and write the following code in it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$zip_file_name = "file.zip";
$zip_path = "uploads/" . $zip_file_name;
 
// Set headers for file download
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . basename($zip_file_name) . '"');
header('Content-Length: ' . filesize($zip_path));
 
// Read and output the file
readfile($zip_path);
 
// Delete the file after sending
unlink($zip_path);
exit;

This will first tell the client that the response will be a zip file. After that, it will read and output the file to the client. Finally, it will delete the zip file from server. Now we need to process that file on client side. So write the following code in [process blob here] section.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// get content disposition header
let disposition = ajax.getResponseHeader("Content-Disposition");
 
// get file name
let filename = disposition.split("filename=")[1];
filename = filename.replace(/['"]/g, "").trim();
 
// get response, in BLOB
const response = this.response;
 
// create object URL from BLOB
const url = window.URL.createObjectURL(response);
 
// create hidden anchor tag
const link = document.createElement("a");
 
// set href to the zip file object URL
link.href = url;
 
// download as zip file name
link.setAttribute("download", filename);
 
// add anchor tag at the end of body
document.body.appendChild(link);
 
// trigger the download
link.click();
 
// remove anchor tag
link.remove();

Comments has been added with each line for explanation. If you are using Laravel, make sure to expose the headers in vendor/laravel/framework/config/cors.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
 
return [
 
    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */
 
    'paths' => ['api/*', 'sanctum/csrf-cookie'],
 
    'allowed_methods' => ['*'],
 
    'allowed_origins' => ['*'],
 
    'allowed_origins_patterns' => [],
 
    'allowed_headers' => ['*'],
 
    'exposed_headers' => ["Content-Disposition"],
 
    'max_age' => 0,
 
    'supports_credentials' => true,
 
];

You can also learn how to create password protected ZIP file using command line.

Right now, this only works for Mac OS X.

2 Replies to “Create ZIP file with password – PHP”

  1. Link exchange is nothing else but it is just placing the other person’s website link on your page at appropriate
    place and other person will also do same in favor of you.

Comments are closed.