ZipFileTest.php 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215
  1. <?php
  2. namespace PhpZip;
  3. use PhpZip\Exception\InvalidArgumentException;
  4. use PhpZip\Exception\ZipEntryNotFoundException;
  5. use PhpZip\Exception\ZipException;
  6. use PhpZip\Exception\ZipUnsupportMethodException;
  7. use PhpZip\Model\ZipEntry;
  8. use PhpZip\Model\ZipInfo;
  9. use PhpZip\Util\FilesUtil;
  10. use Psr\Http\Message\ResponseInterface;
  11. use Zend\Diactoros\Response;
  12. /**
  13. * ZipFile test.
  14. *
  15. * @internal
  16. *
  17. * @small
  18. */
  19. class ZipFileTest extends ZipTestCase
  20. {
  21. /**
  22. * @throws ZipException
  23. */
  24. public function testOpenFileCantExists()
  25. {
  26. $this->setExpectedException(ZipException::class, 'does not exist');
  27. $zipFile = new ZipFile();
  28. $zipFile->openFile(uniqid('', true));
  29. }
  30. /**
  31. * @throws ZipException
  32. */
  33. public function testOpenFileCantOpen()
  34. {
  35. $this->setExpectedException(ZipException::class, 'can\'t open');
  36. /** @noinspection PhpComposerExtensionStubsInspection */
  37. if (posix_getuid() === 0) {
  38. static::markTestSkipped('Skip the test for a user with root privileges');
  39. return;
  40. }
  41. static::assertNotFalse(file_put_contents($this->outputFilename, 'content'));
  42. static::assertTrue(chmod($this->outputFilename, 0222));
  43. $zipFile = new ZipFile();
  44. $zipFile->openFile($this->outputFilename);
  45. }
  46. /**
  47. * @throws ZipException
  48. */
  49. public function testOpenFileEmptyFile()
  50. {
  51. $this->setExpectedException(ZipException::class, 'Invalid zip file');
  52. static::assertNotFalse(touch($this->outputFilename));
  53. $zipFile = new ZipFile();
  54. $zipFile->openFile($this->outputFilename);
  55. }
  56. /**
  57. * @throws ZipException
  58. * @throws \Exception
  59. */
  60. public function testOpenFileInvalidZip()
  61. {
  62. $this->setExpectedException(
  63. ZipException::class,
  64. 'Expected Local File Header or (ZIP64) End Of Central Directory Record'
  65. );
  66. static::assertNotFalse(file_put_contents($this->outputFilename, random_bytes(255)));
  67. $zipFile = new ZipFile();
  68. $zipFile->openFile($this->outputFilename);
  69. }
  70. /**
  71. * @throws ZipException
  72. */
  73. public function testOpenFromStringNullString()
  74. {
  75. $this->setExpectedException(InvalidArgumentException::class, 'Empty string passed');
  76. $zipFile = new ZipFile();
  77. $zipFile->openFromString(null);
  78. }
  79. /**
  80. * @throws ZipException
  81. */
  82. public function testOpenFromStringEmptyString()
  83. {
  84. $this->setExpectedException(InvalidArgumentException::class, 'Empty string passed');
  85. $zipFile = new ZipFile();
  86. $zipFile->openFromString('');
  87. }
  88. /**
  89. * @throws ZipException
  90. * @throws \Exception
  91. */
  92. public function testOpenFromStringInvalidZip()
  93. {
  94. $this->setExpectedException(
  95. ZipException::class,
  96. 'Expected Local File Header or (ZIP64) End Of Central Directory Record'
  97. );
  98. $zipFile = new ZipFile();
  99. $zipFile->openFromString(random_bytes(255));
  100. }
  101. /**
  102. * @throws ZipException
  103. */
  104. public function testOpenFromString()
  105. {
  106. $zipFile = new ZipFile();
  107. $zipFile->addFromString('file', 'content');
  108. $zipFile['file2'] = 'content 2';
  109. $zipContents = $zipFile->outputAsString();
  110. $zipFile->close();
  111. $zipFile->openFromString($zipContents);
  112. static::assertSame($zipFile->count(), 2);
  113. static::assertTrue(isset($zipFile['file']));
  114. static::assertTrue(isset($zipFile['file2']));
  115. static::assertSame($zipFile['file'], 'content');
  116. static::assertSame($zipFile['file2'], 'content 2');
  117. $zipFile->close();
  118. }
  119. /**
  120. * @throws ZipException
  121. */
  122. public function testOpenFromStreamNullStream()
  123. {
  124. $this->setExpectedException(InvalidArgumentException::class, 'Invalid stream resource');
  125. $zipFile = new ZipFile();
  126. $zipFile->openFromStream(null);
  127. }
  128. /**
  129. * @throws ZipException
  130. */
  131. public function testOpenFromStreamInvalidResourceType()
  132. {
  133. $this->setExpectedException(InvalidArgumentException::class, 'Invalid stream resource');
  134. $zipFile = new ZipFile();
  135. /** @noinspection PhpParamsInspection */
  136. $zipFile->openFromStream('stream resource');
  137. }
  138. /**
  139. * @throws ZipException
  140. */
  141. public function testOpenFromStreamInvalidResourceType2()
  142. {
  143. $this->setExpectedException(InvalidArgumentException::class, 'Invalid resource type - gd.');
  144. $zipFile = new ZipFile();
  145. if (!\extension_loaded('gd')) {
  146. static::markTestSkipped('not extension gd');
  147. return;
  148. }
  149. /** @noinspection PhpComposerExtensionStubsInspection */
  150. $zipFile->openFromStream(imagecreate(1, 1));
  151. }
  152. /**
  153. * @throws ZipException
  154. */
  155. public function testOpenFromStreamInvalidResourceType3()
  156. {
  157. $this->setExpectedException(InvalidArgumentException::class, 'Invalid stream type - dir.');
  158. $zipFile = new ZipFile();
  159. $zipFile->openFromStream(opendir(__DIR__));
  160. }
  161. /**
  162. * @throws ZipException
  163. * @noinspection PhpUsageOfSilenceOperatorInspection
  164. * @noinspection NestedPositiveIfStatementsInspection
  165. */
  166. public function testOpenFromStreamNoSeekable()
  167. {
  168. $this->setExpectedException(InvalidArgumentException::class, 'Resource cannot seekable stream.');
  169. if (!$fp = @fopen('http://localhost', 'rb')) {
  170. if (!$fp = @fopen('http://example.org', 'rb')) {
  171. static::markTestSkipped('not connected to localhost or remote host');
  172. return;
  173. }
  174. }
  175. $zipFile = new ZipFile();
  176. $zipFile->openFromStream($fp);
  177. }
  178. /**
  179. * @throws ZipException
  180. */
  181. public function testOpenFromStreamEmptyContents()
  182. {
  183. $this->setExpectedException(ZipException::class, 'Invalid zip file');
  184. $fp = fopen($this->outputFilename, 'w+b');
  185. $zipFile = new ZipFile();
  186. $zipFile->openFromStream($fp);
  187. }
  188. /**
  189. * @throws ZipException
  190. * @throws \Exception
  191. */
  192. public function testOpenFromStreamInvalidZip()
  193. {
  194. $this->setExpectedException(
  195. ZipException::class,
  196. 'Expected Local File Header or (ZIP64) End Of Central Directory Record'
  197. );
  198. $fp = fopen($this->outputFilename, 'w+b');
  199. fwrite($fp, random_bytes(255));
  200. $zipFile = new ZipFile();
  201. $zipFile->openFromStream($fp);
  202. }
  203. /**
  204. * @throws ZipException
  205. */
  206. public function testOpenFromStream()
  207. {
  208. $zipFile = new ZipFile();
  209. $zipFile
  210. ->addFromString('file', 'content')
  211. ->saveAsFile($this->outputFilename)
  212. ->close()
  213. ;
  214. $handle = fopen($this->outputFilename, 'rb');
  215. $zipFile->openFromStream($handle);
  216. static::assertSame($zipFile->count(), 1);
  217. static::assertTrue(isset($zipFile['file']));
  218. static::assertSame($zipFile['file'], 'content');
  219. $zipFile->close();
  220. }
  221. /**
  222. * Test create, open and extract empty archive.
  223. *
  224. * @throws ZipException
  225. */
  226. public function testEmptyArchive()
  227. {
  228. $zipFile = new ZipFile();
  229. $zipFile
  230. ->saveAsFile($this->outputFilename)
  231. ->close()
  232. ;
  233. static::assertCorrectEmptyZip($this->outputFilename);
  234. static::assertTrue(mkdir($this->outputDirname, 0755, true));
  235. $zipFile->openFile($this->outputFilename);
  236. static::assertSame($zipFile->count(), 0);
  237. $zipFile
  238. ->extractTo($this->outputDirname)
  239. ->close()
  240. ;
  241. static::assertTrue(FilesUtil::isEmptyDir($this->outputDirname));
  242. }
  243. /**
  244. * No modified archive.
  245. *
  246. * @throws ZipException
  247. *
  248. * @see ZipOutputFile::create()
  249. */
  250. public function testNoModifiedArchive()
  251. {
  252. static::assertTrue(mkdir($this->outputDirname, 0755, true));
  253. $fileActual = $this->outputDirname . \DIRECTORY_SEPARATOR . 'file_actual.zip';
  254. $fileExpected = $this->outputDirname . \DIRECTORY_SEPARATOR . 'file_expected.zip';
  255. $zipFile = new ZipFile();
  256. $zipFile->addDirRecursive(__DIR__ . '/../../src');
  257. $sourceCount = $zipFile->count();
  258. static::assertTrue($sourceCount > 0);
  259. $zipFile
  260. ->saveAsFile($fileActual)
  261. ->close()
  262. ;
  263. static::assertCorrectZipArchive($fileActual);
  264. $zipFile
  265. ->openFile($fileActual)
  266. ->saveAsFile($fileExpected)
  267. ;
  268. static::assertCorrectZipArchive($fileExpected);
  269. $zipFileExpected = new ZipFile();
  270. $zipFileExpected->openFile($fileExpected);
  271. static::assertSame($zipFile->count(), $sourceCount);
  272. static::assertSame($zipFileExpected->count(), $zipFile->count());
  273. static::assertSame($zipFileExpected->getListFiles(), $zipFile->getListFiles());
  274. foreach ($zipFile as $entryName => $content) {
  275. static::assertSame($zipFileExpected[$entryName], $content);
  276. }
  277. $zipFileExpected->close();
  278. $zipFile->close();
  279. }
  280. /**
  281. * Create archive and add files.
  282. *
  283. * @throws ZipException
  284. *
  285. * @see ZipOutputFile::addFromFile()
  286. * @see ZipOutputFile::addFromStream()
  287. * @see ZipFile::getEntryContents()
  288. * @see ZipOutputFile::addFromString()
  289. */
  290. public function testCreateArchiveAndAddFiles()
  291. {
  292. $outputFromString = file_get_contents(__FILE__);
  293. $outputFromString2 = file_get_contents(\dirname(\dirname(__DIR__)) . \DIRECTORY_SEPARATOR . 'README.md');
  294. $outputFromFile = file_get_contents(\dirname(\dirname(__DIR__)) . \DIRECTORY_SEPARATOR . 'phpunit.xml');
  295. $outputFromStream = file_get_contents(\dirname(\dirname(__DIR__)) . \DIRECTORY_SEPARATOR . 'composer.json');
  296. $filenameFromString = basename(__FILE__);
  297. $filenameFromString2 = 'test_file.txt';
  298. $filenameFromFile = 'data/test file.txt';
  299. $filenameFromStream = 'data/ডিরেক্টরি/αρχείο.json';
  300. $emptyDirName = 'empty dir/пустой каталог/空目錄/ไดเรกทอรีที่ว่างเปล่า/';
  301. $emptyDirName2 = 'empty dir/пустой каталог/';
  302. $emptyDirName3 = 'empty dir/пустой каталог/ещё один пустой каталог/';
  303. $tempFile = tempnam(sys_get_temp_dir(), 'txt');
  304. file_put_contents($tempFile, $outputFromFile);
  305. $tempStream = tmpfile();
  306. fwrite($tempStream, $outputFromStream);
  307. $zipFile = new ZipFile();
  308. $zipFile
  309. ->addFromString($filenameFromString, $outputFromString)
  310. ->addFile($tempFile, $filenameFromFile)
  311. ->addFromStream($tempStream, $filenameFromStream)
  312. ->addEmptyDir($emptyDirName)
  313. ;
  314. $zipFile[$filenameFromString2] = $outputFromString2;
  315. $zipFile[$emptyDirName2] = null;
  316. $zipFile[$emptyDirName3] = 'this content ignoring';
  317. static::assertSame(\count($zipFile), 7);
  318. $zipFile
  319. ->saveAsFile($this->outputFilename)
  320. ->close()
  321. ;
  322. unlink($tempFile);
  323. static::assertCorrectZipArchive($this->outputFilename);
  324. $zipFile->openFile($this->outputFilename);
  325. static::assertSame(\count($zipFile), 7);
  326. static::assertSame($zipFile[$filenameFromString], $outputFromString);
  327. static::assertSame($zipFile[$filenameFromFile], $outputFromFile);
  328. static::assertSame($zipFile[$filenameFromStream], $outputFromStream);
  329. static::assertSame($zipFile[$filenameFromString2], $outputFromString2);
  330. static::assertTrue(isset($zipFile[$emptyDirName]));
  331. static::assertTrue(isset($zipFile[$emptyDirName2]));
  332. static::assertTrue(isset($zipFile[$emptyDirName3]));
  333. static::assertTrue($zipFile->isDirectory($emptyDirName));
  334. static::assertTrue($zipFile->isDirectory($emptyDirName2));
  335. static::assertTrue($zipFile->isDirectory($emptyDirName3));
  336. $listFiles = $zipFile->getListFiles();
  337. static::assertSame($listFiles[0], $filenameFromString);
  338. static::assertSame($listFiles[1], $filenameFromFile);
  339. static::assertSame($listFiles[2], $filenameFromStream);
  340. static::assertSame($listFiles[3], $emptyDirName);
  341. static::assertSame($listFiles[4], $filenameFromString2);
  342. static::assertSame($listFiles[5], $emptyDirName2);
  343. static::assertSame($listFiles[6], $emptyDirName3);
  344. $zipFile->close();
  345. }
  346. /**
  347. * @throws ZipException
  348. */
  349. public function testEmptyContent()
  350. {
  351. $zipFile = new ZipFile();
  352. $zipFile['file'] = '';
  353. $zipFile->saveAsFile($this->outputFilename);
  354. $zipFile->close();
  355. $zipFile->openFile($this->outputFilename);
  356. static::assertSame($zipFile['file'], '');
  357. $zipFile->close();
  358. }
  359. /**
  360. * Test compression method from image file.
  361. *
  362. * @throws ZipException
  363. */
  364. public function testCompressionMethodFromImageMimeType()
  365. {
  366. if (!\function_exists('mime_content_type')) {
  367. static::markTestSkipped('Function mime_content_type not exists');
  368. return;
  369. }
  370. $outputFilename = $this->outputFilename;
  371. $this->outputFilename .= '.gif';
  372. static::assertNotFalse(
  373. file_put_contents(
  374. $this->outputFilename,
  375. base64_decode('R0lGODlhAQABAJAAAP8AAAAAACH5BAUQAAAALAAAAAABAAEAAAICBAEAOw==')
  376. )
  377. );
  378. $basename = basename($this->outputFilename);
  379. $zipFile = new ZipFile();
  380. $zipFile->addFile($this->outputFilename, $basename);
  381. $zipFile->saveAsFile($outputFilename);
  382. unlink($this->outputFilename);
  383. $this->outputFilename = $outputFilename;
  384. $zipFile->openFile($this->outputFilename);
  385. $info = $zipFile->getEntryInfo($basename);
  386. static::assertSame($info->getMethodName(), 'No compression');
  387. $zipFile->close();
  388. }
  389. /**
  390. * Rename zip entry name.
  391. *
  392. * @throws ZipException
  393. */
  394. public function testRename()
  395. {
  396. $oldName = basename(__FILE__);
  397. $newName = 'tests/' . $oldName;
  398. $zipFile = new ZipFile();
  399. $zipFile->addDir(__DIR__);
  400. $zipFile->saveAsFile($this->outputFilename);
  401. $zipFile->close();
  402. static::assertCorrectZipArchive($this->outputFilename);
  403. $zipFile->openFile($this->outputFilename);
  404. $zipFile->rename($oldName, $newName);
  405. $zipFile->addFromString('file1.txt', 'content');
  406. $zipFile->addFromString('file2.txt', 'content');
  407. $zipFile->addFromString('file3.txt', 'content');
  408. $zipFile->rename('file1.txt', 'file_long_name.txt');
  409. $zipFile->rename('file2.txt', 'file4.txt');
  410. $zipFile->rename('file3.txt', 'fi.txt');
  411. $zipFile->saveAsFile($this->outputFilename);
  412. $zipFile->close();
  413. static::assertCorrectZipArchive($this->outputFilename);
  414. $zipFile->openFile($this->outputFilename);
  415. static::assertFalse(isset($zipFile[$oldName]));
  416. static::assertTrue(isset($zipFile[$newName]));
  417. static::assertFalse(isset($zipFile['file1.txt']));
  418. static::assertFalse(isset($zipFile['file2.txt']));
  419. static::assertFalse(isset($zipFile['file3.txt']));
  420. static::assertTrue(isset($zipFile['file_long_name.txt']));
  421. static::assertTrue(isset($zipFile['file4.txt']));
  422. static::assertTrue(isset($zipFile['fi.txt']));
  423. $zipFile->close();
  424. }
  425. /**
  426. * @throws ZipException
  427. */
  428. public function testRenameEntryNull()
  429. {
  430. $this->setExpectedException(InvalidArgumentException::class, 'name is null');
  431. $zipFile = new ZipFile();
  432. $zipFile->rename(null, 'new-file');
  433. }
  434. /**
  435. * @throws ZipException
  436. */
  437. public function testRenameEntryNull2()
  438. {
  439. $this->setExpectedException(InvalidArgumentException::class, 'name is null');
  440. $zipFile = new ZipFile();
  441. $zipFile->rename('old-file', null);
  442. }
  443. /**
  444. * @throws ZipException
  445. */
  446. public function testRenameEntryToExistsNewEntry()
  447. {
  448. $this->setExpectedException(InvalidArgumentException::class, 'is exists');
  449. $zipFile = new ZipFile();
  450. $zipFile['file'] = 'content';
  451. $zipFile['file2'] = 'content 2';
  452. $zipFile->saveAsFile($this->outputFilename);
  453. $zipFile->close();
  454. $zipFile = new ZipFile();
  455. $zipFile->openFile($this->outputFilename);
  456. $zipFile->rename('file2', 'file');
  457. }
  458. /**
  459. * @throws ZipException
  460. */
  461. public function testRenameEntryNotFound()
  462. {
  463. $this->setExpectedException(ZipEntryNotFoundException::class);
  464. $zipFile = new ZipFile();
  465. $zipFile['file'] = 'content';
  466. $zipFile['file2'] = 'content 2';
  467. $zipFile->saveAsFile($this->outputFilename);
  468. $zipFile->close();
  469. $zipFile = new ZipFile();
  470. $zipFile->openFile($this->outputFilename);
  471. $zipFile->rename('file2.bak', 'file3');
  472. }
  473. /**
  474. * Delete entry from name.
  475. *
  476. * @throws ZipException
  477. */
  478. public function testDeleteFromName()
  479. {
  480. $inputDir = \dirname(\dirname(__DIR__)) . \DIRECTORY_SEPARATOR;
  481. $deleteEntryName = 'composer.json';
  482. $zipFile = new ZipFile();
  483. $zipFile->addDir($inputDir);
  484. $zipFile->saveAsFile($this->outputFilename);
  485. $zipFile->close();
  486. static::assertCorrectZipArchive($this->outputFilename);
  487. $zipFile->openFile($this->outputFilename);
  488. $zipFile->deleteFromName($deleteEntryName);
  489. $zipFile->saveAsFile($this->outputFilename);
  490. $zipFile->close();
  491. static::assertCorrectZipArchive($this->outputFilename);
  492. $zipFile->openFile($this->outputFilename);
  493. static::assertFalse(isset($zipFile[$deleteEntryName]));
  494. $zipFile->close();
  495. }
  496. /**
  497. * @throws Exception\ZipEntryNotFoundException
  498. * @throws ZipException
  499. */
  500. public function testDeleteNewEntry()
  501. {
  502. $zipFile = new ZipFile();
  503. $zipFile['entry1'] = '';
  504. $zipFile['entry2'] = '';
  505. $zipFile->deleteFromName('entry2');
  506. $zipFile->saveAsFile($this->outputFilename);
  507. $zipFile->close();
  508. $zipFile->openFile($this->outputFilename);
  509. static::assertSame(\count($zipFile), 1);
  510. static::assertTrue(isset($zipFile['entry1']));
  511. static::assertFalse(isset($zipFile['entry2']));
  512. $zipFile->close();
  513. }
  514. /**
  515. * @throws ZipEntryNotFoundException
  516. */
  517. public function testDeleteFromNameNotFoundEntry()
  518. {
  519. $this->setExpectedException(ZipEntryNotFoundException::class);
  520. $zipFile = new ZipFile();
  521. $zipFile->deleteFromName('entry');
  522. }
  523. /**
  524. * Delete zip entries from glob pattern.
  525. *
  526. * @throws ZipException
  527. */
  528. public function testDeleteFromGlob()
  529. {
  530. $inputDir = \dirname(\dirname(__DIR__));
  531. $zipFile = new ZipFile();
  532. $zipFile->addFilesFromGlobRecursive($inputDir, '**.{xml,json,md}', '/');
  533. static::assertTrue(isset($zipFile['composer.json']));
  534. static::assertTrue(isset($zipFile['phpunit.xml']));
  535. $zipFile->saveAsFile($this->outputFilename);
  536. $zipFile->close();
  537. static::assertCorrectZipArchive($this->outputFilename);
  538. $zipFile->openFile($this->outputFilename);
  539. static::assertTrue(isset($zipFile['composer.json']));
  540. static::assertTrue(isset($zipFile['phpunit.xml']));
  541. $zipFile->deleteFromGlob('**.{xml,json}');
  542. static::assertFalse(isset($zipFile['composer.json']));
  543. static::assertFalse(isset($zipFile['phpunit.xml']));
  544. $zipFile->saveAsFile($this->outputFilename);
  545. $zipFile->close();
  546. static::assertCorrectZipArchive($this->outputFilename);
  547. $zipFile->openFile($this->outputFilename);
  548. static::assertTrue($zipFile->count() > 0);
  549. foreach ($zipFile->getListFiles() as $name) {
  550. static::assertStringEndsWith('.md', $name);
  551. }
  552. $zipFile->close();
  553. }
  554. public function testDeleteFromGlobFailNull()
  555. {
  556. $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified');
  557. $zipFile = new ZipFile();
  558. $zipFile->deleteFromGlob(null);
  559. }
  560. public function testDeleteFromGlobFailEmpty()
  561. {
  562. $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified');
  563. $zipFile = new ZipFile();
  564. $zipFile->deleteFromGlob('');
  565. }
  566. /**
  567. * Delete entries from regex pattern.
  568. *
  569. * @throws ZipException
  570. */
  571. public function testDeleteFromRegex()
  572. {
  573. $inputDir = \dirname(\dirname(__DIR__));
  574. $zipFile = new ZipFile();
  575. $zipFile->addFilesFromRegexRecursive($inputDir, '~\.(xml|json)$~i', 'Path');
  576. $zipFile->saveAsFile($this->outputFilename);
  577. $zipFile->close();
  578. static::assertCorrectZipArchive($this->outputFilename);
  579. $zipFile->openFile($this->outputFilename);
  580. $zipFile->deleteFromRegex('~\.(json)$~i');
  581. $zipFile->addFromString('test.txt', 'content');
  582. $zipFile->deleteFromRegex('~\.txt$~');
  583. $zipFile->saveAsFile($this->outputFilename);
  584. $zipFile->close();
  585. static::assertCorrectZipArchive($this->outputFilename);
  586. $zipFile->openFile($this->outputFilename);
  587. static::assertFalse(isset($zipFile['Path/composer.json']));
  588. static::assertFalse(isset($zipFile['Path/test.txt']));
  589. static::assertTrue(isset($zipFile['Path/phpunit.xml']));
  590. $zipFile->close();
  591. }
  592. public function testDeleteFromRegexFailNull()
  593. {
  594. $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified');
  595. $zipFile = new ZipFile();
  596. $zipFile->deleteFromRegex(null);
  597. }
  598. public function testDeleteFromRegexFailEmpty()
  599. {
  600. $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified');
  601. $zipFile = new ZipFile();
  602. $zipFile->deleteFromRegex('');
  603. }
  604. /**
  605. * Delete all entries.
  606. *
  607. * @throws ZipException
  608. */
  609. public function testDeleteAll()
  610. {
  611. $zipFile = new ZipFile();
  612. $zipFile->addDirRecursive(\dirname(\dirname(__DIR__)) . \DIRECTORY_SEPARATOR . 'src');
  613. static::assertTrue($zipFile->count() > 0);
  614. $zipFile->saveAsFile($this->outputFilename);
  615. $zipFile->close();
  616. static::assertCorrectZipArchive($this->outputFilename);
  617. $zipFile->openFile($this->outputFilename);
  618. static::assertTrue($zipFile->count() > 0);
  619. $zipFile->deleteAll();
  620. $zipFile->saveAsFile($this->outputFilename);
  621. $zipFile->close();
  622. static::assertCorrectEmptyZip($this->outputFilename);
  623. $zipFile->openFile($this->outputFilename);
  624. static::assertSame($zipFile->count(), 0);
  625. $zipFile->close();
  626. }
  627. /**
  628. * Test zip archive comment.
  629. *
  630. * @throws ZipException
  631. */
  632. public function testArchiveComment()
  633. {
  634. $comment = 'This zip file comment' . \PHP_EOL
  635. . 'Αυτό το σχόλιο αρχείο zip' . \PHP_EOL
  636. . 'Это комментарий zip архива' . \PHP_EOL
  637. . '這個ZIP文件註釋' . \PHP_EOL
  638. . 'ეს zip ფაილის კომენტარი' . \PHP_EOL
  639. . 'このzipファイルにコメント' . \PHP_EOL
  640. . 'ความคิดเห็นนี้ไฟล์ซิป';
  641. $zipFile = new ZipFile();
  642. $zipFile->setArchiveComment($comment);
  643. $zipFile->addFile(__FILE__);
  644. $zipFile->saveAsFile($this->outputFilename);
  645. $zipFile->close();
  646. static::assertCorrectZipArchive($this->outputFilename);
  647. $zipFile->openFile($this->outputFilename);
  648. static::assertSame($zipFile->getArchiveComment(), $comment);
  649. $zipFile->setArchiveComment(null); // remove archive comment
  650. $zipFile->saveAsFile($this->outputFilename);
  651. $zipFile->close();
  652. static::assertCorrectZipArchive($this->outputFilename);
  653. // check empty comment
  654. $zipFile->openFile($this->outputFilename);
  655. static::assertNull($zipFile->getArchiveComment());
  656. $zipFile->close();
  657. }
  658. /**
  659. * Test very long archive comment.
  660. */
  661. public function testVeryLongArchiveComment()
  662. {
  663. $this->setExpectedException(InvalidArgumentException::class);
  664. $comment = 'Very long comment' . \PHP_EOL .
  665. 'Очень длинный комментарий' . \PHP_EOL;
  666. $comment = str_repeat($comment, ceil(0xffff / \strlen($comment)) + \strlen($comment) + 1);
  667. $zipFile = new ZipFile();
  668. $zipFile->setArchiveComment($comment);
  669. }
  670. /**
  671. * Test zip entry comment.
  672. *
  673. * @throws ZipException
  674. * @throws \Exception
  675. */
  676. public function testEntryComment()
  677. {
  678. $entries = [
  679. '文件1.txt' => [
  680. 'data' => random_bytes(255),
  681. 'comment' => '這是註釋的條目。',
  682. ],
  683. 'file2.txt' => [
  684. 'data' => random_bytes(255),
  685. 'comment' => null,
  686. ],
  687. 'file3.txt' => [
  688. 'data' => random_bytes(255),
  689. 'comment' => random_bytes(255),
  690. ],
  691. 'file4.txt' => [
  692. 'data' => random_bytes(255),
  693. 'comment' => 'Комментарий файла',
  694. ],
  695. 'file5.txt' => [
  696. 'data' => random_bytes(255),
  697. 'comment' => 'ไฟล์แสดงความคิดเห็น',
  698. ],
  699. 'file6 emoji 🙍🏼.txt' => [
  700. 'data' => random_bytes(255),
  701. 'comment' => 'Emoji comment file - 😀 ⛈ ❤️ 🤴🏽',
  702. ],
  703. ];
  704. // create archive with entry comments
  705. $zipFile = new ZipFile();
  706. foreach ($entries as $entryName => $item) {
  707. $zipFile->addFromString($entryName, $item['data']);
  708. $zipFile->setEntryComment($entryName, $item['comment']);
  709. }
  710. $zipFile->saveAsFile($this->outputFilename);
  711. $zipFile->close();
  712. static::assertCorrectZipArchive($this->outputFilename);
  713. // check and modify comments
  714. $zipFile->openFile($this->outputFilename);
  715. foreach ($zipFile->getListFiles() as $entryName) {
  716. $entriesItem = $entries[$entryName];
  717. static::assertNotEmpty($entriesItem);
  718. static::assertSame($zipFile[$entryName], $entriesItem['data']);
  719. static::assertSame($zipFile->getEntryComment($entryName), (string) $entriesItem['comment']);
  720. }
  721. // modify comment
  722. $entries['file5.txt']['comment'] = mt_rand(1, 100000000);
  723. $zipFile->setEntryComment('file5.txt', $entries['file5.txt']['comment']);
  724. $zipFile->saveAsFile($this->outputFilename);
  725. $zipFile->close();
  726. static::assertCorrectZipArchive($this->outputFilename);
  727. // check modify comments
  728. $zipFile->openFile($this->outputFilename);
  729. foreach ($entries as $entryName => $entriesItem) {
  730. static::assertTrue(isset($zipFile[$entryName]));
  731. static::assertSame($zipFile->getEntryComment($entryName), (string) $entriesItem['comment']);
  732. static::assertSame($zipFile[$entryName], $entriesItem['data']);
  733. }
  734. $zipFile->close();
  735. }
  736. /**
  737. * Test zip entry very long comment.
  738. *
  739. * @throws ZipException
  740. */
  741. public function testVeryLongEntryComment()
  742. {
  743. $this->setExpectedException(ZipException::class, 'Comment too long');
  744. $comment = 'Very long comment' . \PHP_EOL .
  745. 'Очень длинный комментарий' . \PHP_EOL;
  746. $comment = str_repeat($comment, ceil(0xffff / \strlen($comment)) + \strlen($comment) + 1);
  747. $zipFile = new ZipFile();
  748. $zipFile->addFile(__FILE__, 'test');
  749. $zipFile->setEntryComment('test', $comment);
  750. }
  751. /**
  752. * @throws ZipException
  753. */
  754. public function testSetEntryCommentNotFoundEntry()
  755. {
  756. $this->setExpectedException(ZipEntryNotFoundException::class);
  757. $zipFile = new ZipFile();
  758. $zipFile->setEntryComment('test', 'comment');
  759. }
  760. /**
  761. * Test all available support compression methods.
  762. *
  763. * @throws ZipException
  764. * @throws \Exception
  765. */
  766. public function testCompressionMethod()
  767. {
  768. $entries = [
  769. '1' => [
  770. 'data' => random_bytes(255),
  771. 'method' => ZipFile::METHOD_STORED,
  772. 'expected' => 'No compression',
  773. ],
  774. '2' => [
  775. 'data' => random_bytes(255),
  776. 'method' => ZipFile::METHOD_DEFLATED,
  777. 'expected' => 'Deflate',
  778. ],
  779. ];
  780. if (\extension_loaded('bz2')) {
  781. $entries['3'] = [
  782. 'data' => random_bytes(255),
  783. 'method' => ZipFile::METHOD_BZIP2,
  784. 'expected' => 'Bzip2',
  785. ];
  786. }
  787. $zipFile = new ZipFile();
  788. foreach ($entries as $entryName => $item) {
  789. $zipFile->addFromString($entryName, $item['data'], $item['method']);
  790. }
  791. $zipFile->saveAsFile($this->outputFilename);
  792. $zipFile->close();
  793. static::assertCorrectZipArchive($this->outputFilename);
  794. $zipFile->openFile($this->outputFilename);
  795. $zipFile->setCompressionLevel(ZipFile::LEVEL_BEST_COMPRESSION);
  796. $zipAllInfo = $zipFile->getAllInfo();
  797. foreach ($zipAllInfo as $entryName => $info) {
  798. static::assertSame($zipFile[$entryName], $entries[$entryName]['data']);
  799. static::assertSame($info->getMethodName(), $entries[$entryName]['expected']);
  800. $entryInfo = $zipFile->getEntryInfo($entryName);
  801. static::assertEquals($entryInfo, $info);
  802. }
  803. $zipFile->close();
  804. }
  805. public function testSetInvalidCompressionLevel()
  806. {
  807. $this->setExpectedException(
  808. InvalidArgumentException::class,
  809. 'Invalid compression level. Minimum level -1. Maximum level 9'
  810. );
  811. $zipFile = new ZipFile();
  812. $zipFile->setCompressionLevel(-2);
  813. }
  814. public function testSetInvalidCompressionLevel2()
  815. {
  816. $this->setExpectedException(
  817. InvalidArgumentException::class,
  818. 'Invalid compression level. Minimum level -1. Maximum level 9'
  819. );
  820. $zipFile = new ZipFile();
  821. $zipFile->setCompressionLevel(10);
  822. }
  823. /**
  824. * Test extract all files.
  825. *
  826. * @throws ZipException
  827. * @throws \Exception
  828. */
  829. public function testExtract()
  830. {
  831. $entries = [
  832. 'test1.txt' => random_bytes(255),
  833. 'test2.txt' => random_bytes(255),
  834. 'test/test 2/test3.txt' => random_bytes(255),
  835. 'test empty/dir' => null,
  836. ];
  837. $zipFile = new ZipFile();
  838. foreach ($entries as $entryName => $value) {
  839. if ($value === null) {
  840. $zipFile->addEmptyDir($entryName);
  841. } else {
  842. $zipFile->addFromString($entryName, $value);
  843. }
  844. }
  845. $zipFile->saveAsFile($this->outputFilename);
  846. $zipFile->close();
  847. static::assertTrue(mkdir($this->outputDirname, 0755, true));
  848. $zipFile->openFile($this->outputFilename);
  849. $zipFile->extractTo($this->outputDirname);
  850. foreach ($entries as $entryName => $value) {
  851. $fullExtractedFilename = $this->outputDirname . \DIRECTORY_SEPARATOR . $entryName;
  852. if ($value === null) {
  853. static::assertTrue(is_dir($fullExtractedFilename));
  854. static::assertTrue(FilesUtil::isEmptyDir($fullExtractedFilename));
  855. } else {
  856. static::assertTrue(is_file($fullExtractedFilename));
  857. $contents = file_get_contents($fullExtractedFilename);
  858. static::assertSame($contents, $value);
  859. }
  860. }
  861. $zipFile->close();
  862. }
  863. /**
  864. * Test extract some files.
  865. *
  866. * @throws ZipException
  867. * @throws \Exception
  868. */
  869. public function testExtractSomeFiles()
  870. {
  871. $entries = [
  872. 'test1.txt' => random_bytes(255),
  873. 'test2.txt' => random_bytes(255),
  874. 'test3.txt' => random_bytes(255),
  875. 'test4.txt' => random_bytes(255),
  876. 'test5.txt' => random_bytes(255),
  877. 'test/test/test.txt' => random_bytes(255),
  878. 'test/test/test 2.txt' => random_bytes(255),
  879. 'test empty/dir/' => null,
  880. 'test empty/dir2/' => null,
  881. ];
  882. $extractEntries = [
  883. 'test1.txt',
  884. 'test3.txt',
  885. 'test5.txt',
  886. 'test/test/test 2.txt',
  887. 'test empty/dir2/',
  888. ];
  889. static::assertTrue(mkdir($this->outputDirname, 0755, true));
  890. $zipFile = new ZipFile();
  891. $zipFile->addAll($entries);
  892. $zipFile->saveAsFile($this->outputFilename);
  893. $zipFile->close();
  894. $zipFile->openFile($this->outputFilename);
  895. $zipFile->extractTo($this->outputDirname, $extractEntries);
  896. foreach ($entries as $entryName => $value) {
  897. $fullExtractFilename = $this->outputDirname . \DIRECTORY_SEPARATOR . $entryName;
  898. if (\in_array($entryName, $extractEntries, true)) {
  899. if ($value === null) {
  900. static::assertTrue(is_dir($fullExtractFilename));
  901. static::assertTrue(FilesUtil::isEmptyDir($fullExtractFilename));
  902. } else {
  903. static::assertTrue(is_file($fullExtractFilename));
  904. $contents = file_get_contents($fullExtractFilename);
  905. static::assertEquals($contents, $value);
  906. }
  907. } elseif ($value === null) {
  908. static::assertFalse(is_dir($fullExtractFilename));
  909. } else {
  910. static::assertFalse(is_file($fullExtractFilename));
  911. }
  912. }
  913. static::assertFalse(is_file($this->outputDirname . \DIRECTORY_SEPARATOR . 'test/test/test.txt'));
  914. $zipFile->extractTo($this->outputDirname, 'test/test/test.txt');
  915. static::assertTrue(is_file($this->outputDirname . \DIRECTORY_SEPARATOR . 'test/test/test.txt'));
  916. $zipFile->close();
  917. }
  918. /**
  919. * @throws ZipException
  920. */
  921. public function testExtractFail()
  922. {
  923. $this->setExpectedException(ZipException::class, 'not found');
  924. $zipFile = new ZipFile();
  925. $zipFile['file'] = 'content';
  926. $zipFile->saveAsFile($this->outputFilename);
  927. $zipFile->close();
  928. $zipFile->openFile($this->outputFilename);
  929. $zipFile->extractTo('path/to/path');
  930. }
  931. /**
  932. * @throws ZipException
  933. */
  934. public function testExtractFail2()
  935. {
  936. $this->setExpectedException(ZipException::class, 'Destination is not directory');
  937. $zipFile = new ZipFile();
  938. $zipFile['file'] = 'content';
  939. $zipFile->saveAsFile($this->outputFilename);
  940. $zipFile->close();
  941. $zipFile->openFile($this->outputFilename);
  942. $zipFile->extractTo($this->outputFilename);
  943. }
  944. /**
  945. * @throws ZipException
  946. */
  947. public function testExtractFail3()
  948. {
  949. $this->setExpectedException(ZipException::class, 'Destination is not writable directory');
  950. /** @noinspection PhpComposerExtensionStubsInspection */
  951. if (posix_getuid() === 0) {
  952. static::markTestSkipped('Skip the test for a user with root privileges');
  953. return;
  954. }
  955. $zipFile = new ZipFile();
  956. $zipFile['file'] = 'content';
  957. $zipFile->saveAsFile($this->outputFilename);
  958. $zipFile->close();
  959. static::assertTrue(mkdir($this->outputDirname, 0444, true));
  960. static::assertTrue(chmod($this->outputDirname, 0444));
  961. $zipFile->openFile($this->outputFilename);
  962. $zipFile->extractTo($this->outputDirname);
  963. }
  964. /**
  965. * @noinspection OnlyWritesOnParameterInspection
  966. */
  967. public function testAddFromArrayAccessNullName()
  968. {
  969. $this->setExpectedException(InvalidArgumentException::class, 'entryName is null');
  970. $zipFile = new ZipFile();
  971. $zipFile[null] = 'content';
  972. }
  973. /**
  974. * @noinspection OnlyWritesOnParameterInspection
  975. */
  976. public function testAddFromArrayAccessEmptyName()
  977. {
  978. $this->setExpectedException(InvalidArgumentException::class, 'entryName is empty');
  979. $zipFile = new ZipFile();
  980. $zipFile[''] = 'content';
  981. }
  982. /**
  983. * @throws ZipException
  984. */
  985. public function testAddFromStringNullContents()
  986. {
  987. $this->setExpectedException(InvalidArgumentException::class, 'Contents is null');
  988. $zipFile = new ZipFile();
  989. $zipFile->addFromString('file', null);
  990. }
  991. /**
  992. * @throws ZipException
  993. */
  994. public function testAddFromStringNullEntryName()
  995. {
  996. $this->setExpectedException(InvalidArgumentException::class, 'Entry name is null');
  997. $zipFile = new ZipFile();
  998. $zipFile->addFromString(null, 'contents');
  999. }
  1000. /**
  1001. * @throws ZipException
  1002. */
  1003. public function testAddFromStringUnsupportedMethod()
  1004. {
  1005. $this->setExpectedException(ZipUnsupportMethodException::class, 'Unsupported compression method');
  1006. $zipFile = new ZipFile();
  1007. $zipFile->addFromString('file', 'contents', ZipEntry::METHOD_WINZIP_AES);
  1008. }
  1009. /**
  1010. * @throws ZipException
  1011. */
  1012. public function testAddFromStringEmptyEntryName()
  1013. {
  1014. $this->setExpectedException(InvalidArgumentException::class, 'Empty entry name');
  1015. $zipFile = new ZipFile();
  1016. $zipFile->addFromString('', 'contents');
  1017. }
  1018. /**
  1019. * Test compression method from add string.
  1020. *
  1021. * @throws ZipException
  1022. */
  1023. public function testAddFromStringCompressionMethod()
  1024. {
  1025. $fileStored = sys_get_temp_dir() . '/zip-stored.txt';
  1026. $fileDeflated = sys_get_temp_dir() . '/zip-deflated.txt';
  1027. static::assertNotFalse(file_put_contents($fileStored, 'content'));
  1028. static::assertNotFalse(file_put_contents($fileDeflated, str_repeat('content', 200)));
  1029. $zipFile = new ZipFile();
  1030. $zipFile->addFromString(basename($fileStored), file_get_contents($fileStored));
  1031. $zipFile->addFromString(basename($fileDeflated), file_get_contents($fileDeflated));
  1032. $zipFile->saveAsFile($this->outputFilename);
  1033. $zipFile->close();
  1034. unlink($fileStored);
  1035. unlink($fileDeflated);
  1036. $zipFile->openFile($this->outputFilename);
  1037. $infoStored = $zipFile->getEntryInfo(basename($fileStored));
  1038. $infoDeflated = $zipFile->getEntryInfo(basename($fileDeflated));
  1039. static::assertSame($infoStored->getMethodName(), 'No compression');
  1040. static::assertSame($infoDeflated->getMethodName(), 'Deflate');
  1041. $zipFile->close();
  1042. }
  1043. /**
  1044. * @throws ZipException
  1045. */
  1046. public function testAddFromStreamInvalidResource()
  1047. {
  1048. $this->setExpectedException(InvalidArgumentException::class, 'Stream is not resource');
  1049. $zipFile = new ZipFile();
  1050. /** @noinspection PhpParamsInspection */
  1051. $zipFile->addFromStream('invalid resource', 'name');
  1052. }
  1053. /**
  1054. * @throws ZipException
  1055. */
  1056. public function testAddFromStreamEmptyEntryName()
  1057. {
  1058. $this->setExpectedException(InvalidArgumentException::class, 'Empty entry name');
  1059. $handle = fopen(__FILE__, 'rb');
  1060. $zipFile = new ZipFile();
  1061. $zipFile->addFromStream($handle, '');
  1062. }
  1063. /**
  1064. * @throws ZipException
  1065. */
  1066. public function testAddFromStreamUnsupportedMethod()
  1067. {
  1068. $this->setExpectedException(ZipUnsupportMethodException::class, 'Unsupported method');
  1069. $handle = fopen(__FILE__, 'rb');
  1070. $zipFile = new ZipFile();
  1071. $zipFile->addFromStream($handle, basename(__FILE__), ZipEntry::METHOD_WINZIP_AES);
  1072. }
  1073. /**
  1074. * Test compression method from add stream.
  1075. *
  1076. * @throws ZipException
  1077. */
  1078. public function testAddFromStreamCompressionMethod()
  1079. {
  1080. $fileStored = sys_get_temp_dir() . '/zip-stored.txt';
  1081. $fileDeflated = sys_get_temp_dir() . '/zip-deflated.txt';
  1082. static::assertNotFalse(file_put_contents($fileStored, 'content'));
  1083. static::assertNotFalse(file_put_contents($fileDeflated, str_repeat('content', 200)));
  1084. $fpStored = fopen($fileStored, 'rb');
  1085. $fpDeflated = fopen($fileDeflated, 'rb');
  1086. $zipFile = new ZipFile();
  1087. $zipFile->addFromStream($fpStored, basename($fileStored));
  1088. $zipFile->addFromStream($fpDeflated, basename($fileDeflated));
  1089. $zipFile->saveAsFile($this->outputFilename);
  1090. $zipFile->close();
  1091. unlink($fileStored);
  1092. unlink($fileDeflated);
  1093. $zipFile->openFile($this->outputFilename);
  1094. $infoStored = $zipFile->getEntryInfo(basename($fileStored));
  1095. $infoDeflated = $zipFile->getEntryInfo(basename($fileDeflated));
  1096. static::assertSame($infoStored->getMethodName(), 'No compression');
  1097. static::assertSame($infoDeflated->getMethodName(), 'Deflate');
  1098. $zipFile->close();
  1099. }
  1100. /**
  1101. * @throws ZipException
  1102. */
  1103. public function testAddFileNullFileName()
  1104. {
  1105. $this->setExpectedException(InvalidArgumentException::class, 'file is null');
  1106. $zipFile = new ZipFile();
  1107. $zipFile->addFile(null);
  1108. }
  1109. /**
  1110. * @throws ZipException
  1111. */
  1112. public function testAddFileCantExists()
  1113. {
  1114. $this->setExpectedException(ZipException::class, 'does not exist');
  1115. $zipFile = new ZipFile();
  1116. $zipFile->addFile('path/to/file');
  1117. }
  1118. /**
  1119. * @throws ZipException
  1120. */
  1121. public function testAddFileUnsupportedMethod()
  1122. {
  1123. $this->setExpectedException(ZipUnsupportMethodException::class, 'Unsupported compression method 99');
  1124. $zipFile = new ZipFile();
  1125. $zipFile->addFile(__FILE__, null, ZipEntry::METHOD_WINZIP_AES);
  1126. }
  1127. /**
  1128. * @throws ZipException
  1129. */
  1130. public function testAddFileCantOpen()
  1131. {
  1132. $this->setExpectedException(ZipException::class, 'file could not be read');
  1133. /** @noinspection PhpComposerExtensionStubsInspection */
  1134. if (posix_getuid() === 0) {
  1135. static::markTestSkipped('Skip the test for a user with root privileges');
  1136. return;
  1137. }
  1138. static::assertNotFalse(file_put_contents($this->outputFilename, ''));
  1139. static::assertTrue(chmod($this->outputFilename, 0244));
  1140. $zipFile = new ZipFile();
  1141. $zipFile->addFile($this->outputFilename);
  1142. }
  1143. /**
  1144. * @throws ZipException
  1145. */
  1146. public function testAddDirNullDirname()
  1147. {
  1148. $this->setExpectedException(InvalidArgumentException::class, 'Input dir is null');
  1149. $zipFile = new ZipFile();
  1150. $zipFile->addDir(null);
  1151. }
  1152. /**
  1153. * @throws ZipException
  1154. */
  1155. public function testAddDirEmptyDirname()
  1156. {
  1157. $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified');
  1158. $zipFile = new ZipFile();
  1159. $zipFile->addDir('');
  1160. }
  1161. /**
  1162. * @throws ZipException
  1163. */
  1164. public function testAddDirCantExists()
  1165. {
  1166. $this->setExpectedException(InvalidArgumentException::class, 'does not exist');
  1167. $zipFile = new ZipFile();
  1168. $zipFile->addDir(uniqid('', true));
  1169. }
  1170. /**
  1171. * @throws ZipException
  1172. */
  1173. public function testAddDirRecursiveNullDirname()
  1174. {
  1175. $this->setExpectedException(InvalidArgumentException::class, 'Input dir is null');
  1176. $zipFile = new ZipFile();
  1177. $zipFile->addDirRecursive(null);
  1178. }
  1179. /**
  1180. * @throws ZipException
  1181. */
  1182. public function testAddDirRecursiveEmptyDirname()
  1183. {
  1184. $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified');
  1185. $zipFile = new ZipFile();
  1186. $zipFile->addDirRecursive('');
  1187. }
  1188. /**
  1189. * @throws ZipException
  1190. */
  1191. public function testAddDirRecursiveCantExists()
  1192. {
  1193. $this->setExpectedException(InvalidArgumentException::class, 'does not exist');
  1194. $zipFile = new ZipFile();
  1195. $zipFile->addDirRecursive(uniqid('', true));
  1196. }
  1197. /**
  1198. * @throws ZipException
  1199. */
  1200. public function testAddFilesFromGlobNull()
  1201. {
  1202. $this->setExpectedException(InvalidArgumentException::class, 'Input dir is null');
  1203. $zipFile = new ZipFile();
  1204. $zipFile->addFilesFromGlob(null, '*.png');
  1205. }
  1206. /**
  1207. * @throws ZipException
  1208. */
  1209. public function testAddFilesFromGlobEmpty()
  1210. {
  1211. $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified');
  1212. $zipFile = new ZipFile();
  1213. $zipFile->addFilesFromGlob('', '*.png');
  1214. }
  1215. /**
  1216. * @throws ZipException
  1217. */
  1218. public function testAddFilesFromGlobCantExists()
  1219. {
  1220. $this->setExpectedException(InvalidArgumentException::class, 'does not exist');
  1221. $zipFile = new ZipFile();
  1222. $zipFile->addFilesFromGlob('path/to/path', '*.png');
  1223. }
  1224. /**
  1225. * @throws ZipException
  1226. */
  1227. public function testAddFilesFromGlobNullPattern()
  1228. {
  1229. $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified');
  1230. $zipFile = new ZipFile();
  1231. $zipFile->addFilesFromGlob(__DIR__, null);
  1232. }
  1233. /**
  1234. * @throws ZipException
  1235. */
  1236. public function testAddFilesFromGlobEmptyPattern()
  1237. {
  1238. $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified');
  1239. $zipFile = new ZipFile();
  1240. $zipFile->addFilesFromGlob(__DIR__, '');
  1241. }
  1242. /**
  1243. * @throws ZipException
  1244. */
  1245. public function testAddFilesFromGlobRecursiveNull()
  1246. {
  1247. $this->setExpectedException(InvalidArgumentException::class, 'Input dir is null');
  1248. $zipFile = new ZipFile();
  1249. $zipFile->addFilesFromGlobRecursive(null, '*.png');
  1250. }
  1251. /**
  1252. * @throws ZipException
  1253. */
  1254. public function testAddFilesFromGlobRecursiveEmpty()
  1255. {
  1256. $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified');
  1257. $zipFile = new ZipFile();
  1258. $zipFile->addFilesFromGlobRecursive('', '*.png');
  1259. }
  1260. /**
  1261. * @throws ZipException
  1262. */
  1263. public function testAddFilesFromGlobRecursiveCantExists()
  1264. {
  1265. $this->setExpectedException(InvalidArgumentException::class, 'does not exist');
  1266. $zipFile = new ZipFile();
  1267. $zipFile->addFilesFromGlobRecursive('path/to/path', '*.png');
  1268. }
  1269. /**
  1270. * @throws ZipException
  1271. */
  1272. public function testAddFilesFromGlobRecursiveNullPattern()
  1273. {
  1274. $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified');
  1275. $zipFile = new ZipFile();
  1276. $zipFile->addFilesFromGlobRecursive(__DIR__, null);
  1277. }
  1278. /**
  1279. * @throws ZipException
  1280. */
  1281. public function testAddFilesFromGlobRecursiveEmptyPattern()
  1282. {
  1283. $this->setExpectedException(InvalidArgumentException::class, 'The glob pattern is not specified');
  1284. $zipFile = new ZipFile();
  1285. $zipFile->addFilesFromGlobRecursive(__DIR__, '');
  1286. }
  1287. /**
  1288. * @throws ZipException
  1289. */
  1290. public function testAddFilesFromRegexDirectoryNull()
  1291. {
  1292. $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified');
  1293. $zipFile = new ZipFile();
  1294. $zipFile->addFilesFromRegex(null, '~\.png$~i');
  1295. }
  1296. /**
  1297. * @throws ZipException
  1298. */
  1299. public function testAddFilesFromRegexDirectoryEmpty()
  1300. {
  1301. $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified');
  1302. $zipFile = new ZipFile();
  1303. $zipFile->addFilesFromRegex('', '~\.png$~i');
  1304. }
  1305. /**
  1306. * @throws ZipException
  1307. */
  1308. public function testAddFilesFromRegexCantExists()
  1309. {
  1310. $this->setExpectedException(InvalidArgumentException::class, 'does not exist');
  1311. $zipFile = new ZipFile();
  1312. $zipFile->addFilesFromRegex('path/to/path', '~\.png$~i');
  1313. }
  1314. /**
  1315. * @throws ZipException
  1316. */
  1317. public function testAddFilesFromRegexNullPattern()
  1318. {
  1319. $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified');
  1320. $zipFile = new ZipFile();
  1321. $zipFile->addFilesFromRegex(__DIR__, null);
  1322. }
  1323. /**
  1324. * @throws ZipException
  1325. */
  1326. public function testAddFilesFromRegexEmptyPattern()
  1327. {
  1328. $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified');
  1329. $zipFile = new ZipFile();
  1330. $zipFile->addFilesFromRegex(__DIR__, '');
  1331. }
  1332. /**
  1333. * @throws ZipException
  1334. */
  1335. public function testAddFilesFromRegexRecursiveDirectoryNull()
  1336. {
  1337. $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified');
  1338. $zipFile = new ZipFile();
  1339. $zipFile->addFilesFromRegexRecursive(null, '~\.png$~i');
  1340. }
  1341. /**
  1342. * @throws ZipException
  1343. */
  1344. public function testAddFilesFromRegexRecursiveEmpty()
  1345. {
  1346. $this->setExpectedException(InvalidArgumentException::class, 'The input directory is not specified');
  1347. $zipFile = new ZipFile();
  1348. $zipFile->addFilesFromRegexRecursive('', '~\.png$~i');
  1349. }
  1350. /**
  1351. * @throws ZipException
  1352. */
  1353. public function testAddFilesFromRegexRecursiveCantExists()
  1354. {
  1355. $this->setExpectedException(InvalidArgumentException::class, 'does not exist');
  1356. $zipFile = new ZipFile();
  1357. $zipFile->addFilesFromGlobRecursive('path/to/path', '~\.png$~i');
  1358. }
  1359. /**
  1360. * @throws ZipException
  1361. */
  1362. public function testAddFilesFromRegexRecursiveNullPattern()
  1363. {
  1364. $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified');
  1365. $zipFile = new ZipFile();
  1366. $zipFile->addFilesFromRegexRecursive(__DIR__, null);
  1367. }
  1368. /**
  1369. * @throws ZipException
  1370. */
  1371. public function testAddFilesFromRegexRecursiveEmptyPattern()
  1372. {
  1373. $this->setExpectedException(InvalidArgumentException::class, 'The regex pattern is not specified');
  1374. $zipFile = new ZipFile();
  1375. $zipFile->addFilesFromRegexRecursive(__DIR__, '');
  1376. }
  1377. /**
  1378. * @throws ZipException
  1379. */
  1380. public function testSaveAsStreamBadStream()
  1381. {
  1382. $this->setExpectedException(InvalidArgumentException::class, 'handle is not resource');
  1383. $zipFile = new ZipFile();
  1384. /** @noinspection PhpParamsInspection */
  1385. $zipFile->saveAsStream('bad stream');
  1386. }
  1387. /**
  1388. * @throws ZipException
  1389. */
  1390. public function testSaveAsFileNotWritable()
  1391. {
  1392. $this->setExpectedException(InvalidArgumentException::class, 'can not open from write');
  1393. /** @noinspection PhpComposerExtensionStubsInspection */
  1394. if (posix_getuid() === 0) {
  1395. static::markTestSkipped('Skip the test for a user with root privileges');
  1396. return;
  1397. }
  1398. static::assertTrue(mkdir($this->outputDirname, 0444, true));
  1399. static::assertTrue(chmod($this->outputDirname, 0444));
  1400. $this->outputFilename = $this->outputDirname . \DIRECTORY_SEPARATOR . basename($this->outputFilename);
  1401. $zipFile = new ZipFile();
  1402. $zipFile->saveAsFile($this->outputFilename);
  1403. }
  1404. /**
  1405. * Test `ZipFile` implemented \ArrayAccess, \Countable and |iterator.
  1406. *
  1407. * @throws ZipException
  1408. * @throws \Exception
  1409. */
  1410. public function testZipFileArrayAccessAndCountableAndIterator()
  1411. {
  1412. $files = [];
  1413. $numFiles = mt_rand(20, 100);
  1414. for ($i = 0; $i < $numFiles; $i++) {
  1415. $files['file' . $i . '.txt'] = random_bytes(255);
  1416. }
  1417. $methods = [ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED];
  1418. if (\extension_loaded('bz2')) {
  1419. $methods[] = ZipFile::METHOD_BZIP2;
  1420. }
  1421. $zipFile = new ZipFile();
  1422. $zipFile->setCompressionLevel(ZipFile::LEVEL_BEST_SPEED);
  1423. foreach ($files as $entryName => $content) {
  1424. $zipFile->addFromString($entryName, $content, $methods[array_rand($methods)]);
  1425. }
  1426. $zipFile->saveAsFile($this->outputFilename);
  1427. $zipFile->close();
  1428. static::assertCorrectZipArchive($this->outputFilename);
  1429. $zipFile->openFile($this->outputFilename);
  1430. // Test \Countable
  1431. static::assertSame($zipFile->count(), $numFiles);
  1432. static::assertSame(\count($zipFile), $numFiles);
  1433. // Test \ArrayAccess
  1434. reset($files);
  1435. foreach ($zipFile as $entryName => $content) {
  1436. static::assertSame($entryName, key($files));
  1437. static::assertSame($content, current($files));
  1438. next($files);
  1439. }
  1440. // Test \Iterator
  1441. reset($files);
  1442. $iterator = new \ArrayIterator($zipFile);
  1443. $iterator->rewind();
  1444. while ($iterator->valid()) {
  1445. $key = $iterator->key();
  1446. $value = $iterator->current();
  1447. static::assertSame($key, key($files));
  1448. static::assertSame($value, current($files));
  1449. next($files);
  1450. $iterator->next();
  1451. }
  1452. $zipFile->close();
  1453. $zipFile = new ZipFile();
  1454. $zipFile['file1.txt'] = 'content 1';
  1455. $zipFile['dir/file2.txt'] = 'content 1';
  1456. $zipFile['dir/empty dir/'] = null;
  1457. $zipFile->saveAsFile($this->outputFilename);
  1458. $zipFile->close();
  1459. static::assertCorrectZipArchive($this->outputFilename);
  1460. $zipFile->openFile($this->outputFilename);
  1461. static::assertTrue(isset($zipFile['file1.txt']));
  1462. static::assertTrue(isset($zipFile['dir/file2.txt']));
  1463. static::assertTrue(isset($zipFile['dir/empty dir/']));
  1464. static::assertFalse(isset($zipFile['dir/empty dir/2/']));
  1465. $zipFile['dir/empty dir/2/'] = null;
  1466. unset($zipFile['dir/file2.txt'], $zipFile['dir/empty dir/']);
  1467. $zipFile->saveAsFile($this->outputFilename);
  1468. $zipFile->close();
  1469. static::assertCorrectZipArchive($this->outputFilename);
  1470. $zipFile->openFile($this->outputFilename);
  1471. static::assertTrue(isset($zipFile['file1.txt']));
  1472. static::assertFalse(isset($zipFile['dir/file2.txt']));
  1473. static::assertFalse(isset($zipFile['dir/empty dir/']));
  1474. static::assertTrue(isset($zipFile['dir/empty dir/2/']));
  1475. $zipFile->close();
  1476. }
  1477. /**
  1478. * @throws ZipException
  1479. */
  1480. public function testArrayAccessAddFile()
  1481. {
  1482. $entryName = 'path/to/file.dat';
  1483. $entryNameStream = 'path/to/' . basename(__FILE__);
  1484. $zipFile = new ZipFile();
  1485. $zipFile[$entryName] = new \SplFileInfo(__FILE__);
  1486. $zipFile[$entryNameStream] = fopen(__FILE__, 'rb');
  1487. $zipFile->saveAsFile($this->outputFilename);
  1488. $zipFile->close();
  1489. static::assertCorrectZipArchive($this->outputFilename);
  1490. $zipFile->openFile($this->outputFilename);
  1491. static::assertSame(\count($zipFile), 2);
  1492. static::assertTrue(isset($zipFile[$entryName]));
  1493. static::assertTrue(isset($zipFile[$entryNameStream]));
  1494. static::assertSame($zipFile[$entryName], file_get_contents(__FILE__));
  1495. static::assertSame($zipFile[$entryNameStream], file_get_contents(__FILE__));
  1496. $zipFile->close();
  1497. }
  1498. /**
  1499. * @throws Exception\ZipEntryNotFoundException
  1500. * @throws ZipException
  1501. * @throws \Exception
  1502. */
  1503. public function testUnknownCompressionMethod()
  1504. {
  1505. $zipFile = new ZipFile();
  1506. $zipFile->addFromString('file', 'content', ZipEntry::UNKNOWN);
  1507. $zipFile->addFromString('file2', base64_encode(random_bytes(512)), ZipEntry::UNKNOWN);
  1508. static::assertSame($zipFile->getEntryInfo('file')->getMethodName(), 'Unknown');
  1509. static::assertSame($zipFile->getEntryInfo('file2')->getMethodName(), 'Unknown');
  1510. $zipFile->saveAsFile($this->outputFilename);
  1511. $zipFile->close();
  1512. $zipFile->openFile($this->outputFilename);
  1513. static::assertSame($zipFile->getEntryInfo('file')->getMethodName(), 'No compression');
  1514. static::assertSame($zipFile->getEntryInfo('file2')->getMethodName(), 'Deflate');
  1515. $zipFile->close();
  1516. }
  1517. /**
  1518. * @throws ZipException
  1519. */
  1520. public function testAddEmptyDirNullName()
  1521. {
  1522. $this->setExpectedException(InvalidArgumentException::class, 'Dir name is null');
  1523. $zipFile = new ZipFile();
  1524. $zipFile->addEmptyDir(null);
  1525. }
  1526. /**
  1527. * @throws ZipException
  1528. */
  1529. public function testAddEmptyDirEmptyName()
  1530. {
  1531. $this->setExpectedException(InvalidArgumentException::class, 'Empty dir name');
  1532. $zipFile = new ZipFile();
  1533. $zipFile->addEmptyDir('');
  1534. }
  1535. public function testNotFoundEntry()
  1536. {
  1537. $this->setExpectedException(ZipEntryNotFoundException::class, '"bad entry name"');
  1538. $zipFile = new ZipFile();
  1539. $zipFile['bad entry name'];
  1540. }
  1541. /**
  1542. * Test rewrite input file.
  1543. *
  1544. * @throws ZipException
  1545. */
  1546. public function testRewriteFile()
  1547. {
  1548. $zipFile = new ZipFile();
  1549. $zipFile['file'] = 'content';
  1550. $zipFile['file2'] = 'content2';
  1551. static::assertSame(\count($zipFile), 2);
  1552. $zipFile
  1553. ->saveAsFile($this->outputFilename)
  1554. ->close()
  1555. ;
  1556. $md5file = md5_file($this->outputFilename);
  1557. $zipFile->openFile($this->outputFilename);
  1558. static::assertSame(\count($zipFile), 2);
  1559. static::assertTrue(isset($zipFile['file']));
  1560. static::assertTrue(isset($zipFile['file2']));
  1561. $zipFile['file3'] = 'content3';
  1562. static::assertSame(\count($zipFile), 3);
  1563. $zipFile = $zipFile->rewrite();
  1564. static::assertSame(\count($zipFile), 3);
  1565. static::assertTrue(isset($zipFile['file']));
  1566. static::assertTrue(isset($zipFile['file2']));
  1567. static::assertTrue(isset($zipFile['file3']));
  1568. $zipFile->close();
  1569. static::assertNotSame(md5_file($this->outputFilename), $md5file);
  1570. }
  1571. /**
  1572. * Test rewrite for string.
  1573. *
  1574. * @throws ZipException
  1575. */
  1576. public function testRewriteString()
  1577. {
  1578. $zipFile = new ZipFile();
  1579. $zipFile['file'] = 'content';
  1580. $zipFile['file2'] = 'content2';
  1581. $zipFile->saveAsFile($this->outputFilename);
  1582. $zipFile->close();
  1583. $zipFile->openFromString(file_get_contents($this->outputFilename));
  1584. static::assertSame(\count($zipFile), 2);
  1585. static::assertTrue(isset($zipFile['file']));
  1586. static::assertTrue(isset($zipFile['file2']));
  1587. $zipFile['file3'] = 'content3';
  1588. $zipFile = $zipFile->rewrite();
  1589. static::assertSame(\count($zipFile), 3);
  1590. static::assertTrue(isset($zipFile['file']));
  1591. static::assertTrue(isset($zipFile['file2']));
  1592. static::assertTrue(isset($zipFile['file3']));
  1593. $zipFile->close();
  1594. }
  1595. /**
  1596. * @throws ZipException
  1597. */
  1598. public function testRewriteNullStream()
  1599. {
  1600. $this->setExpectedException(ZipException::class, 'input stream is null');
  1601. $zipFile = new ZipFile();
  1602. $zipFile->rewrite();
  1603. }
  1604. /**
  1605. * @throws ZipException
  1606. */
  1607. public function testFilename0()
  1608. {
  1609. $zipFile = new ZipFile();
  1610. $zipFile[0] = 0;
  1611. static::assertTrue(isset($zipFile[0]));
  1612. static::assertTrue(isset($zipFile['0']));
  1613. static::assertCount(1, $zipFile);
  1614. $zipFile
  1615. ->saveAsFile($this->outputFilename)
  1616. ->close()
  1617. ;
  1618. static::assertCorrectZipArchive($this->outputFilename);
  1619. $zipFile->openFile($this->outputFilename);
  1620. static::assertTrue(isset($zipFile[0]));
  1621. static::assertTrue(isset($zipFile['0']));
  1622. static::assertSame($zipFile['0'], '0');
  1623. static::assertCount(1, $zipFile);
  1624. $zipFile->close();
  1625. static::assertTrue(unlink($this->outputFilename));
  1626. $zipFile = new ZipFile();
  1627. $zipFile->addFromString(0, 0);
  1628. static::assertTrue(isset($zipFile[0]));
  1629. static::assertTrue(isset($zipFile['0']));
  1630. static::assertCount(1, $zipFile);
  1631. $zipFile
  1632. ->saveAsFile($this->outputFilename)
  1633. ->close()
  1634. ;
  1635. static::assertCorrectZipArchive($this->outputFilename);
  1636. }
  1637. /**
  1638. * @throws ZipException
  1639. */
  1640. public function testPsrResponse()
  1641. {
  1642. $zipFile = new ZipFile();
  1643. for ($i = 0; $i < 10; $i++) {
  1644. $zipFile[$i] = $i;
  1645. }
  1646. $filename = 'file.jar';
  1647. $response = $zipFile->outputAsResponse(new Response(), $filename);
  1648. static::assertInstanceOf(ResponseInterface::class, $response);
  1649. static::assertSame('application/java-archive', $response->getHeaderLine('content-type'));
  1650. static::assertSame('attachment; filename="file.jar"', $response->getHeaderLine('content-disposition'));
  1651. }
  1652. /**
  1653. * @throws ZipEntryNotFoundException
  1654. * @throws ZipException
  1655. */
  1656. public function testCompressionLevel()
  1657. {
  1658. $zipFile = new ZipFile();
  1659. $zipFile
  1660. ->addFromString('file', 'content', ZipFile::METHOD_DEFLATED)
  1661. ->setCompressionLevelEntry('file', ZipFile::LEVEL_BEST_COMPRESSION)
  1662. ->addFromString('file2', 'content', ZipFile::METHOD_DEFLATED)
  1663. ->setCompressionLevelEntry('file2', ZipFile::LEVEL_FAST)
  1664. ->addFromString('file3', 'content', ZipFile::METHOD_DEFLATED)
  1665. ->setCompressionLevelEntry('file3', ZipFile::LEVEL_SUPER_FAST)
  1666. ->addFromString('file4', 'content', ZipFile::METHOD_DEFLATED)
  1667. ->setCompressionLevelEntry('file4', ZipFile::LEVEL_DEFAULT_COMPRESSION)
  1668. ->saveAsFile($this->outputFilename)
  1669. ->close()
  1670. ;
  1671. static::assertCorrectZipArchive($this->outputFilename);
  1672. $zipFile->openFile($this->outputFilename);
  1673. static::assertSame(
  1674. $zipFile->getEntryInfo('file')
  1675. ->getCompressionLevel(),
  1676. ZipFile::LEVEL_BEST_COMPRESSION
  1677. );
  1678. static::assertSame(
  1679. $zipFile->getEntryInfo('file2')
  1680. ->getCompressionLevel(),
  1681. ZipFile::LEVEL_FAST
  1682. );
  1683. static::assertSame(
  1684. $zipFile->getEntryInfo('file3')
  1685. ->getCompressionLevel(),
  1686. ZipFile::LEVEL_SUPER_FAST
  1687. );
  1688. static::assertSame(
  1689. $zipFile->getEntryInfo('file4')
  1690. ->getCompressionLevel(),
  1691. ZipFile::LEVEL_DEFAULT_COMPRESSION
  1692. );
  1693. $zipFile->close();
  1694. }
  1695. /**
  1696. * @throws ZipException
  1697. */
  1698. public function testInvalidCompressionLevel()
  1699. {
  1700. $this->setExpectedException(InvalidArgumentException::class, 'Invalid compression level');
  1701. $zipFile = new ZipFile();
  1702. $zipFile->addFromString('file', 'content');
  1703. $zipFile->setCompressionLevel(15);
  1704. }
  1705. /**
  1706. * @throws ZipException
  1707. */
  1708. public function testInvalidCompressionLevelEntry()
  1709. {
  1710. $this->setExpectedException(InvalidArgumentException::class, 'Invalid compression level');
  1711. $zipFile = new ZipFile();
  1712. $zipFile->addFromString('file', 'content');
  1713. $zipFile->setCompressionLevelEntry('file', 15);
  1714. }
  1715. /**
  1716. * @throws ZipException
  1717. */
  1718. public function testCompressionGlobal()
  1719. {
  1720. $zipFile = new ZipFile();
  1721. for ($i = 0; $i < 10; $i++) {
  1722. $zipFile->addFromString('file' . $i, 'content', ZipFile::METHOD_DEFLATED);
  1723. }
  1724. $zipFile
  1725. ->setCompressionLevel(ZipFile::LEVEL_BEST_SPEED)
  1726. ->saveAsFile($this->outputFilename)
  1727. ->close()
  1728. ;
  1729. static::assertCorrectZipArchive($this->outputFilename);
  1730. $zipFile->openFile($this->outputFilename);
  1731. $infoList = $zipFile->getAllInfo();
  1732. array_walk(
  1733. $infoList,
  1734. function (ZipInfo $zipInfo) {
  1735. $this->assertSame($zipInfo->getCompressionLevel(), ZipFile::LEVEL_BEST_SPEED);
  1736. }
  1737. );
  1738. $zipFile->close();
  1739. }
  1740. /**
  1741. * @throws ZipEntryNotFoundException
  1742. * @throws ZipException
  1743. */
  1744. public function testCompressionMethodEntry()
  1745. {
  1746. $zipFile = new ZipFile();
  1747. $zipFile->addFromString('file', 'content', ZipFile::METHOD_STORED);
  1748. $zipFile->saveAsFile($this->outputFilename);
  1749. $zipFile->close();
  1750. $zipFile->openFile($this->outputFilename);
  1751. static::assertSame($zipFile->getEntryInfo('file')->getMethodName(), 'No compression');
  1752. $zipFile->setCompressionMethodEntry('file', ZipFile::METHOD_DEFLATED);
  1753. static::assertSame($zipFile->getEntryInfo('file')->getMethodName(), 'Deflate');
  1754. $zipFile->rewrite();
  1755. static::assertSame($zipFile->getEntryInfo('file')->getMethodName(), 'Deflate');
  1756. }
  1757. /**
  1758. * @throws ZipException
  1759. */
  1760. public function testInvalidCompressionMethodEntry()
  1761. {
  1762. $this->setExpectedException(ZipUnsupportMethodException::class, 'Unsupported method');
  1763. $zipFile = new ZipFile();
  1764. $zipFile->addFromString('file', 'content', ZipFile::METHOD_STORED);
  1765. $zipFile->setCompressionMethodEntry('file', 99);
  1766. }
  1767. /**
  1768. * @throws ZipException
  1769. */
  1770. public function testUnchangeAll()
  1771. {
  1772. $zipFile = new ZipFile();
  1773. for ($i = 0; $i < 10; $i++) {
  1774. $zipFile[$i] = $i;
  1775. }
  1776. $zipFile->setArchiveComment('comment');
  1777. static::assertCount(10, $zipFile);
  1778. static::assertSame($zipFile->getArchiveComment(), 'comment');
  1779. $zipFile->saveAsFile($this->outputFilename);
  1780. $zipFile->unchangeAll();
  1781. static::assertCount(0, $zipFile);
  1782. static::assertNull($zipFile->getArchiveComment());
  1783. $zipFile->close();
  1784. $zipFile->openFile($this->outputFilename);
  1785. static::assertCount(10, $zipFile);
  1786. static::assertSame($zipFile->getArchiveComment(), 'comment');
  1787. for ($i = 10; $i < 100; $i++) {
  1788. $zipFile[$i] = $i;
  1789. }
  1790. $zipFile->setArchiveComment('comment 2');
  1791. static::assertCount(100, $zipFile);
  1792. static::assertSame($zipFile->getArchiveComment(), 'comment 2');
  1793. $zipFile->unchangeAll();
  1794. static::assertCount(10, $zipFile);
  1795. static::assertSame($zipFile->getArchiveComment(), 'comment');
  1796. $zipFile->close();
  1797. }
  1798. /**
  1799. * @throws ZipException
  1800. */
  1801. public function testUnchangeArchiveComment()
  1802. {
  1803. $zipFile = new ZipFile();
  1804. for ($i = 0; $i < 10; $i++) {
  1805. $zipFile[$i] = $i;
  1806. }
  1807. $zipFile->setArchiveComment('comment');
  1808. static::assertSame($zipFile->getArchiveComment(), 'comment');
  1809. $zipFile->saveAsFile($this->outputFilename);
  1810. $zipFile->unchangeArchiveComment();
  1811. static::assertNull($zipFile->getArchiveComment());
  1812. $zipFile->close();
  1813. $zipFile->openFile($this->outputFilename);
  1814. static::assertSame($zipFile->getArchiveComment(), 'comment');
  1815. $zipFile->setArchiveComment('comment 2');
  1816. static::assertSame($zipFile->getArchiveComment(), 'comment 2');
  1817. $zipFile->unchangeArchiveComment();
  1818. static::assertSame($zipFile->getArchiveComment(), 'comment');
  1819. $zipFile->close();
  1820. }
  1821. /**
  1822. * @throws ZipEntryNotFoundException
  1823. * @throws ZipException
  1824. */
  1825. public function testUnchangeEntry()
  1826. {
  1827. $zipFile = new ZipFile();
  1828. $zipFile['file 1'] = 'content 1';
  1829. $zipFile['file 2'] = 'content 2';
  1830. $zipFile
  1831. ->saveAsFile($this->outputFilename)
  1832. ->close()
  1833. ;
  1834. $zipFile->openFile($this->outputFilename);
  1835. $zipFile['file 1'] = 'modify content 1';
  1836. $zipFile->setPasswordEntry('file 1', 'password');
  1837. static::assertSame($zipFile['file 1'], 'modify content 1');
  1838. static::assertTrue($zipFile->getEntryInfo('file 1')->isEncrypted());
  1839. static::assertSame($zipFile['file 2'], 'content 2');
  1840. static::assertFalse($zipFile->getEntryInfo('file 2')->isEncrypted());
  1841. $zipFile->unchangeEntry('file 1');
  1842. static::assertSame($zipFile['file 1'], 'content 1');
  1843. static::assertFalse($zipFile->getEntryInfo('file 1')->isEncrypted());
  1844. static::assertSame($zipFile['file 2'], 'content 2');
  1845. static::assertFalse($zipFile->getEntryInfo('file 2')->isEncrypted());
  1846. $zipFile->close();
  1847. }
  1848. }