ZipPasswordTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. <?php
  2. namespace PhpZip;
  3. use PhpZip\Exception\ZipAuthenticationException;
  4. use PhpZip\Model\ZipInfo;
  5. use PhpZip\Util\CryptoUtil;
  6. /**
  7. * Tests with zip password.
  8. */
  9. class ZipPasswordTest extends ZipFileAddDirTest
  10. {
  11. /**
  12. * Test archive password.
  13. */
  14. public function testSetPassword()
  15. {
  16. if (PHP_INT_SIZE === 4) {
  17. $this->markTestSkipped('Skip test for 32-bit system. Not support Traditional PKWARE Encryption.');
  18. }
  19. $password = base64_encode(CryptoUtil::randomBytes(100));
  20. $badPassword = "bad password";
  21. // create encryption password with ZipCrypto
  22. $zipFile = new ZipFile();
  23. $zipFile->addDir(__DIR__);
  24. $zipFile->setPassword($password, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL);
  25. $zipFile->saveAsFile($this->outputFilename);
  26. $zipFile->close();
  27. self::assertCorrectZipArchive($this->outputFilename, $password);
  28. // check bad password for ZipCrypto
  29. $zipFile->openFile($this->outputFilename);
  30. $zipFile->setReadPassword($badPassword);
  31. foreach ($zipFile->getListFiles() as $entryName) {
  32. try {
  33. $zipFile[$entryName];
  34. self::fail("Expected Exception has not been raised.");
  35. } catch (ZipAuthenticationException $ae) {
  36. self::assertNotNull($ae);
  37. }
  38. }
  39. // check correct password for ZipCrypto
  40. $zipFile->setReadPassword($password);
  41. foreach ($zipFile->getAllInfo() as $info) {
  42. self::assertTrue($info->isEncrypted());
  43. self::assertContains('ZipCrypto', $info->getMethodName());
  44. $decryptContent = $zipFile[$info->getName()];
  45. self::assertNotEmpty($decryptContent);
  46. self::assertContains('<?php', $decryptContent);
  47. }
  48. // change encryption method to WinZip Aes and update file
  49. $zipFile->setPassword($password, ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES);
  50. $zipFile->saveAsFile($this->outputFilename);
  51. $zipFile->close();
  52. self::assertCorrectZipArchive($this->outputFilename, $password);
  53. // check from WinZip AES encryption
  54. $zipFile->openFile($this->outputFilename);
  55. // set bad password WinZip AES
  56. $zipFile->setReadPassword($badPassword);
  57. foreach ($zipFile->getListFiles() as $entryName) {
  58. try {
  59. $zipFile[$entryName];
  60. self::fail("Expected Exception has not been raised.");
  61. } catch (ZipAuthenticationException $ae) {
  62. self::assertNotNull($ae);
  63. }
  64. }
  65. // set correct password WinZip AES
  66. $zipFile->setReadPassword($password);
  67. foreach ($zipFile->getAllInfo() as $info) {
  68. self::assertTrue($info->isEncrypted());
  69. self::assertContains('WinZip', $info->getMethodName());
  70. $decryptContent = $zipFile[$info->getName()];
  71. self::assertNotEmpty($decryptContent);
  72. self::assertContains('<?php', $decryptContent);
  73. }
  74. // clear password
  75. $zipFile->addFromString('file1', '');
  76. $zipFile->disableEncryption();
  77. $zipFile->addFromString('file2', '');
  78. $zipFile->saveAsFile($this->outputFilename);
  79. $zipFile->close();
  80. self::assertCorrectZipArchive($this->outputFilename);
  81. // check remove password
  82. $zipFile->openFile($this->outputFilename);
  83. foreach ($zipFile->getAllInfo() as $info) {
  84. self::assertFalse($info->isEncrypted());
  85. }
  86. $zipFile->close();
  87. }
  88. public function testTraditionalEncryption()
  89. {
  90. if (PHP_INT_SIZE === 4) {
  91. $this->markTestSkipped('Skip test for 32-bit system. Not support Traditional PKWARE Encryption.');
  92. }
  93. $password = base64_encode(CryptoUtil::randomBytes(50));
  94. $zip = new ZipFile();
  95. $zip->addDirRecursive($this->outputDirname);
  96. $zip->setPassword($password, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL);
  97. $zip->saveAsFile($this->outputFilename);
  98. $zip->close();
  99. self::assertCorrectZipArchive($this->outputFilename, $password);
  100. $zip->openFile($this->outputFilename);
  101. $zip->setReadPassword($password);
  102. self::assertFilesResult($zip, array_keys(self::$files));
  103. foreach ($zip->getAllInfo() as $info) {
  104. if (!$info->isFolder()) {
  105. self::assertTrue($info->isEncrypted());
  106. self::assertContains('ZipCrypto', $info->getMethodName());
  107. }
  108. }
  109. $zip->close();
  110. }
  111. /**
  112. * @dataProvider winZipKeyStrengthProvider
  113. * @param int $encryptionMethod
  114. * @param int $bitSize
  115. */
  116. public function testWinZipAesEncryption($encryptionMethod, $bitSize)
  117. {
  118. $password = base64_encode(CryptoUtil::randomBytes(50));
  119. $zip = new ZipFile();
  120. $zip->addDirRecursive($this->outputDirname);
  121. $zip->setPassword($password, $encryptionMethod);
  122. $zip->saveAsFile($this->outputFilename);
  123. $zip->close();
  124. self::assertCorrectZipArchive($this->outputFilename, $password);
  125. $zip->openFile($this->outputFilename);
  126. $zip->setReadPassword($password);
  127. self::assertFilesResult($zip, array_keys(self::$files));
  128. foreach ($zip->getAllInfo() as $info) {
  129. if (!$info->isFolder()) {
  130. self::assertTrue($info->isEncrypted());
  131. self::assertEquals($info->getEncryptionMethod(), $encryptionMethod);
  132. self::assertContains('WinZip AES-' . $bitSize, $info->getMethodName());
  133. }
  134. }
  135. $zip->close();
  136. }
  137. /**
  138. * @return array
  139. */
  140. public function winZipKeyStrengthProvider()
  141. {
  142. return [
  143. [ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128, 128],
  144. [ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192, 192],
  145. [ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES, 256],
  146. [ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256, 256],
  147. ];
  148. }
  149. public function testEncryptionEntries()
  150. {
  151. if (PHP_INT_SIZE === 4) {
  152. $this->markTestSkipped('Skip test for 32-bit system. Not support Traditional PKWARE Encryption.');
  153. }
  154. $password1 = '353442434235424234';
  155. $password2 = 'adgerhvrwjhqqehtqhkbqrgewg';
  156. $zip = new ZipFile();
  157. $zip->addDir($this->outputDirname);
  158. $zip->setPasswordEntry('.hidden', $password1, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL);
  159. $zip->setPasswordEntry('text file.txt', $password2, ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES);
  160. $zip->saveAsFile($this->outputFilename);
  161. $zip->close();
  162. $zip->openFile($this->outputFilename);
  163. $zip->setReadPasswordEntry('.hidden', $password1);
  164. $zip->setReadPasswordEntry('text file.txt', $password2);
  165. self::assertFilesResult($zip, [
  166. '.hidden',
  167. 'text file.txt',
  168. 'Текстовый документ.txt',
  169. 'empty dir/',
  170. ]);
  171. $info = $zip->getEntryInfo('.hidden');
  172. self::assertTrue($info->isEncrypted());
  173. self::assertContains('ZipCrypto', $info->getMethodName());
  174. $info = $zip->getEntryInfo('text file.txt');
  175. self::assertTrue($info->isEncrypted());
  176. self::assertContains('WinZip AES', $info->getMethodName());
  177. self::assertFalse($zip->getEntryInfo('Текстовый документ.txt')->isEncrypted());
  178. self::assertFalse($zip->getEntryInfo('empty dir/')->isEncrypted());
  179. $zip->close();
  180. }
  181. public function testEncryptionEntriesWithDefaultPassword()
  182. {
  183. if (PHP_INT_SIZE === 4) {
  184. $this->markTestSkipped('Skip test for 32-bit system. Not support Traditional PKWARE Encryption.');
  185. }
  186. $password1 = '353442434235424234';
  187. $password2 = 'adgerhvrwjhqqehtqhkbqrgewg';
  188. $defaultPassword = ' f f f f f ffff f5 ';
  189. $zip = new ZipFile();
  190. $zip->addDir($this->outputDirname);
  191. $zip->setPassword($defaultPassword);
  192. $zip->setPasswordEntry('.hidden', $password1, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL);
  193. $zip->setPasswordEntry('text file.txt', $password2, ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES);
  194. $zip->saveAsFile($this->outputFilename);
  195. $zip->close();
  196. $zip->openFile($this->outputFilename);
  197. $zip->setReadPassword($defaultPassword);
  198. $zip->setReadPasswordEntry('.hidden', $password1);
  199. $zip->setReadPasswordEntry('text file.txt', $password2);
  200. self::assertFilesResult($zip, [
  201. '.hidden',
  202. 'text file.txt',
  203. 'Текстовый документ.txt',
  204. 'empty dir/',
  205. ]);
  206. $info = $zip->getEntryInfo('.hidden');
  207. self::assertTrue($info->isEncrypted());
  208. self::assertContains('ZipCrypto', $info->getMethodName());
  209. $info = $zip->getEntryInfo('text file.txt');
  210. self::assertTrue($info->isEncrypted());
  211. self::assertContains('WinZip AES', $info->getMethodName());
  212. $info = $zip->getEntryInfo('Текстовый документ.txt');
  213. self::assertTrue($info->isEncrypted());
  214. self::assertContains('WinZip AES', $info->getMethodName());
  215. self::assertFalse($zip->getEntryInfo('empty dir/')->isEncrypted());
  216. $zip->close();
  217. }
  218. /**
  219. * @expectedException \PhpZip\Exception\ZipException
  220. * @expectedExceptionMessage Invalid encryption method
  221. */
  222. public function testSetEncryptionMethodInvalid()
  223. {
  224. $zipFile = new ZipFile();
  225. $encryptionMethod = 9999;
  226. $zipFile->setPassword('pass', $encryptionMethod);
  227. $zipFile['entry'] = 'content';
  228. $zipFile->outputAsString();
  229. }
  230. public function testEntryPassword()
  231. {
  232. $zipFile = new ZipFile();
  233. $zipFile->setPassword('pass');
  234. $zipFile['file'] = 'content';
  235. self::assertFalse($zipFile->getEntryInfo('file')->isEncrypted());
  236. for ($i = 1; $i <= 10; $i++) {
  237. $zipFile['file' . $i] = 'content';
  238. if ($i < 6) {
  239. $zipFile->setPasswordEntry('file' . $i, 'pass');
  240. self::assertTrue($zipFile->getEntryInfo('file' . $i)->isEncrypted());
  241. } else {
  242. self::assertFalse($zipFile->getEntryInfo('file' . $i)->isEncrypted());
  243. }
  244. }
  245. $zipFile->disableEncryptionEntry('file3');
  246. self::assertFalse($zipFile->getEntryInfo('file3')->isEncrypted());
  247. self::asserttrue($zipFile->getEntryInfo('file2')->isEncrypted());
  248. $zipFile->disableEncryption();
  249. $infoList = $zipFile->getAllInfo();
  250. array_walk($infoList, function (ZipInfo $zipInfo) {
  251. self::assertFalse($zipInfo->isEncrypted());
  252. });
  253. $zipFile->close();
  254. }
  255. /**
  256. * @expectedException \PhpZip\Exception\ZipException
  257. * @expectedExceptionMessage Invalid encryption method
  258. */
  259. public function testInvalidEncryptionMethodEntry()
  260. {
  261. $zipFile = new ZipFile();
  262. $zipFile->addFromString('file', 'content', ZipFileInterface::METHOD_STORED);
  263. $zipFile->setPasswordEntry('file', 'pass', 99);
  264. }
  265. public function testArchivePasswordUpdateWithoutSetReadPassword()
  266. {
  267. $zipFile = new ZipFile();
  268. $zipFile['file1'] = 'content';
  269. $zipFile['file2'] = 'content';
  270. $zipFile['file3'] = 'content';
  271. $zipFile->setPassword('password');
  272. $zipFile->saveAsFile($this->outputFilename);
  273. $zipFile->close();
  274. self::assertCorrectZipArchive($this->outputFilename, 'password');
  275. $zipFile->openFile($this->outputFilename);
  276. self::assertCount(3, $zipFile);
  277. foreach ($zipFile->getAllInfo() as $info) {
  278. self::assertTrue($info->isEncrypted());
  279. }
  280. unset($zipFile['file3']);
  281. $zipFile['file4'] = 'content';
  282. $zipFile->rewrite();
  283. self::assertCorrectZipArchive($this->outputFilename, 'password');
  284. self::assertCount(3, $zipFile);
  285. self::assertFalse(isset($zipFile['file3']));
  286. self::assertTrue(isset($zipFile['file4']));
  287. self::assertTrue($zipFile->getEntryInfo('file1')->isEncrypted());
  288. self::assertTrue($zipFile->getEntryInfo('file2')->isEncrypted());
  289. self::assertFalse($zipFile->getEntryInfo('file4')->isEncrypted());
  290. self::assertEquals($zipFile['file4'], 'content');
  291. $zipFile->extractTo($this->outputDirname, ['file4']);
  292. self::assertTrue(file_exists($this->outputDirname . DIRECTORY_SEPARATOR . 'file4'));
  293. self::assertEquals(file_get_contents($this->outputDirname . DIRECTORY_SEPARATOR . 'file4'), $zipFile['file4']);
  294. $zipFile->close();
  295. }
  296. }