ZipEntryTest.php 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617
  1. <?php
  2. namespace PhpZip\Tests;
  3. use PHPUnit\Framework\TestCase;
  4. use PhpZip\Constants\DosAttrs;
  5. use PhpZip\Constants\DosCodePage;
  6. use PhpZip\Constants\GeneralPurposeBitFlag;
  7. use PhpZip\Constants\ZipCompressionLevel;
  8. use PhpZip\Constants\ZipCompressionMethod;
  9. use PhpZip\Constants\ZipConstants;
  10. use PhpZip\Constants\ZipEncryptionMethod;
  11. use PhpZip\Constants\ZipPlatform;
  12. use PhpZip\Constants\ZipVersion;
  13. use PhpZip\Exception\InvalidArgumentException;
  14. use PhpZip\Exception\ZipException;
  15. use PhpZip\Exception\ZipUnsupportMethodException;
  16. use PhpZip\Model\Data\ZipFileData;
  17. use PhpZip\Model\Data\ZipNewData;
  18. use PhpZip\Model\Extra\ExtraFieldsCollection;
  19. use PhpZip\Model\Extra\Fields\AsiExtraField;
  20. use PhpZip\Model\Extra\Fields\ExtendedTimestampExtraField;
  21. use PhpZip\Model\Extra\Fields\JarMarkerExtraField;
  22. use PhpZip\Model\Extra\Fields\NewUnixExtraField;
  23. use PhpZip\Model\Extra\Fields\NtfsExtraField;
  24. use PhpZip\Model\Extra\Fields\OldUnixExtraField;
  25. use PhpZip\Model\Extra\Fields\UnicodePathExtraField;
  26. use PhpZip\Model\ZipEntry;
  27. /**
  28. * Class ZipEntryTest.
  29. *
  30. * @internal
  31. *
  32. * @small
  33. */
  34. class ZipEntryTest extends TestCase
  35. {
  36. public function testEntry()
  37. {
  38. $zipEntry = new ZipEntry('entry');
  39. static::assertSame($zipEntry->getName(), 'entry');
  40. static::assertFalse($zipEntry->isDirectory());
  41. static::assertNull($zipEntry->getData());
  42. static::assertSame($zipEntry->getCompressionMethod(), ZipEntry::UNKNOWN);
  43. static::assertSame($zipEntry->getCreatedOS(), ZipEntry::UNKNOWN);
  44. static::assertSame($zipEntry->getExtractedOS(), ZipEntry::UNKNOWN);
  45. static::assertSame($zipEntry->getSoftwareVersion(), ZipVersion::v10_DEFAULT_MIN);
  46. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v10_DEFAULT_MIN);
  47. static::assertSame($zipEntry->getGeneralPurposeBitFlags(), 0);
  48. static::assertSame($zipEntry->getDosTime(), ZipEntry::UNKNOWN);
  49. static::assertSame($zipEntry->getTime(), ZipEntry::UNKNOWN);
  50. static::assertSame($zipEntry->getCrc(), ZipEntry::UNKNOWN);
  51. static::assertSame($zipEntry->getCompressedSize(), ZipEntry::UNKNOWN);
  52. static::assertSame($zipEntry->getUncompressedSize(), ZipEntry::UNKNOWN);
  53. static::assertSame($zipEntry->getInternalAttributes(), 0);
  54. static::assertSame($zipEntry->getExternalAttributes(), DosAttrs::DOS_ARCHIVE);
  55. static::assertSame($zipEntry->getLocalHeaderOffset(), 0);
  56. static::assertInstanceOf(ExtraFieldsCollection::class, $zipEntry->getCdExtraFields());
  57. static::assertInstanceOf(ExtraFieldsCollection::class, $zipEntry->getLocalExtraFields());
  58. static::assertCount(0, $zipEntry->getCdExtraFields());
  59. static::assertCount(0, $zipEntry->getLocalExtraFields());
  60. static::assertSame($zipEntry->getComment(), '');
  61. static::assertNull($zipEntry->getPassword());
  62. static::assertSame($zipEntry->getEncryptionMethod(), ZipEncryptionMethod::NONE);
  63. static::assertSame($zipEntry->getCompressionLevel(), ZipCompressionLevel::NORMAL);
  64. static::assertNull($zipEntry->getCharset());
  65. static::assertNull($zipEntry->getATime());
  66. static::assertNull($zipEntry->getCTime());
  67. static::assertSame($zipEntry->getUnixMode(), 0100644);
  68. $zipDirEntry = $zipEntry->rename('directory/');
  69. static::assertNotSame($zipEntry, $zipDirEntry);
  70. static::assertSame($zipDirEntry->getName(), 'directory/');
  71. static::assertTrue($zipDirEntry->isDirectory());
  72. static::assertSame($zipDirEntry->getExternalAttributes(), DosAttrs::DOS_DIRECTORY);
  73. static::assertSame($zipDirEntry->getUnixMode(), 040755);
  74. static::assertNotSame($zipDirEntry->getName(), $zipEntry->getName());
  75. static::assertNotSame($zipDirEntry->isDirectory(), $zipEntry->isDirectory());
  76. static::assertNotSame($zipDirEntry->getExternalAttributes(), $zipEntry->getExternalAttributes());
  77. static::assertNotSame($zipDirEntry->getUnixMode(), $zipEntry->getUnixMode());
  78. }
  79. /**
  80. * @dataProvider provideEmptyName
  81. *
  82. * @param string|null $entryName
  83. * @param string $exceptionMessage
  84. */
  85. public function testEmptyName($entryName, $exceptionMessage)
  86. {
  87. $this->setExpectedException(InvalidArgumentException::class, $exceptionMessage);
  88. new ZipEntry($entryName);
  89. }
  90. /**
  91. * @return array
  92. */
  93. public function provideEmptyName()
  94. {
  95. return [
  96. ['', 'Empty zip entry name'],
  97. ['/', 'Empty zip entry name'],
  98. [null, 'zip entry name is null'],
  99. ];
  100. }
  101. /**
  102. * @dataProvider provideEntryName
  103. *
  104. * @param string $entryName
  105. * @param string $actualEntryName
  106. * @param bool $directory
  107. */
  108. public function testEntryName($entryName, $actualEntryName, $directory)
  109. {
  110. $entry = new ZipEntry($entryName);
  111. static::assertSame($entry->getName(), $actualEntryName);
  112. static::assertSame($entry->isDirectory(), $directory);
  113. }
  114. /**
  115. * @return array
  116. */
  117. public function provideEntryName()
  118. {
  119. return [
  120. ['0', '0', false],
  121. [0, '0', false],
  122. ['directory/', 'directory/', true],
  123. ];
  124. }
  125. /**
  126. * @dataProvider provideCompressionMethod
  127. *
  128. * @param int $compressionMethod
  129. *
  130. * @throws ZipUnsupportMethodException
  131. */
  132. public function testCompressionMethod($compressionMethod)
  133. {
  134. $entry = new ZipEntry('entry');
  135. static::assertSame($entry->getCompressionMethod(), ZipEntry::UNKNOWN);
  136. $entry->setCompressionMethod($compressionMethod);
  137. static::assertSame($entry->getCompressionMethod(), $compressionMethod);
  138. }
  139. /**
  140. * @return array
  141. */
  142. public function provideCompressionMethod()
  143. {
  144. $provides = [
  145. [ZipCompressionMethod::STORED],
  146. [ZipCompressionMethod::DEFLATED],
  147. ];
  148. if (\extension_loaded('bz2')) {
  149. $provides[] = [ZipCompressionMethod::BZIP2];
  150. }
  151. return $provides;
  152. }
  153. /**
  154. * @dataProvider provideOutOfRangeCompressionMethod
  155. *
  156. * @param int $compressionMethod
  157. *
  158. * @throws ZipUnsupportMethodException
  159. */
  160. public function testOutOfRangeCompressionMethod($compressionMethod)
  161. {
  162. $this->setExpectedException(InvalidArgumentException::class, 'method out of range: ' . $compressionMethod);
  163. $zipEntry = new ZipEntry('entry');
  164. $zipEntry->setCompressionMethod($compressionMethod);
  165. }
  166. /**
  167. * @return array
  168. */
  169. public function provideOutOfRangeCompressionMethod()
  170. {
  171. return [
  172. [-1],
  173. [0x44444],
  174. ];
  175. }
  176. /**
  177. * @dataProvider provideUnsupportCompressionMethod
  178. *
  179. * @param int $compressionMethod
  180. * @param string $exceptionMessage
  181. *
  182. * @throws ZipUnsupportMethodException
  183. */
  184. public function testUnsupportCompressionMethod($compressionMethod, $exceptionMessage)
  185. {
  186. $this->setExpectedException(ZipUnsupportMethodException::class, $exceptionMessage);
  187. $zipEntry = new ZipEntry('entry');
  188. $zipEntry->setCompressionMethod($compressionMethod);
  189. }
  190. /**
  191. * @return array
  192. */
  193. public function provideUnsupportCompressionMethod()
  194. {
  195. return [
  196. [1, 'Compression method 1 (Shrunk) is not supported.'],
  197. [2, 'Compression method 2 (Reduced compression factor 1) is not supported.'],
  198. [3, 'Compression method 3 (Reduced compression factor 2) is not supported.'],
  199. [4, 'Compression method 4 (Reduced compression factor 3) is not supported.'],
  200. [5, 'Compression method 5 (Reduced compression factor 4) is not supported.'],
  201. [6, 'Compression method 6 (Imploded) is not supported.'],
  202. [7, 'Compression method 7 (Reserved for Tokenizing compression algorithm) is not supported.'],
  203. [9, 'Compression method 9 (Enhanced Deflating using Deflate64(tm)) is not supported.'],
  204. [10, 'Compression method 10 (PKWARE Data Compression Library Imploding) is not supported.'],
  205. [11, 'Compression method 11 (Reserved by PKWARE) is not supported.'],
  206. [13, 'Compression method 13 (Reserved by PKWARE) is not supported.'],
  207. [14, 'Compression method 14 (LZMA) is not supported.'],
  208. [15, 'Compression method 15 (Reserved by PKWARE) is not supported.'],
  209. [16, 'Compression method 16 (Reserved by PKWARE) is not supported.'],
  210. [17, 'Compression method 17 (Reserved by PKWARE) is not supported.'],
  211. [18, 'Compression method 18 (File is compressed using IBM TERSE (new)) is not supported.'],
  212. [19, 'Compression method 19 (IBM LZ77 z Architecture (PFS)) is not supported.'],
  213. [96, 'Compression method 96 (WinZip JPEG Compression) is not supported.'],
  214. [97, 'Compression method 97 (WavPack compressed data) is not supported.'],
  215. [98, 'Compression method 98 (PPMd version I, Rev 1) is not supported.'],
  216. [
  217. ZipCompressionMethod::WINZIP_AES,
  218. 'Compression method ' . ZipCompressionMethod::WINZIP_AES . ' (AES Encryption) is not supported.',
  219. ],
  220. [100, 'Compression method 100 (Unknown Method) is not supported.'],
  221. ];
  222. }
  223. public function testCharset()
  224. {
  225. $zipEntry = new ZipEntry('entry');
  226. $zipEntry->setCharset(DosCodePage::CP_CYRILLIC_RUSSIAN);
  227. static::assertSame($zipEntry->getCharset(), DosCodePage::CP_CYRILLIC_RUSSIAN);
  228. $zipEntry->setCharset(null);
  229. static::assertNull($zipEntry->getCharset());
  230. }
  231. public function testEmptyCharset()
  232. {
  233. $this->setExpectedException(InvalidArgumentException::class, 'Empty charset');
  234. $zipEntry = new ZipEntry('entry');
  235. $zipEntry->setCharset('');
  236. }
  237. public function testRenameAndDeleteUnicodePath()
  238. {
  239. $entryName = 'файл.txt';
  240. $charset = DosCodePage::CP_CYRILLIC_RUSSIAN;
  241. $dosEntryName = DosCodePage::fromUTF8($entryName, $charset);
  242. static::assertSame(DosCodePage::toUTF8($dosEntryName, $charset), $entryName);
  243. $unicodePathExtraField = new UnicodePathExtraField(crc32($dosEntryName), $entryName);
  244. $zipEntry = new ZipEntry($dosEntryName, $charset);
  245. static::assertSame($zipEntry->getName(), $dosEntryName);
  246. static::assertSame($zipEntry->getCharset(), $charset);
  247. static::assertFalse($zipEntry->isUtf8Flag());
  248. $zipEntry->addExtraField($unicodePathExtraField);
  249. static::assertSame(
  250. $zipEntry->getLocalExtraField(UnicodePathExtraField::HEADER_ID),
  251. $unicodePathExtraField
  252. );
  253. static::assertSame(
  254. $zipEntry->getCdExtraField(UnicodePathExtraField::HEADER_ID),
  255. $unicodePathExtraField
  256. );
  257. $utf8EntryName = $zipEntry->rename($entryName);
  258. static::assertSame($utf8EntryName->getName(), $entryName);
  259. static::assertTrue($utf8EntryName->isUtf8Flag());
  260. static::assertNull($utf8EntryName->getCharset());
  261. static::assertNull($utf8EntryName->getLocalExtraField(UnicodePathExtraField::HEADER_ID));
  262. static::assertNull($utf8EntryName->getCdExtraField(UnicodePathExtraField::HEADER_ID));
  263. }
  264. public function testData()
  265. {
  266. $zipEntry = new ZipEntry('entry');
  267. static::assertNull($zipEntry->getData());
  268. $zipData = new ZipNewData($zipEntry, 'Text contents');
  269. $zipEntry->setData($zipData);
  270. static::assertSame($zipEntry->getData(), $zipData);
  271. $zipEntry->setData(null);
  272. static::assertNull($zipEntry->getData());
  273. }
  274. /**
  275. * @throws \Exception
  276. */
  277. public function testZipNewDataGuardClone()
  278. {
  279. $resource = fopen('php://temp', 'r+b');
  280. static::assertNotFalse($resource);
  281. fwrite($resource, random_bytes(1024));
  282. rewind($resource);
  283. $zipEntry = new ZipEntry('entry');
  284. $zipEntry2 = new ZipEntry('entry2');
  285. $zipData = new ZipNewData($zipEntry, $resource);
  286. $zipData2 = new ZipNewData($zipEntry2, $resource);
  287. $cloneData = clone $zipData;
  288. $cloneData2 = clone $cloneData;
  289. static::assertSame($zipData->getDataAsStream(), $resource);
  290. static::assertSame($zipData2->getDataAsStream(), $resource);
  291. static::assertSame($cloneData->getDataAsStream(), $resource);
  292. static::assertSame($cloneData2->getDataAsStream(), $resource);
  293. $validResource = \is_resource($resource);
  294. static::assertTrue($validResource);
  295. unset($cloneData);
  296. $validResource = \is_resource($resource);
  297. static::assertTrue($validResource);
  298. unset($zipData);
  299. $validResource = \is_resource($resource);
  300. static::assertTrue($validResource);
  301. unset($zipData2);
  302. $validResource = \is_resource($resource);
  303. static::assertTrue($validResource);
  304. $reflectionClass = new \ReflectionClass($cloneData2);
  305. static::assertSame(
  306. $reflectionClass->getStaticProperties()['guardClonedStream'][(int) $resource],
  307. 0
  308. );
  309. unset($cloneData2);
  310. $validResource = \is_resource($resource);
  311. static::assertFalse($validResource);
  312. }
  313. /**
  314. * @dataProvider providePlatform
  315. *
  316. * @param int $zipOS
  317. */
  318. public function testCreatedOS($zipOS)
  319. {
  320. $zipEntry = new ZipEntry('entry');
  321. static::assertSame($zipEntry->getCreatedOS(), ZipEntry::UNKNOWN);
  322. $zipEntry->setCreatedOS($zipOS);
  323. static::assertSame($zipEntry->getCreatedOS(), $zipOS);
  324. }
  325. /**
  326. * @return array
  327. */
  328. public function providePlatform()
  329. {
  330. return [
  331. [ZipPlatform::OS_DOS],
  332. [ZipPlatform::OS_UNIX],
  333. [ZipPlatform::OS_MAC_OSX],
  334. ];
  335. }
  336. /**
  337. * @dataProvider providePlatform
  338. *
  339. * @param int $zipOS
  340. */
  341. public function testExtractedOS($zipOS)
  342. {
  343. $zipEntry = new ZipEntry('entry');
  344. static::assertSame($zipEntry->getExtractedOS(), ZipEntry::UNKNOWN);
  345. $zipEntry->setExtractedOS($zipOS);
  346. static::assertSame($zipEntry->getExtractedOS(), $zipOS);
  347. }
  348. /**
  349. * @dataProvider provideInvalidPlatform
  350. *
  351. * @param int $zipOS
  352. */
  353. public function testInvalidCreatedOs($zipOS)
  354. {
  355. $this->setExpectedException(InvalidArgumentException::class, 'Platform out of range');
  356. $zipEntry = new ZipEntry('entry');
  357. $zipEntry->setCreatedOS($zipOS);
  358. }
  359. /**
  360. * @return array
  361. */
  362. public function provideInvalidPlatform()
  363. {
  364. return [
  365. [-1],
  366. [0xff + 1],
  367. ];
  368. }
  369. /**
  370. * @dataProvider provideInvalidPlatform
  371. *
  372. * @param int $zipOS
  373. */
  374. public function testInvalidExtractedOs($zipOS)
  375. {
  376. $this->setExpectedException(InvalidArgumentException::class, 'Platform out of range');
  377. $zipEntry = new ZipEntry('entry');
  378. $zipEntry->setExtractedOS($zipOS);
  379. }
  380. /**
  381. * @throws ZipException
  382. */
  383. public function testAutoExtractVersion()
  384. {
  385. $zipEntry = new ZipEntry('entry');
  386. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v10_DEFAULT_MIN);
  387. $zipEntry->setCompressionMethod(ZipCompressionMethod::DEFLATED);
  388. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO);
  389. static::assertSame(
  390. (new ZipEntry('directory/'))->getExtractVersion(),
  391. ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO
  392. );
  393. if (\extension_loaded('bz2')) {
  394. $zipEntry->setCompressionMethod(ZipCompressionMethod::BZIP2);
  395. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v46_BZIP2);
  396. }
  397. $zipEntry->setCompressionMethod(ZipCompressionMethod::STORED);
  398. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v10_DEFAULT_MIN);
  399. $zipEntry->setPassword('12345', ZipEncryptionMethod::PKWARE);
  400. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO);
  401. $zipEntry->setEncryptionMethod(ZipEncryptionMethod::WINZIP_AES_256);
  402. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v51_ENCR_AES_RC2_CORRECT);
  403. }
  404. /**
  405. * @throws ZipException
  406. */
  407. public function testExtractVersion()
  408. {
  409. $zipEntry = new ZipEntry('entry');
  410. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v10_DEFAULT_MIN);
  411. $zipEntry->setExtractVersion(ZipVersion::v63_LZMA_PPMD_BLOWFISH_TWOFISH);
  412. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v63_LZMA_PPMD_BLOWFISH_TWOFISH);
  413. $renameEntry = $zipEntry->rename('new_entry');
  414. static::assertSame($renameEntry->getExtractVersion(), ZipVersion::v63_LZMA_PPMD_BLOWFISH_TWOFISH);
  415. $renameDirEntry = $zipEntry->rename('new_directory/');
  416. static::assertSame($renameDirEntry->getExtractVersion(), ZipVersion::v63_LZMA_PPMD_BLOWFISH_TWOFISH);
  417. $zipEntry->setExtractVersion(ZipVersion::v10_DEFAULT_MIN);
  418. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v10_DEFAULT_MIN);
  419. $renameDirEntry = $zipEntry->rename('new_directory/');
  420. static::assertSame($renameDirEntry->getExtractVersion(), ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO);
  421. $zipEntry->setCompressionMethod(ZipCompressionMethod::DEFLATED);
  422. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO);
  423. if (\extension_loaded('bz2')) {
  424. $zipEntry->setExtractVersion(ZipVersion::v10_DEFAULT_MIN);
  425. $zipEntry->setCompressionMethod(ZipCompressionMethod::BZIP2);
  426. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v46_BZIP2);
  427. }
  428. $zipEntry->setExtractVersion(ZipVersion::v63_LZMA_PPMD_BLOWFISH_TWOFISH);
  429. $zipEntry->setCompressionMethod(ZipCompressionMethod::STORED);
  430. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v10_DEFAULT_MIN);
  431. $zipEntry->setExtractVersion(ZipVersion::v10_DEFAULT_MIN);
  432. $zipEntry->setPassword('12345', ZipEncryptionMethod::PKWARE);
  433. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO);
  434. $zipEntry->setExtractVersion(ZipVersion::v10_DEFAULT_MIN);
  435. $zipEntry->setEncryptionMethod(ZipEncryptionMethod::WINZIP_AES_256);
  436. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v51_ENCR_AES_RC2_CORRECT);
  437. }
  438. public function testSoftwareVersion()
  439. {
  440. $zipEntry = new ZipEntry('entry');
  441. static::assertSame($zipEntry->getSoftwareVersion(), $zipEntry->getExtractVersion());
  442. $zipEntry->setExtractVersion(ZipVersion::v45_ZIP64_EXT);
  443. static::assertSame($zipEntry->getSoftwareVersion(), $zipEntry->getExtractVersion());
  444. $softwareVersion = 35;
  445. $zipEntry->setSoftwareVersion($softwareVersion);
  446. static::assertSame($softwareVersion, $zipEntry->getSoftwareVersion());
  447. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v45_ZIP64_EXT);
  448. $zipEntry->setExtractVersion(ZipVersion::v63_LZMA_PPMD_BLOWFISH_TWOFISH);
  449. static::assertNotSame($zipEntry->getSoftwareVersion(), $zipEntry->getExtractVersion());
  450. static::assertSame($softwareVersion, $zipEntry->getSoftwareVersion());
  451. static::assertSame($zipEntry->getExtractVersion(), ZipVersion::v63_LZMA_PPMD_BLOWFISH_TWOFISH);
  452. }
  453. public function testSize()
  454. {
  455. $zipEntry = new ZipEntry('entry');
  456. static::assertSame($zipEntry->getCompressedSize(), ZipEntry::UNKNOWN);
  457. static::assertSame($zipEntry->getUncompressedSize(), ZipEntry::UNKNOWN);
  458. $compressedSize = 100000;
  459. $uncompressedSize = 400000;
  460. $zipEntry->setCompressedSize($compressedSize);
  461. $zipEntry->setUncompressedSize($uncompressedSize);
  462. static::assertSame($zipEntry->getCompressedSize(), $compressedSize);
  463. static::assertSame($zipEntry->getUncompressedSize(), $uncompressedSize);
  464. $zipEntry->setCompressedSize(ZipEntry::UNKNOWN);
  465. $zipEntry->setUncompressedSize(ZipEntry::UNKNOWN);
  466. static::assertSame($zipEntry->getCompressedSize(), ZipEntry::UNKNOWN);
  467. static::assertSame($zipEntry->getUncompressedSize(), ZipEntry::UNKNOWN);
  468. }
  469. public function testInvalidCompressedSize()
  470. {
  471. $this->setExpectedException(InvalidArgumentException::class, 'Compressed size < -1');
  472. $zipEntry = new ZipEntry('entry');
  473. $zipEntry->setCompressedSize(-2);
  474. }
  475. public function testInvalidUncompressedSize()
  476. {
  477. $this->setExpectedException(InvalidArgumentException::class, 'Uncompressed size < -1');
  478. $zipEntry = new ZipEntry('entry');
  479. $zipEntry->setUncompressedSize(-2);
  480. }
  481. public function testLocalHeaderOffset()
  482. {
  483. $zipEntry = new ZipEntry('entry');
  484. static::assertSame($zipEntry->getLocalHeaderOffset(), 0);
  485. $localHeaderOffset = 10000;
  486. $zipEntry->setLocalHeaderOffset($localHeaderOffset);
  487. static::assertSame($zipEntry->getLocalHeaderOffset(), $localHeaderOffset);
  488. $this->setExpectedException(InvalidArgumentException::class, 'Negative $localHeaderOffset');
  489. $zipEntry->setLocalHeaderOffset(-1);
  490. }
  491. public function testGeneralPurposeBitFlags()
  492. {
  493. $zipEntry = new ZipEntry('entry');
  494. static::assertSame($zipEntry->getGeneralPurposeBitFlags(), 0);
  495. static::assertFalse($zipEntry->isUtf8Flag());
  496. static::assertFalse($zipEntry->isEncrypted());
  497. static::assertFalse($zipEntry->isStrongEncryption());
  498. static::assertFalse($zipEntry->isDataDescriptorEnabled());
  499. $gpbf = GeneralPurposeBitFlag::DATA_DESCRIPTOR | GeneralPurposeBitFlag::UTF8;
  500. $zipEntry->setGeneralPurposeBitFlags($gpbf);
  501. static::assertSame($zipEntry->getGeneralPurposeBitFlags(), $gpbf);
  502. static::assertTrue($zipEntry->isDataDescriptorEnabled());
  503. static::assertTrue($zipEntry->isUtf8Flag());
  504. $zipEntry->setGeneralPurposeBitFlags(0);
  505. static::assertSame($zipEntry->getGeneralPurposeBitFlags(), 0);
  506. static::assertFalse($zipEntry->isUtf8Flag());
  507. static::assertFalse($zipEntry->isDataDescriptorEnabled());
  508. $zipEntry->enableUtf8Name(true);
  509. static::assertTrue($zipEntry->isUtf8Flag());
  510. static::assertSame(
  511. ($zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::UTF8),
  512. GeneralPurposeBitFlag::UTF8
  513. );
  514. $zipEntry->enableUtf8Name(false);
  515. static::assertFalse($zipEntry->isUtf8Flag());
  516. static::assertSame(
  517. ($zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::UTF8),
  518. 0
  519. );
  520. $zipEntry->enableDataDescriptor(true);
  521. static::assertTrue($zipEntry->isDataDescriptorEnabled());
  522. static::assertSame(
  523. ($zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::DATA_DESCRIPTOR),
  524. GeneralPurposeBitFlag::DATA_DESCRIPTOR
  525. );
  526. $zipEntry->enableDataDescriptor(false);
  527. static::assertFalse($zipEntry->isDataDescriptorEnabled());
  528. static::assertSame(
  529. ($zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::DATA_DESCRIPTOR),
  530. 0
  531. );
  532. }
  533. public function testEncryptionGPBF()
  534. {
  535. $zipEntry = new ZipEntry('entry');
  536. static::assertFalse($zipEntry->isEncrypted());
  537. $zipEntry->setGeneralPurposeBitFlags(GeneralPurposeBitFlag::ENCRYPTION);
  538. static::assertSame(
  539. ($zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::ENCRYPTION),
  540. GeneralPurposeBitFlag::ENCRYPTION
  541. );
  542. static::assertTrue($zipEntry->isEncrypted());
  543. $zipEntry->disableEncryption();
  544. static::assertSame(
  545. ($zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::ENCRYPTION),
  546. 0
  547. );
  548. static::assertFalse($zipEntry->isEncrypted());
  549. // SIC! Strong encryption is not supported in ZipReader and ZipWriter
  550. static::assertFalse($zipEntry->isStrongEncryption());
  551. $zipEntry->setGeneralPurposeBitFlags(GeneralPurposeBitFlag::STRONG_ENCRYPTION);
  552. static::assertTrue($zipEntry->isStrongEncryption());
  553. }
  554. /**
  555. * @dataProvider provideInvalidGPBF
  556. *
  557. * @param int $gpbf
  558. */
  559. public function testInvalidGPBF($gpbf)
  560. {
  561. $this->setExpectedException(InvalidArgumentException::class, 'general purpose bit flags out of range');
  562. $zipEntry = new ZipEntry('entry');
  563. $zipEntry->setGeneralPurposeBitFlags($gpbf);
  564. }
  565. /**
  566. * @return array
  567. */
  568. public function provideInvalidGPBF()
  569. {
  570. return [
  571. [-1],
  572. [0x10000],
  573. ];
  574. }
  575. /**
  576. * @dataProvider provideCompressionLevelGPBF
  577. *
  578. * @param int $compressionLevel
  579. * @param bool $bit1
  580. * @param bool $bit2
  581. *
  582. * @throws ZipUnsupportMethodException
  583. */
  584. public function testSetCompressionFlags($compressionLevel, $bit1, $bit2)
  585. {
  586. $zipEntry = new ZipEntry('entry');
  587. $zipEntry->setCompressionMethod(ZipCompressionMethod::DEFLATED);
  588. $gpbf = ($bit1 ? GeneralPurposeBitFlag::COMPRESSION_FLAG1 : 0) |
  589. ($bit2 ? GeneralPurposeBitFlag::COMPRESSION_FLAG2 : 0);
  590. $zipEntry->setGeneralPurposeBitFlags($gpbf);
  591. static::assertSame($zipEntry->getCompressionLevel(), $compressionLevel);
  592. static::assertSame(
  593. (
  594. $zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::COMPRESSION_FLAG1
  595. ) === GeneralPurposeBitFlag::COMPRESSION_FLAG1,
  596. $bit1,
  597. 'Compression flag1 is not same'
  598. );
  599. static::assertSame(
  600. (
  601. $zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::COMPRESSION_FLAG2
  602. ) === GeneralPurposeBitFlag::COMPRESSION_FLAG2,
  603. $bit2,
  604. 'Compression flag2 is not same'
  605. );
  606. }
  607. /**
  608. * @return array
  609. */
  610. public function provideCompressionLevelGPBF()
  611. {
  612. return [
  613. [ZipCompressionLevel::SUPER_FAST, true, true],
  614. [ZipCompressionLevel::FAST, false, true],
  615. [ZipCompressionLevel::NORMAL, false, false],
  616. [ZipCompressionLevel::MAXIMUM, true, false],
  617. ];
  618. }
  619. /**
  620. * @dataProvider provideCompressionLevels
  621. *
  622. * @param int $compressionLevel
  623. * @param bool $bit1
  624. * @param bool $bit2
  625. *
  626. * @throws ZipUnsupportMethodException
  627. */
  628. public function testSetCompressionLevel($compressionLevel, $bit1, $bit2)
  629. {
  630. $zipEntry = new ZipEntry('entry');
  631. $zipEntry->setCompressionMethod(ZipCompressionMethod::DEFLATED);
  632. $zipEntry->setCompressionLevel($compressionLevel);
  633. static::assertSame($zipEntry->getCompressionLevel(), $compressionLevel);
  634. static::assertSame(
  635. (
  636. $zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::COMPRESSION_FLAG1
  637. ) === GeneralPurposeBitFlag::COMPRESSION_FLAG1,
  638. $bit1,
  639. 'Compression flag1 is not same'
  640. );
  641. static::assertSame(
  642. (
  643. $zipEntry->getGeneralPurposeBitFlags() & GeneralPurposeBitFlag::COMPRESSION_FLAG2
  644. ) === GeneralPurposeBitFlag::COMPRESSION_FLAG2,
  645. $bit2,
  646. 'Compression flag2 is not same'
  647. );
  648. }
  649. /**
  650. * @return array
  651. */
  652. public function provideCompressionLevels()
  653. {
  654. return [
  655. [ZipCompressionLevel::SUPER_FAST, true, true],
  656. [ZipCompressionLevel::FAST, false, true],
  657. [3, false, false],
  658. [4, false, false],
  659. [ZipCompressionLevel::NORMAL, false, false],
  660. [6, false, false],
  661. [7, false, false],
  662. [8, false, false],
  663. [ZipCompressionLevel::MAXIMUM, true, false],
  664. ];
  665. }
  666. /**
  667. * @throws ZipException
  668. */
  669. public function testLegacyDefaultCompressionLevel()
  670. {
  671. $zipEntry = new ZipEntry('entry');
  672. $zipEntry->setCompressionMethod(ZipCompressionMethod::DEFLATED);
  673. $zipEntry->setCompressionLevel(ZipCompressionLevel::MAXIMUM);
  674. static::assertSame($zipEntry->getCompressionLevel(), ZipCompressionLevel::MAXIMUM);
  675. $zipEntry->setCompressionLevel(ZipEntry::UNKNOWN);
  676. static::assertSame($zipEntry->getCompressionLevel(), ZipCompressionLevel::NORMAL);
  677. }
  678. /**
  679. * @dataProvider provideInvalidCompressionLevel
  680. *
  681. * @param int $compressionLevel
  682. *
  683. * @throws ZipException
  684. */
  685. public function testInvalidCompressionLevel($compressionLevel)
  686. {
  687. $this->setExpectedException(
  688. InvalidArgumentException::class,
  689. 'Invalid compression level. Minimum level ' . ZipCompressionLevel::LEVEL_MIN .
  690. '. Maximum level ' . ZipCompressionLevel::LEVEL_MAX
  691. );
  692. $zipEntry = new ZipEntry('entry');
  693. $zipEntry->setCompressionMethod(ZipCompressionMethod::DEFLATED);
  694. $zipEntry->setCompressionLevel($compressionLevel);
  695. }
  696. /**
  697. * @return array
  698. */
  699. public function provideInvalidCompressionLevel()
  700. {
  701. return [
  702. [0],
  703. [-2],
  704. [10],
  705. [100],
  706. ];
  707. }
  708. /**
  709. * @dataProvider provideDosTime
  710. *
  711. * @param int $dosTime
  712. */
  713. public function testDosTime($dosTime)
  714. {
  715. $zipEntry = new ZipEntry('entry');
  716. static::assertSame($zipEntry->getDosTime(), ZipEntry::UNKNOWN);
  717. $zipEntry->setDosTime($dosTime);
  718. static::assertSame($zipEntry->getDosTime(), $dosTime);
  719. }
  720. /**
  721. * @return array
  722. */
  723. public function provideDosTime()
  724. {
  725. return [
  726. [0],
  727. [1043487716],
  728. [1177556759],
  729. [1282576076],
  730. ];
  731. }
  732. /**
  733. * @dataProvider provideInvalidDosTime
  734. *
  735. * @param int $dosTime
  736. */
  737. public function testInvalidDosTime($dosTime)
  738. {
  739. if (\PHP_INT_SIZE === 4) {
  740. static::markTestSkipped('only 64 bit test');
  741. return;
  742. }
  743. $this->setExpectedException(InvalidArgumentException::class, 'DosTime out of range');
  744. $zipEntry = new ZipEntry('entry');
  745. $zipEntry->setDosTime($dosTime);
  746. }
  747. /**
  748. * @return array
  749. */
  750. public function provideInvalidDosTime()
  751. {
  752. return [
  753. [-1],
  754. [0xffffffff + 1],
  755. ];
  756. }
  757. public function testSetTime()
  758. {
  759. $zipEntry = new ZipEntry('entry');
  760. static::assertSame($zipEntry->getDosTime(), ZipEntry::UNKNOWN);
  761. $zipEntry->setTime(ZipEntry::UNKNOWN);
  762. static::assertSame($zipEntry->getDosTime(), 0);
  763. $zipEntry->setTime(0);
  764. static::assertSame($zipEntry->getDosTime(), 0);
  765. }
  766. /**
  767. * @dataProvider provideExternalAttributes
  768. *
  769. * @param string $entryName
  770. * @param int $expectedExternalAttr
  771. * @param int $createdOS
  772. * @param int $extractedOS
  773. * @param int|null $externalAttr
  774. * @param int $unixMode
  775. *
  776. * @noinspection PhpTooManyParametersInspection
  777. */
  778. public function testExternalAttributes(
  779. $entryName,
  780. $expectedExternalAttr,
  781. $createdOS,
  782. $extractedOS,
  783. $externalAttr,
  784. $unixMode
  785. ) {
  786. $zipEntry = new ZipEntry($entryName);
  787. static::assertSame($zipEntry->getExternalAttributes(), $expectedExternalAttr);
  788. $zipEntry
  789. ->setCreatedOS($createdOS)
  790. ->setExtractedOS($extractedOS)
  791. ;
  792. if ($externalAttr !== null) {
  793. $zipEntry->setExternalAttributes($externalAttr);
  794. static::assertSame($zipEntry->getExternalAttributes(), $externalAttr);
  795. }
  796. static::assertSame($zipEntry->getUnixMode(), $unixMode);
  797. }
  798. /**
  799. * @return array
  800. */
  801. public function provideExternalAttributes()
  802. {
  803. return [
  804. [
  805. 'entry.txt',
  806. DosAttrs::DOS_ARCHIVE,
  807. ZipPlatform::OS_UNIX,
  808. ZipPlatform::OS_UNIX,
  809. (010644 << 16) | DosAttrs::DOS_ARCHIVE,
  810. 010644,
  811. ],
  812. [
  813. 'dir/',
  814. DosAttrs::DOS_DIRECTORY,
  815. ZipPlatform::OS_UNIX,
  816. ZipPlatform::OS_UNIX,
  817. (040755 << 16) | DosAttrs::DOS_DIRECTORY,
  818. 040755,
  819. ],
  820. [
  821. 'entry.txt',
  822. DosAttrs::DOS_ARCHIVE,
  823. ZipPlatform::OS_DOS,
  824. ZipPlatform::OS_DOS,
  825. null,
  826. 0100644,
  827. ],
  828. [
  829. 'entry.txt',
  830. DosAttrs::DOS_ARCHIVE,
  831. ZipPlatform::OS_DOS,
  832. ZipPlatform::OS_UNIX,
  833. null,
  834. 0100644,
  835. ],
  836. [
  837. 'entry.txt',
  838. DosAttrs::DOS_ARCHIVE,
  839. ZipPlatform::OS_UNIX,
  840. ZipPlatform::OS_DOS,
  841. null,
  842. 0100644,
  843. ],
  844. [
  845. 'dir/',
  846. DosAttrs::DOS_DIRECTORY,
  847. ZipPlatform::OS_DOS,
  848. ZipPlatform::OS_DOS,
  849. null,
  850. 040755,
  851. ],
  852. [
  853. 'dir/',
  854. DosAttrs::DOS_DIRECTORY,
  855. ZipPlatform::OS_DOS,
  856. ZipPlatform::OS_UNIX,
  857. null,
  858. 040755,
  859. ],
  860. [
  861. 'dir/',
  862. DosAttrs::DOS_DIRECTORY,
  863. ZipPlatform::OS_UNIX,
  864. ZipPlatform::OS_DOS,
  865. null,
  866. 040755,
  867. ],
  868. [
  869. 'entry.txt',
  870. DosAttrs::DOS_ARCHIVE,
  871. ZipPlatform::OS_UNIX,
  872. ZipPlatform::OS_UNIX,
  873. 0777 << 16,
  874. 0777,
  875. ],
  876. ];
  877. }
  878. /**
  879. * @dataProvider provideInvalidExternalAttributes
  880. *
  881. * @param int $externalAttributes
  882. */
  883. public function testInvalidExternalAttributes($externalAttributes)
  884. {
  885. if (\PHP_INT_SIZE === 4) {
  886. static::markTestSkipped('only 64 bit test');
  887. return;
  888. }
  889. $this->setExpectedException(InvalidArgumentException::class, 'external attributes out of range');
  890. $zipEntry = new ZipEntry('entry');
  891. $zipEntry->setExternalAttributes($externalAttributes);
  892. }
  893. /**
  894. * @return array
  895. */
  896. public function provideInvalidExternalAttributes()
  897. {
  898. return [
  899. [-1],
  900. [0xffffffff + 1],
  901. ];
  902. }
  903. public function testInternalAttributes()
  904. {
  905. $zipEntry = new ZipEntry('entry');
  906. static::assertSame($zipEntry->getInternalAttributes(), 0);
  907. $zipEntry->setInternalAttributes(1);
  908. static::assertSame($zipEntry->getInternalAttributes(), 1);
  909. }
  910. /**
  911. * @dataProvider provideInvalidInternalAttributes
  912. *
  913. * @param int $internalAttributes
  914. */
  915. public function testInvalidInternalAttributes($internalAttributes)
  916. {
  917. $this->setExpectedException(InvalidArgumentException::class, 'internal attributes out of range');
  918. $zipEntry = new ZipEntry('entry');
  919. $zipEntry->setInternalAttributes($internalAttributes);
  920. }
  921. /**
  922. * @return array
  923. */
  924. public function provideInvalidInternalAttributes()
  925. {
  926. return [
  927. [-1],
  928. [0xffff + 1],
  929. ];
  930. }
  931. public function testExtraFields()
  932. {
  933. $zipEntry = new ZipEntry('entry');
  934. static::assertInstanceOf(ExtraFieldsCollection::class, $zipEntry->getCdExtraFields());
  935. static::assertInstanceOf(ExtraFieldsCollection::class, $zipEntry->getLocalExtraFields());
  936. static::assertCount(0, $zipEntry->getCdExtraFields());
  937. static::assertCount(0, $zipEntry->getLocalExtraFields());
  938. $extraNtfs = new NtfsExtraField(time(), time() - 10000, time() - 100000);
  939. $extraAsi = new AsiExtraField(010644);
  940. $extraJar = new JarMarkerExtraField();
  941. $zipEntry->getLocalExtraFields()->add($extraNtfs);
  942. $zipEntry->getCdExtraFields()->add($extraNtfs);
  943. static::assertCount(1, $zipEntry->getCdExtraFields());
  944. static::assertCount(1, $zipEntry->getLocalExtraFields());
  945. $zipEntry->addExtraField($extraAsi);
  946. static::assertCount(2, $zipEntry->getCdExtraFields());
  947. static::assertCount(2, $zipEntry->getLocalExtraFields());
  948. $zipEntry->addCdExtraField($extraJar);
  949. static::assertCount(3, $zipEntry->getCdExtraFields());
  950. static::assertCount(2, $zipEntry->getLocalExtraFields());
  951. static::assertSame($zipEntry->getCdExtraField(JarMarkerExtraField::HEADER_ID), $extraJar);
  952. static::assertNull($zipEntry->getLocalExtraField(JarMarkerExtraField::HEADER_ID));
  953. static::assertSame($zipEntry->getLocalExtraField(AsiExtraField::HEADER_ID), $extraAsi);
  954. static::assertSame(
  955. [$extraNtfs, $extraAsi, $extraJar],
  956. array_values($zipEntry->getCdExtraFields()->getAll())
  957. );
  958. static::assertSame(
  959. [$extraNtfs, $extraAsi],
  960. array_values($zipEntry->getLocalExtraFields()->getAll())
  961. );
  962. $zipEntry->removeExtraField(AsiExtraField::HEADER_ID);
  963. static::assertNull($zipEntry->getCdExtraField(AsiExtraField::HEADER_ID));
  964. static::assertNull($zipEntry->getLocalExtraField(AsiExtraField::HEADER_ID));
  965. static::assertCount(2, $zipEntry->getCdExtraFields());
  966. static::assertCount(1, $zipEntry->getLocalExtraFields());
  967. static::assertSame(
  968. [$extraNtfs, $extraJar],
  969. array_values($zipEntry->getCdExtraFields()->getAll())
  970. );
  971. static::assertSame(
  972. [$extraNtfs],
  973. array_values($zipEntry->getLocalExtraFields()->getAll())
  974. );
  975. static::assertTrue($zipEntry->hasExtraField(NtfsExtraField::HEADER_ID));
  976. static::assertTrue($zipEntry->hasExtraField(JarMarkerExtraField::HEADER_ID));
  977. static::assertFalse($zipEntry->hasExtraField(AsiExtraField::HEADER_ID));
  978. }
  979. public function testComment()
  980. {
  981. $zipEntry = new ZipEntry('entry');
  982. static::assertSame($zipEntry->getComment(), '');
  983. $zipEntry->setComment('comment');
  984. static::assertSame($zipEntry->getComment(), 'comment');
  985. $zipEntry->setComment(null);
  986. static::assertSame($zipEntry->getComment(), '');
  987. static::assertFalse($zipEntry->isUtf8Flag());
  988. $zipEntry->setComment('комментарий');
  989. static::assertTrue($zipEntry->isUtf8Flag());
  990. static::assertSame($zipEntry->getComment(), 'комментарий');
  991. }
  992. /**
  993. * @throws \Exception
  994. */
  995. public function testLongComment()
  996. {
  997. $this->setExpectedException(InvalidArgumentException::class, 'Comment too long');
  998. $longComment = random_bytes(0xffff + 1);
  999. $zipEntry = new ZipEntry('entry');
  1000. $zipEntry->setComment($longComment);
  1001. }
  1002. /**
  1003. * @dataProvider provideDataDescriptorRequired
  1004. *
  1005. * @param int $crc
  1006. * @param int $compressedSize
  1007. * @param int $uncompressedSize
  1008. * @param bool $required
  1009. */
  1010. public function testDataDescriptorRequired($crc, $compressedSize, $uncompressedSize, $required)
  1011. {
  1012. $zipEntry = new ZipEntry('entry');
  1013. $zipEntry->setCrc($crc);
  1014. $zipEntry->setCompressedSize($compressedSize);
  1015. $zipEntry->setUncompressedSize($uncompressedSize);
  1016. static::assertSame($zipEntry->isDataDescriptorRequired(), $required);
  1017. static::assertSame($zipEntry->getCrc(), $crc);
  1018. static::assertSame($zipEntry->getCompressedSize(), $compressedSize);
  1019. static::assertSame($zipEntry->getUncompressedSize(), $uncompressedSize);
  1020. }
  1021. /**
  1022. * @return array
  1023. */
  1024. public function provideDataDescriptorRequired()
  1025. {
  1026. return [
  1027. [ZipEntry::UNKNOWN, ZipEntry::UNKNOWN, ZipEntry::UNKNOWN, true],
  1028. [0xF33F33, ZipEntry::UNKNOWN, ZipEntry::UNKNOWN, true],
  1029. [0xF33F33, 11111111, ZipEntry::UNKNOWN, true],
  1030. [0xF33F33, ZipEntry::UNKNOWN, 22333333, true],
  1031. [ZipEntry::UNKNOWN, 11111111, ZipEntry::UNKNOWN, true],
  1032. [ZipEntry::UNKNOWN, 11111111, 22333333, true],
  1033. [ZipEntry::UNKNOWN, ZipEntry::UNKNOWN, 22333333, true],
  1034. [0xF33F33, 11111111, 22333333, false],
  1035. ];
  1036. }
  1037. /**
  1038. * @dataProvider provideEncryption
  1039. *
  1040. * @param string|null $password
  1041. * @param int|null $encryptionMethod
  1042. * @param bool $encrypted
  1043. * @param int $expectedEncryptionMethod
  1044. */
  1045. public function testEncryption($password, $encryptionMethod, $encrypted, $expectedEncryptionMethod)
  1046. {
  1047. $zipEntry = new ZipEntry('entry');
  1048. $zipEntry->setPassword($password, $encryptionMethod);
  1049. static::assertSame($zipEntry->isEncrypted(), $encrypted);
  1050. static::assertSame($zipEntry->getPassword(), $password);
  1051. static::assertSame($zipEntry->getEncryptionMethod(), $expectedEncryptionMethod);
  1052. $zipEntry->setPassword($password, null);
  1053. static::assertSame($zipEntry->getEncryptionMethod(), $expectedEncryptionMethod);
  1054. }
  1055. /**
  1056. * @return array
  1057. */
  1058. public function provideEncryption()
  1059. {
  1060. return [
  1061. [null, null, false, ZipEncryptionMethod::NONE],
  1062. [null, ZipEncryptionMethod::WINZIP_AES_256, false, ZipEncryptionMethod::NONE],
  1063. ['12345', null, true, ZipEncryptionMethod::WINZIP_AES_256],
  1064. ['12345', ZipEncryptionMethod::PKWARE, true, ZipEncryptionMethod::PKWARE],
  1065. ['12345', ZipEncryptionMethod::WINZIP_AES_256, true, ZipEncryptionMethod::WINZIP_AES_256],
  1066. ['12345', ZipEncryptionMethod::WINZIP_AES_128, true, ZipEncryptionMethod::WINZIP_AES_128],
  1067. ['12345', ZipEncryptionMethod::WINZIP_AES_192, true, ZipEncryptionMethod::WINZIP_AES_192],
  1068. ];
  1069. }
  1070. public function testDirectoryEncryption()
  1071. {
  1072. $zipEntry = new ZipEntry('directory/');
  1073. $zipEntry->setPassword('12345', ZipEncryptionMethod::WINZIP_AES_256);
  1074. static::assertTrue($zipEntry->isDirectory());
  1075. static::assertNull($zipEntry->getPassword());
  1076. static::assertFalse($zipEntry->isEncrypted());
  1077. static::assertSame($zipEntry->getEncryptionMethod(), ZipEncryptionMethod::NONE);
  1078. }
  1079. /**
  1080. * @dataProvider provideEncryptionMethod
  1081. *
  1082. * @param int|null $encryptionMethod
  1083. * @param int $expectedEncryptionMethod
  1084. * @param bool $encrypted
  1085. * @param int $extractVersion
  1086. */
  1087. public function testEncryptionMethod(
  1088. $encryptionMethod,
  1089. $expectedEncryptionMethod,
  1090. $encrypted,
  1091. $extractVersion
  1092. ) {
  1093. $zipEntry = new ZipEntry('entry');
  1094. $zipEntry->setEncryptionMethod($encryptionMethod);
  1095. static::assertSame($zipEntry->isEncrypted(), $encrypted);
  1096. static::assertSame($zipEntry->getEncryptionMethod(), $expectedEncryptionMethod);
  1097. static::assertSame($zipEntry->getExtractVersion(), $extractVersion);
  1098. }
  1099. /**
  1100. * @return array
  1101. */
  1102. public function provideEncryptionMethod()
  1103. {
  1104. return [
  1105. [
  1106. null,
  1107. ZipEncryptionMethod::NONE,
  1108. false,
  1109. ZipVersion::v10_DEFAULT_MIN,
  1110. ],
  1111. [
  1112. ZipEncryptionMethod::NONE,
  1113. ZipEncryptionMethod::NONE,
  1114. false,
  1115. ZipVersion::v10_DEFAULT_MIN,
  1116. ],
  1117. [
  1118. ZipEncryptionMethod::PKWARE,
  1119. ZipEncryptionMethod::PKWARE,
  1120. true,
  1121. ZipVersion::v20_DEFLATED_FOLDER_ZIPCRYPTO,
  1122. ],
  1123. [
  1124. ZipEncryptionMethod::WINZIP_AES_256,
  1125. ZipEncryptionMethod::WINZIP_AES_256,
  1126. true,
  1127. ZipVersion::v51_ENCR_AES_RC2_CORRECT,
  1128. ],
  1129. [
  1130. ZipEncryptionMethod::WINZIP_AES_192,
  1131. ZipEncryptionMethod::WINZIP_AES_192,
  1132. true,
  1133. ZipVersion::v51_ENCR_AES_RC2_CORRECT,
  1134. ],
  1135. [
  1136. ZipEncryptionMethod::WINZIP_AES_128,
  1137. ZipEncryptionMethod::WINZIP_AES_128,
  1138. true,
  1139. ZipVersion::v51_ENCR_AES_RC2_CORRECT,
  1140. ],
  1141. ];
  1142. }
  1143. /**
  1144. * @dataProvider provideInvalidEncryptionMethod
  1145. *
  1146. * @param int $encryptionMethod
  1147. */
  1148. public function testInvalidEncryptionMethod($encryptionMethod)
  1149. {
  1150. $this->setExpectedException(
  1151. InvalidArgumentException::class,
  1152. 'Encryption method ' . $encryptionMethod . ' is not supported.'
  1153. );
  1154. $zipEntry = new ZipEntry('entry');
  1155. $zipEntry->setEncryptionMethod($encryptionMethod);
  1156. }
  1157. /**
  1158. * @return array
  1159. */
  1160. public function provideInvalidEncryptionMethod()
  1161. {
  1162. return [
  1163. [-2],
  1164. [4],
  1165. [5],
  1166. ];
  1167. }
  1168. /**
  1169. * @dataProvider provideUnixMode
  1170. *
  1171. * @param string $entryName
  1172. * @param int $unixMode
  1173. */
  1174. public function testUnixMode($entryName, $unixMode)
  1175. {
  1176. $zipEntry = new ZipEntry($entryName);
  1177. $zipEntry->setUnixMode($unixMode);
  1178. static::assertSame($zipEntry->getUnixMode(), $unixMode);
  1179. static::assertSame($zipEntry->getCreatedOS(), ZipPlatform::OS_UNIX);
  1180. }
  1181. /**
  1182. * @return array
  1183. */
  1184. public function provideUnixMode()
  1185. {
  1186. return [
  1187. ['entry.txt', 0700], // read, write, & execute only for owner
  1188. ['entry.txt', 0770], // read, write, & execute for owner and group
  1189. ['entry.txt', 0777], // read, write, & execute for owner, group and others
  1190. ['entry.txt', 0111], // execute
  1191. ['entry.txt', 0222], // write
  1192. ['entry.txt', 0333], // write & execute
  1193. ['entry.txt', 0444], // read
  1194. ['entry.txt', 0555], // read & execute
  1195. ['entry.txt', 0666], // read & write
  1196. ['entry.txt', 0740], // owner can read, write, & execute; group can only read; others have no permissions
  1197. ['entry.txt', 0777], // owner can read, write, & execute
  1198. ['directory/', 040700], // directory, read, write, & execute only for owner
  1199. ['directory/', 040770], // directory, read, write, & execute for owner and group
  1200. ['directory/', 040777], // directory, read, write, & execute
  1201. ];
  1202. }
  1203. /**
  1204. * @dataProvider provideUnixMode
  1205. * @dataProvider provideSymlink
  1206. *
  1207. * @param $entryName
  1208. * @param $unixMode
  1209. * @param bool $symlink
  1210. */
  1211. public function testSymlink($entryName, $unixMode, $symlink = false)
  1212. {
  1213. $zipEntry = new ZipEntry($entryName);
  1214. $zipEntry->setUnixMode($unixMode);
  1215. static::assertSame($zipEntry->isUnixSymlink(), $symlink);
  1216. }
  1217. public function testAsiUnixMode()
  1218. {
  1219. $unixMode = 0100666;
  1220. $asiUnixMode = 0100600;
  1221. $asiExtraField = new AsiExtraField($asiUnixMode);
  1222. $zipEntry = new ZipEntry('entry');
  1223. $zipEntry->setCreatedOS(ZipPlatform::OS_DOS);
  1224. $zipEntry->setExtractedOS(ZipPlatform::OS_DOS);
  1225. $zipEntry->setExternalAttributes(DosAttrs::DOS_ARCHIVE);
  1226. $zipEntry->addExtraField($asiExtraField);
  1227. static::assertSame($zipEntry->getUnixMode(), $asiUnixMode);
  1228. $zipEntry->setUnixMode($unixMode);
  1229. static::assertSame($zipEntry->getCreatedOS(), ZipPlatform::OS_UNIX);
  1230. static::assertSame($zipEntry->getUnixMode(), $unixMode);
  1231. }
  1232. /**
  1233. * @return array
  1234. */
  1235. public function provideSymlink()
  1236. {
  1237. return [
  1238. ['entry', 0120644, true],
  1239. ['dir/', 0120755, true],
  1240. ];
  1241. }
  1242. /**
  1243. * @dataProvider provideIsZip64ExtensionsRequired
  1244. *
  1245. * @param int $compressionSize
  1246. * @param int $uncompressionSize
  1247. * @param bool $required
  1248. */
  1249. public function testIsZip64ExtensionsRequired($compressionSize, $uncompressionSize, $required)
  1250. {
  1251. if (\PHP_INT_SIZE === 4) {
  1252. static::markTestSkipped('only php 64-bit');
  1253. return;
  1254. }
  1255. $zipEntry = new ZipEntry('entry');
  1256. $zipEntry->setCompressedSize($compressionSize);
  1257. $zipEntry->setUncompressedSize($uncompressionSize);
  1258. static::assertSame($zipEntry->isZip64ExtensionsRequired(), $required);
  1259. }
  1260. /**
  1261. * @return array
  1262. */
  1263. public function provideIsZip64ExtensionsRequired()
  1264. {
  1265. return [
  1266. [11111111, 22222222, false],
  1267. [ZipEntry::UNKNOWN, ZipEntry::UNKNOWN, false],
  1268. [ZipEntry::UNKNOWN, ZipConstants::ZIP64_MAGIC + 1, true],
  1269. [ZipConstants::ZIP64_MAGIC + 1, ZipEntry::UNKNOWN, true],
  1270. [ZipConstants::ZIP64_MAGIC + 1, ZipConstants::ZIP64_MAGIC + 1, true],
  1271. [ZipConstants::ZIP64_MAGIC, ZipConstants::ZIP64_MAGIC, false],
  1272. [ZipConstants::ZIP64_MAGIC, ZipEntry::UNKNOWN, false],
  1273. [ZipEntry::UNKNOWN, ZipConstants::ZIP64_MAGIC, false],
  1274. ];
  1275. }
  1276. /**
  1277. * @dataProvider provideExtraTime
  1278. *
  1279. * @param ExtraFieldsCollection $extraFieldsCollection
  1280. * @param \DateTimeInterface $mtime
  1281. * @param \DateTimeInterface|null $atime
  1282. * @param \DateTimeInterface|null $ctime
  1283. */
  1284. public function testMTimeATimeCTime(ExtraFieldsCollection $extraFieldsCollection, $mtime, $atime, $ctime)
  1285. {
  1286. $unixTimestamp = time();
  1287. $zipEntry = new ZipEntry('entry');
  1288. $zipEntry->setTime($unixTimestamp);
  1289. // converting from unixtime to dos may occur with a small margin of error
  1290. static::assertLessThanOrEqual($zipEntry->getMTime()->getTimestamp() + 1, $unixTimestamp);
  1291. static::assertGreaterThanOrEqual($zipEntry->getMTime()->getTimestamp() - 1, $unixTimestamp);
  1292. static::assertNull($zipEntry->getATime());
  1293. static::assertNull($zipEntry->getCTime());
  1294. $zipEntry->getCdExtraFields()->addCollection($extraFieldsCollection);
  1295. $zipEntry->getLocalExtraFields()->addCollection($extraFieldsCollection);
  1296. static::assertNotNull($zipEntry->getMTime());
  1297. static::assertSame($zipEntry->getMTime()->getTimestamp(), $mtime->getTimestamp());
  1298. if ($atime !== null) {
  1299. static::assertSame($zipEntry->getATime()->getTimestamp(), $atime->getTimestamp());
  1300. } else {
  1301. static::assertNull($zipEntry->getATime());
  1302. }
  1303. if ($ctime !== null) {
  1304. static::assertSame($zipEntry->getCTime()->getTimestamp(), $ctime->getTimestamp());
  1305. } else {
  1306. static::assertNull($zipEntry->getCTime());
  1307. }
  1308. }
  1309. /**
  1310. * @throws \Exception
  1311. *
  1312. * @return array
  1313. */
  1314. public function provideExtraTime()
  1315. {
  1316. $ntfsExtra = NtfsExtraField::create(
  1317. new \DateTimeImmutable('-1 week'),
  1318. new \DateTimeImmutable('-1 month'),
  1319. new \DateTimeImmutable('-1 year')
  1320. );
  1321. $extendedTimestampExtraField = ExtendedTimestampExtraField::create(
  1322. strtotime('-2 weeks'),
  1323. strtotime('-2 months'),
  1324. strtotime('-2 years')
  1325. );
  1326. $oldUnixExtraField = new OldUnixExtraField(
  1327. strtotime('-3 weeks'),
  1328. strtotime('-3 months'),
  1329. 1000,
  1330. 1000
  1331. );
  1332. $ntfsTimeCollection = new ExtraFieldsCollection();
  1333. $ntfsTimeCollection->add($ntfsExtra);
  1334. $extendedTimestampCollection = new ExtraFieldsCollection();
  1335. $extendedTimestampCollection->add($extendedTimestampExtraField);
  1336. $oldUnixExtraFieldCollection = new ExtraFieldsCollection();
  1337. $oldUnixExtraFieldCollection->add($oldUnixExtraField);
  1338. $oldExtendedCollection = clone $oldUnixExtraFieldCollection;
  1339. $oldExtendedCollection->add($extendedTimestampExtraField);
  1340. $fullCollection = clone $oldExtendedCollection;
  1341. $fullCollection->add($ntfsExtra);
  1342. return [
  1343. [
  1344. $ntfsTimeCollection,
  1345. $ntfsExtra->getModifyDateTime(),
  1346. $ntfsExtra->getAccessDateTime(),
  1347. $ntfsExtra->getCreateDateTime(),
  1348. ],
  1349. [
  1350. $extendedTimestampCollection,
  1351. $extendedTimestampExtraField->getModifyDateTime(),
  1352. $extendedTimestampExtraField->getAccessDateTime(),
  1353. $extendedTimestampExtraField->getCreateDateTime(),
  1354. ],
  1355. [
  1356. $oldUnixExtraFieldCollection,
  1357. $oldUnixExtraField->getModifyDateTime(),
  1358. $oldUnixExtraField->getAccessDateTime(),
  1359. null,
  1360. ],
  1361. [
  1362. $oldExtendedCollection,
  1363. $extendedTimestampExtraField->getModifyDateTime(),
  1364. $extendedTimestampExtraField->getAccessDateTime(),
  1365. $extendedTimestampExtraField->getCreateDateTime(),
  1366. ],
  1367. [
  1368. $fullCollection,
  1369. $ntfsExtra->getModifyDateTime(),
  1370. $ntfsExtra->getAccessDateTime(),
  1371. $ntfsExtra->getCreateDateTime(),
  1372. ],
  1373. ];
  1374. }
  1375. /**
  1376. * @throws ZipException
  1377. */
  1378. public function testClone()
  1379. {
  1380. $newUnixExtra = new NewUnixExtraField();
  1381. $zipEntry = new ZipEntry('entry');
  1382. $zipData = new ZipFileData($zipEntry, new \SplFileInfo(__FILE__));
  1383. $zipEntry->addExtraField($newUnixExtra);
  1384. $zipEntry->setData($zipData);
  1385. $cloneEntry = clone $zipEntry;
  1386. static::assertNotSame($cloneEntry, $zipEntry);
  1387. static::assertNotSame($cloneEntry->getCdExtraFields(), $zipEntry->getCdExtraFields());
  1388. static::assertNotSame($cloneEntry->getLocalExtraFields(), $zipEntry->getLocalExtraFields());
  1389. static::assertNotSame($cloneEntry->getCdExtraField(NewUnixExtraField::HEADER_ID), $newUnixExtra);
  1390. static::assertNotSame($cloneEntry->getLocalExtraField(NewUnixExtraField::HEADER_ID), $newUnixExtra);
  1391. static::assertNotSame($cloneEntry->getData(), $zipData);
  1392. }
  1393. public function testExtraCollection()
  1394. {
  1395. $zipEntry = new ZipEntry('entry');
  1396. $cdCollection = $zipEntry->getCdExtraFields();
  1397. $localCollection = $zipEntry->getLocalExtraFields();
  1398. static::assertNotSame($cdCollection, $localCollection);
  1399. $anotherCollection = new ExtraFieldsCollection();
  1400. $anotherCollection->add(new JarMarkerExtraField());
  1401. $anotherCollection->add(new AsiExtraField(0100777, 1000, 1000));
  1402. $zipEntry->setCdExtraFields($anotherCollection);
  1403. static::assertSame($anotherCollection, $zipEntry->getCdExtraFields());
  1404. static::assertSame($localCollection, $zipEntry->getLocalExtraFields());
  1405. $zipEntry->setLocalExtraFields($anotherCollection);
  1406. static::assertSame($anotherCollection, $zipEntry->getLocalExtraFields());
  1407. static::assertSame($zipEntry->getCdExtraFields(), $zipEntry->getLocalExtraFields());
  1408. $newUnixExtraField = new NewUnixExtraField(1, 1000, 1000);
  1409. $zipEntry->getCdExtraFields()->add($newUnixExtraField);
  1410. static::assertSame($zipEntry->getCdExtraField(NewUnixExtraField::HEADER_ID), $newUnixExtraField);
  1411. static::assertSame($zipEntry->getLocalExtraField(NewUnixExtraField::HEADER_ID), $newUnixExtraField);
  1412. }
  1413. }