ZipFileTest.php 82 KB

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