2
0

ZipEntryTest.php 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616
  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. $zipData = new ZipFileData(new \SplFileInfo(__FILE__));
  1382. $zipEntry = new ZipEntry('entry');
  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. }