ZipEntryTest.php 55 KB

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