ZipFileTest.php 70 KB

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