Create an Encrypted Zip Archive with PHP

Create an encrypted zip archive with PHP

Note: this answer recommends a cryptographic method that is known
insecure, even with good password. Please see link from comments
and the Winzip QA on AES. Support for in-php AES zip encryption
arrives with php 7.2 (and libzip 1.2.0), which means this
answer will soon be outdated too. Until then see this answer for how
to call out to 7z instead of the zip command, which supports winzip's
AES encryption.

You can use this:

<?php echo system('zip -P pass file.zip file.txt'); ?>

Where pass is the password, and file.txt will be zipped into file.zip. This should work on Windows and Linux, you just need to get a free version of zip for Windows ( http://www.info-zip.org/Zip.html#Win32 )

This kind of security can be broken by brute force attacks, dictionary attacks and etc. But it's not that easy, specially if you chose a long and hard to guess password.

Create a zip archive with a password

If anyone will face the same problem as I did, here is the solution:
Just add -jrq after zip in shell_exec like this:

shell_exec('zip -jrq -P '.$zipPassword.' '.$zipFileName.'.zip '.$fileName);

After that, full path will be ignored.

ZIP a file and protect with a password in PHP

Yes, creation of password protected archives is not supported (they will be created simply as non-protected archives).

But, still it can be used to extract password protected archives.

Returning to the problem.

You always can just

<?php echo system('zip -P pass file.zip file.txt'); ?>

(this will work both on Windows and our beloved Linux)

But, if it not fits into your requirements, let's continue.

I would suggest you to use DotNetZip (Windows only), you will exactly dynamically generate AES-encrypted zip archives from PHP.

<?php
// origin: https://stackoverflow.com/a/670804/3684575
try
{
$fname = "zip-generated-from-php-" . date('Y-m-d-His') . ".zip";
$zipOutput = "c:\\temp\\" . $fname;
$zipfact = new COM("Ionic.Zip.ZipFile");
$zip->Name = $zipOutput;
$dirToZip= "c:\\temp\\psh";
# Encryption: 3 => 256-bit AES.
# 2 => 128-bit AES.
# 1 => PKZIP (Weak).
# 0 => None
$zip->Encryption = 3;
$zip->Password = "AES-Encryption-Is-Secure";
$zip->AddDirectory($dirToZip);
$zip->Save();
$zip->Dispose();

if (file_exists($zipOutput))
{
header('Cache-Control: no-cache, must-revalidate');
header('Content-Type: application/x-zip');
header('Content-Disposition: attachment; filename=' . $fname);
header('Content-Length: ' . filesize($zipOutput));
readfile($zipOutput);
unlink($zipOutput);
}
else
{
echo '<html>';
echo ' <head>';
echo ' <title>Calling DotNetZip from PHP through COM</title>';
echo ' <link rel="stylesheet" href="basic.css"/>';
echo ' </head>';
echo '<body>';
echo '<h2>Whoops!</h2>' . "<br/>\n";
echo '<p>The file was not successfully generated.</p>';
echo '</body>';
echo '</html>';
}
}
catch (Exception $e)
{
echo '<html>';
echo ' <head>';
echo ' <title>Calling DotNetZip from PHP through COM</title>';
echo ' <link rel="stylesheet" href="basic.css"/>';
echo ' </head>';
echo '<body>';
echo '<h2>Whoops!</h2>' . "<br/>\n";
echo '<p>The file was not successfully generated.</p>';
echo '<p>Caught exception: ', $e->getMessage(), '</p>', "\n";
echo '<pre>';
echo $e->getTraceAsString(), "\n";
echo '</pre>';
echo '</body>';
echo '</html>';
}

?>

But still, this is very dirty solution and more of that, not works on Linux.

So, although PHP is a mature language, there is no adequate method (excluding custom extension or something like that) to achieve such a simple task with pure PHP.

What you also can do, is to wait until PHP 7.2 will be available for production (cuz ZipArchive::setEncryptionName is implemented (thanks to Pierre and Remi)).

But, until then you also can try to port php_zip >= 1.14.0 to PHP < 7.2, but there is currently no compiled binaries available, so you have to compile it yourself and try if it is possible at all (I believe it is).

p.s. I would try it, but have no VS2015+ on my PC right now.

How to send an Encrypted Zip Archive as Mail Attachment in PHP?

Note : Most Servers will mark the attachment as unsafe as they wont be able to scan the zip archive for malicious files.

Following is the Code to send an Encrypted Zip Archive as mail attachment in PHP.

<?php

$file_key="password"; //Password for the Zip Archive

$receiver_name = "Receiver Name";
$receiver_email = "Receiver Email";

$sender_name = "Sender Name";
$sender_mail = "Sender Mail";

//Main Content
$main_subject = "Mail Subject";
$main_body = "Mail Body";

echo "Creating Zip Archive <br>";
$zip = new ZipArchive();
$filename = "final-level.zip"; //Zip File Name
if ($zip->open($filename, ZipArchive::CREATE)===TRUE) {
$zip->setPassword($file_key);
$zip->addFile(
"./dir/test.txt", //File Directory
"test.txt" //New File Name inside Zip Archive
);
$zip->setEncryptionName('text.txt', //New File Name
ZipArchive::EM_AES_256); //Encryption
$zip->close();
}else{
echo "Cannot open Zip file <br>";
exit("cannot open <$filename>\n");
}
echo "Created Zip File <br>";
//#############################DO NOT CHANGE ANYTHING BELOW THIS LINE#############################
$file = chunk_split(base64_encode(file_get_contents($filename)));
$uid = md5(uniqid(time()));
//Sending mail to Server
$retval = mail($receiver_email, $main_subject, "--$uid\r\nContent-type:text/html; charset=iso-8859-1\r\nContent-Transfer-Encoding: 7bit\r\n\r\n$main_body \r\n\r\n--$uid\r\nContent-Type: application/octet-stream; name=\"$filename\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment; filename=\"$filename\"\r\n\r\n$file\r\n\r\n--$uid--", "From: $sender_name <$sender_mail>\r\nReply-To: $sender_mail\r\nMIME-Version: 1.0\r\nContent-Type: multipart/mixed; boundary=\"$uid\"\r\n\r\n");

//#############################DO NOT CHANGE ANYTHING ABOVE THIS LINE#############################
//Output
if ($retval == true) {
echo "Message sent successfully...";
} else {
echo "Error<br>";
echo "Message could not be sent...Try again later";
}
//Delete File from Server
if (file_exists($filename)) {
unlink($filename);
}
echo "Unlinked File from Server <br>";
echo "Done <br>";

How to extract zip archive in PHP if file encrypted using setEncryptionName

You didn't set password correctly.

Zip files with password:

# Creating new zip object
$zip = new ZipArchive();
if ($zip->open('file.zip', ZipArchive::CREATE) === TRUE) {

# Setting password here
$zip->setPassword('12345');

# Adding some files to zip
$zip->addFile('some-file.txt');
$zip->setEncryptionName('some-file.txt', ZipArchive::EM_AES_256);

# Closing instance of zip object
$zip->close();

exit("Done! Your zip is ready!")
} else {
exit("Whoops:( Failed to create zip.");
}

And unzip like this:

# Creating new ZipArchive instance
$zip = new ZipArchive();

# Open file to read
if ($zip->open('file.zip') === true) {

# Enter your password
$zip->setPassword('12345');

# Extract files to some destination
# dirname(__FILE__) sets destination to directory of current file
$zip->extractTo(dirname(__FILE__));

# Closing instance of zip object
$zip->close();
}

How to create password protected archive file in PHP?

Easy peasy lemon squeezy (no).

Yes, creation of password protected archives is not supported (they will be created simply as non-protected archives, as you just described).

But, still it can be used to extract password protected archives.

Returning to the problem.

You always can just

<?php echo system('zip -P pass file.zip file.txt'); ?>

(this will work both on Windows and our beloved Linux)

But, if it not fits into your requirements, let's continue.

I would suggest you to use DotNetZip (Windows only), you will exactly dynamically generate AES-encrypted zip archives from PHP.

<?php
// origin: https://stackoverflow.com/a/670804/3684575
try
{
$fname = "zip-generated-from-php-" . date('Y-m-d-His') . ".zip";
$zipOutput = "c:\\temp\\" . $fname;
$zipfact = new COM("Ionic.Zip.ZipFile");
$zip->Name = $zipOutput;
$dirToZip= "c:\\temp\\psh";
# Encryption: 3 => 256-bit AES.
# 2 => 128-bit AES.
# 1 => PKZIP (Weak).
# 0 => None
$zip->Encryption = 3;
$zip->Password = "AES-Encryption-Is-Secure";
$zip->AddDirectory($dirToZip);
$zip->Save();
$zip->Dispose();

if (file_exists($zipOutput))
{
header('Cache-Control: no-cache, must-revalidate');
header('Content-Type: application/x-zip');
header('Content-Disposition: attachment; filename=' . $fname);
header('Content-Length: ' . filesize($zipOutput));
readfile($zipOutput);
unlink($zipOutput);
}
else
{
echo '<html>';
echo ' <head>';
echo ' <title>Calling DotNetZip from PHP through COM</title>';
echo ' <link rel="stylesheet" href="basic.css"/>';
echo ' </head>';
echo '<body>';
echo '<h2>Whoops!</h2>' . "<br/>\n";
echo '<p>The file was not successfully generated.</p>';
echo '</body>';
echo '</html>';
}
}
catch (Exception $e)
{
echo '<html>';
echo ' <head>';
echo ' <title>Calling DotNetZip from PHP through COM</title>';
echo ' <link rel="stylesheet" href="basic.css"/>';
echo ' </head>';
echo '<body>';
echo '<h2>Whoops!</h2>' . "<br/>\n";
echo '<p>The file was not successfully generated.</p>';
echo '<p>Caught exception: ', $e->getMessage(), '</p>', "\n";
echo '<pre>';
echo $e->getTraceAsString(), "\n";
echo '</pre>';
echo '</body>';
echo '</html>';
}

?>

But still, this is very dirty solution and more of that, not works on Linux.

So, although PHP is a mature language, there is no adequate method (excluding custom extension or something like that) to achieve such a simple task with pure PHP.

What you also can do, is to wait until PHP 7.2 will be available for production (cuz ZipArchive::setEncryptionName is implemented (thanks to Pierre and Remi)).

But, until then you also can try to port php_zip >= 1.14.0 to PHP < 7.2, but there is currently no compiled binaries available, so you have to compile it yourself and try if it is possible at all (I believe it is).

p.s. I would try it, but have no VS2015+ on my PC right now.

Opening and creating password protected zip files with PHP

You can create simple file zip using some libraries (as PclZip) but you can't create zip with the password.



Related Topics



Leave a reply



Submit