使用 PHP 创建加密的 zip 存档
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/646195/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Create an encrypted zip archive with PHP
提问by Digits
I am searching for a way to encrypt a .txt file into a zip, but in a secure password protected way. My goal is to email this file to me, without anyone being able to read the content of the attachment.
我正在寻找一种将 .txt 文件加密为 zip 的方法,但采用安全的密码保护方式。我的目标是将此文件通过电子邮件发送给我,而任何人都无法阅读附件的内容。
Does anybody know an easy, and above all, secure way to accomplish this ? I can create zip archives, but I do not know how to encrypt them, or, how secure this is.
有没有人知道一个简单的,最重要的是,安全的方法来完成这个?我可以创建 zip 档案,但我不知道如何加密它们,或者,这有多安全。
采纳答案by fromvega
Note: this answer recommends a cryptographic method that is known insecure, even with good password. Please see link from commentsand 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.
注意:这个答案推荐了一种已知不安全的加密方法,即使密码很好。请参阅来自评论和AES 上的 Winzip QA 的链接。php 7.2(和libzip 1.2.0)支持 in-php AES zip 加密,这意味着这个答案很快也会过时。在此之前,请参阅此答案,了解如何调用 7z 而不是 zip 命令,该命令支持 winzip 的 AES 加密。
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)
其中 pass 是密码,file.txt 将被压缩到 file.zip 中。这应该适用于 Windows 和 Linux,您只需要为 Windows 获取一个免费版本的 zip ( 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.
这种安全性可以被蛮力攻击、字典攻击等破坏。但这并不是那么容易,特别是如果你选择了一个又长又难猜的密码。
回答by ftrotter
As of php 7.2 (which was released a hours ago), the right way to do this is to use additional functionality included in ZipArchivenative php code. (thanks to abraham-tugalovfor pointing out that this change was coming)
从 php 7.2(几个小时前发布)开始,正确的方法是使用ZipArchive原生 php 代码中包含的附加功能。(感谢abraham-tugalov指出这一变化即将到来)
Now the simple answer looks something like this:
现在简单的答案看起来像这样:
<?php
$zip = new ZipArchive();
if ($zip->open('test.zip', ZipArchive::CREATE) === TRUE) {
$zip->setPassword('secret_used_as_default_for_all_files'); //set default password
$zip->addFile('thing1.txt'); //add file
$zip->setEncryptionName('thing1.txt', ZipArchive::EM_AES_256); //encrypt it
$zip->addFile('thing2.txt'); //add file
$zip->setEncryptionName('thing2.txt', ZipArchive::EM_AES_256); //encrypt it
$zip->close();
echo "Added thing1 and thing2 with the same password\n";
} else {
echo "KO\n";
}
?>
But you can also set the encryption method by index and not name, and you can set each password on a per-file basis... as well as specify weaker encryption options, using the newly supported encryption options.
但是您也可以通过索引而不是名称来设置加密方法,并且您可以在每个文件的基础上设置每个密码......以及使用新支持的加密选项指定较弱的加密选项。
This example exercises these more complex options.
这个例子练习了这些更复杂的选项。
<?php
$zip = new ZipArchive();
if ($zip->open('test.zip', ZipArchive::CREATE) === TRUE) {
//being here means that we were able to create the file..
//setting this means that we do not need to pass in a password to every file, this will be the default
$zip->addFile('thing3.txt');
//$zip->setEncryptionName('thing3.txt', ZipArchive::EM_AES_128);
//$zip->setEncryptionName('thing3.txt', ZipArchive::EM_AES_192);
//you should just use ZipArchive::EM_AES_256 unless you have super-good reason why not.
$zip->setEncryptionName('thing3.txt', ZipArchive::EM_AES_256, 'password_for_thing3');
$zip->addFile('thing4.txt');
//or you can also use the index (starting at 0) of the file...
//which means the following line should do the same thing...
//but just referencing the text.txt by index instead of name..
//$zip->setEncryptionIndex(1, ZipArchive::EM_AES_256, 'password_for_thing_4'); //encrypt thing4, using its index instead of its name...
$zip->close();
echo "Added thing3 and thing4 with two different passwords\n";
} else {
echo "KO\n";
}
?>
The underlying support for zip encryption is enabled because libzip 1.2.0 introduced support for encryption. So you will need to have php 7.2 and libzip 7.2 in order to run this code... Hopefully this note will be cruft on this answer "real soon"
启用了对 zip 加密的底层支持,因为 libzip 1.2.0 引入了对加密的支持。因此,您需要拥有 php 7.2 和 libzip 7.2 才能运行此代码...
回答by Abraham Tugalov
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.
虽然 PHP 是一种成熟的语言,但没有足够的方法(不包括自定义扩展或类似的东西)来用纯 PHP 来完成如此简单的任务。
What you also can do, is to wait until PHP 7.2will be available for production (because ZipArchive::setEncryptionNameis implemented (thanks to Pierre and Remi)).
您还可以做的是等到PHP 7.2可用于生产(因为ZipArchive::setEncryptionName已实现(感谢 Pierre 和 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).
但是,在那之前,您还可以尝试将php_zip>= 1.14.0移植到 PHP < 7.2,但是目前没有可用的已编译二进制文件,因此您必须自己编译它并尝试是否有可能(我相信它是)。
PS I would try it, but have no VS2015+ on my PC right now.
PS 我会尝试一下,但现在我的 PC 上没有 VS2015+。
回答by Cheeso
More and more tools are supporting AES-encrypted ZIP files. It works, it's secure.
越来越多的工具支持 AES 加密的 ZIP 文件。它有效,它是安全的。
EDIT2: You can use DotNetZipfrom PHP to dynamically generate AES-encrypted zip archives from PHP. DotNetZip is a .NET library that is designed for .NET languages (C#, VB, etc). It runs only on Windows :(. But DotNetZip does AES, and it's free, and it works from PHP.
EDIT2:您可以使用PHP 中的DotNetZip从 PHP 动态生成 AES 加密的 zip 存档。DotNetZip 是一个 .NET 库,专为 .NET 语言(C#、VB 等)设计。它只能在 Windows 上运行 :(。但是 DotNetZip 可以使用 AES,而且它是免费的,并且可以通过 PHP 运行。
This is the code I used. (PHP v5.2.9 on Win32)
这是我使用的代码。(Win32 上的 PHP v5.2.9)
<?php
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>';
}
?>
I had to modify DotNetZip to make it work with PHP: I had to make the Name property read/write, and I had to make it COM-callable. This change is first available in the v1.8.2.3 release.
我必须修改 DotNetZip 以使其与 PHP 一起使用:我必须使 Name 属性读/写,并且必须使其可 COM 调用。此更改首先在v1.8.2.3 版本中可用。
回答by Joeri
This is how I did it. It's with an excel, but it's the same thing.
我就是这样做的。这是一个excel,但它是一样的。
- Let php create a random codename.
- Save the codename in db or in a file to be included by the retrieve.php.
Mail yourself the codename.
Access via web the retrieve.php?codename=[codename]
- Let php check if codename is correct. (maybe even it's age).
- Create the excel/textfile in memory from the data that needs to be send to you.
- Create an encryption code by adding a local password (that only you know) with the codename.( I say add but can also be mixed or xor-ed or substr... )
- Encrypt on the fly with the created encryption code.
- Remove the codename from db or config file.
- Return this encrypted document in a mail (zipped or not for size).
Maybe add two first characters from codename in the mail to know what local full codename to use.
Use a local decryption script to decode the downloaded file. Use same codename/password algorithm to create a decryption key.
- 让 php 创建一个随机代号。
- 将代号保存在 db 或一个文件中,以包含在retrieve.php 中。
给自己邮寄代号。
通过网络访问retrieve.php?codename=[codename]
- 让 php 检查代号是否正确。(甚至可能是年龄)。
- 根据需要发送给您的数据在内存中创建 excel/textfile。
- 通过添加带有代号的本地密码(只有您知道)来创建加密代码。(我说添加但也可以混合或异或或子字符串...)
- 使用创建的加密代码即时加密。
- 从数据库或配置文件中删除代号。
- 在邮件中返回此加密文档(压缩或不压缩)。
也许在邮件中添加代号的前两个字符以了解要使用的本地完整代号。
使用本地解密脚本对下载的文件进行解码。使用相同的代号/密码算法来创建解密密钥。
I use gibberish-aes-php. ( https://github.com/ivantcholakov/gibberish-aes-php)
Because then I can use https://github.com/mdp/gibberish-aesas javascript on a client decoder (for things I want to take a quick peek at in a browser).
我使用乱码-aes-php。(https://github.com/ivantcholakov/gibberish-aes-php)
因为那样我可以在客户端解码器上使用https://github.com/mdp/gibberish-aes作为 javascript(对于我想快速在浏览器中查看)。

