ZipModel.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. <?php
  2. namespace PhpZip\Model;
  3. use PhpZip\Exception\InvalidArgumentException;
  4. use PhpZip\Exception\ZipEntryNotFoundException;
  5. use PhpZip\Exception\ZipException;
  6. use PhpZip\Model\Entry\ZipChangesEntry;
  7. use PhpZip\Model\Entry\ZipSourceEntry;
  8. use PhpZip\ZipFile;
  9. /**
  10. * Zip Model.
  11. *
  12. * @author Ne-Lexa alexey@nelexa.ru
  13. * @license MIT
  14. */
  15. class ZipModel implements \Countable
  16. {
  17. /** @var ZipSourceEntry[] */
  18. protected $inputEntries = [];
  19. /** @var ZipEntry[] */
  20. protected $outEntries = [];
  21. /** @var string|null */
  22. protected $archiveComment;
  23. /** @var string|null */
  24. protected $archiveCommentChanges;
  25. /** @var bool */
  26. protected $archiveCommentChanged = false;
  27. /** @var int|null */
  28. protected $zipAlign;
  29. /** @var bool */
  30. private $zip64;
  31. /**
  32. * @param ZipSourceEntry[] $entries
  33. * @param EndOfCentralDirectory $endOfCentralDirectory
  34. *
  35. * @return ZipModel
  36. */
  37. public static function newSourceModel(array $entries, EndOfCentralDirectory $endOfCentralDirectory)
  38. {
  39. $model = new self();
  40. $model->inputEntries = $entries;
  41. $model->outEntries = $entries;
  42. $model->archiveComment = $endOfCentralDirectory->getComment();
  43. $model->zip64 = $endOfCentralDirectory->isZip64();
  44. return $model;
  45. }
  46. /**
  47. * @return string|null
  48. */
  49. public function getArchiveComment()
  50. {
  51. if ($this->archiveCommentChanged) {
  52. return $this->archiveCommentChanges;
  53. }
  54. return $this->archiveComment;
  55. }
  56. /**
  57. * @param string $comment
  58. */
  59. public function setArchiveComment($comment)
  60. {
  61. if ($comment !== null && $comment !== '') {
  62. $comment = (string) $comment;
  63. $length = \strlen($comment);
  64. if ($length > 0xffff) {
  65. throw new InvalidArgumentException('Length comment out of range');
  66. }
  67. }
  68. if ($comment !== $this->archiveComment) {
  69. $this->archiveCommentChanges = $comment;
  70. $this->archiveCommentChanged = true;
  71. } else {
  72. $this->archiveCommentChanged = false;
  73. }
  74. }
  75. /**
  76. * Specify a password for extracting files.
  77. *
  78. * @param string|null $password
  79. *
  80. * @throws ZipException
  81. */
  82. public function setReadPassword($password)
  83. {
  84. foreach ($this->inputEntries as $entry) {
  85. if ($entry->isEncrypted()) {
  86. $entry->setPassword($password);
  87. }
  88. }
  89. }
  90. /**
  91. * @param string $entryName
  92. * @param string $password
  93. *
  94. * @throws ZipEntryNotFoundException
  95. * @throws ZipException
  96. */
  97. public function setReadPasswordEntry($entryName, $password)
  98. {
  99. if (!isset($this->inputEntries[$entryName])) {
  100. throw new ZipEntryNotFoundException($entryName);
  101. }
  102. if ($this->inputEntries[$entryName]->isEncrypted()) {
  103. $this->inputEntries[$entryName]->setPassword($password);
  104. }
  105. }
  106. /**
  107. * @return int|null
  108. */
  109. public function getZipAlign()
  110. {
  111. return $this->zipAlign;
  112. }
  113. /**
  114. * @param int|null $zipAlign
  115. */
  116. public function setZipAlign($zipAlign)
  117. {
  118. $this->zipAlign = $zipAlign === null ? null : (int) $zipAlign;
  119. }
  120. /**
  121. * @return bool
  122. */
  123. public function isZipAlign()
  124. {
  125. return $this->zipAlign !== null;
  126. }
  127. /**
  128. * @param string|null $writePassword
  129. */
  130. public function setWritePassword($writePassword)
  131. {
  132. $this->matcher()->all()->setPassword($writePassword);
  133. }
  134. /**
  135. * Remove password.
  136. */
  137. public function removePassword()
  138. {
  139. $this->matcher()->all()->setPassword(null);
  140. }
  141. /**
  142. * @param string|ZipEntry $entryName
  143. */
  144. public function removePasswordEntry($entryName)
  145. {
  146. $this->matcher()->add($entryName)->setPassword(null);
  147. }
  148. /**
  149. * @return bool
  150. */
  151. public function isArchiveCommentChanged()
  152. {
  153. return $this->archiveCommentChanged;
  154. }
  155. /**
  156. * @param string|ZipEntry $old
  157. * @param string|ZipEntry $new
  158. *
  159. * @throws ZipException
  160. */
  161. public function renameEntry($old, $new)
  162. {
  163. $old = $old instanceof ZipEntry ? $old->getName() : (string) $old;
  164. $new = $new instanceof ZipEntry ? $new->getName() : (string) $new;
  165. if (isset($this->outEntries[$new])) {
  166. throw new InvalidArgumentException('New entry name ' . $new . ' is exists.');
  167. }
  168. $entry = $this->getEntryForChanges($old);
  169. $entry->setName($new);
  170. $this->deleteEntry($old);
  171. $this->addEntry($entry);
  172. }
  173. /**
  174. * @param string|ZipEntry $entry
  175. *
  176. * @throws ZipEntryNotFoundException
  177. * @throws ZipException
  178. *
  179. * @return ZipChangesEntry|ZipEntry
  180. */
  181. public function getEntryForChanges($entry)
  182. {
  183. $entry = $this->getEntry($entry);
  184. if ($entry instanceof ZipSourceEntry) {
  185. $entry = new ZipChangesEntry($entry);
  186. $this->addEntry($entry);
  187. }
  188. return $entry;
  189. }
  190. /**
  191. * @param string|ZipEntry $entryName
  192. *
  193. * @throws ZipEntryNotFoundException
  194. *
  195. * @return ZipEntry
  196. */
  197. public function getEntry($entryName)
  198. {
  199. $entryName = $entryName instanceof ZipEntry ? $entryName->getName() : (string) $entryName;
  200. if (isset($this->outEntries[$entryName])) {
  201. return $this->outEntries[$entryName];
  202. }
  203. throw new ZipEntryNotFoundException($entryName);
  204. }
  205. /**
  206. * @param string|ZipEntry $entry
  207. *
  208. * @return bool
  209. */
  210. public function deleteEntry($entry)
  211. {
  212. $entry = $entry instanceof ZipEntry ? $entry->getName() : (string) $entry;
  213. if (isset($this->outEntries[$entry])) {
  214. unset($this->outEntries[$entry]);
  215. return true;
  216. }
  217. return false;
  218. }
  219. /**
  220. * @param ZipEntry $entry
  221. */
  222. public function addEntry(ZipEntry $entry)
  223. {
  224. $this->outEntries[$entry->getName()] = $entry;
  225. }
  226. /**
  227. * Get all entries with changes.
  228. *
  229. * @return ZipEntry[]
  230. */
  231. public function &getEntries()
  232. {
  233. return $this->outEntries;
  234. }
  235. /**
  236. * @param string|ZipEntry $entryName
  237. *
  238. * @return bool
  239. */
  240. public function hasEntry($entryName)
  241. {
  242. $entryName = $entryName instanceof ZipEntry ? $entryName->getName() : (string) $entryName;
  243. return isset($this->outEntries[$entryName]);
  244. }
  245. /**
  246. * Delete all entries.
  247. */
  248. public function deleteAll()
  249. {
  250. $this->outEntries = [];
  251. }
  252. /**
  253. * Count elements of an object.
  254. *
  255. * @see http://php.net/manual/en/countable.count.php
  256. *
  257. * @return int The custom count as an integer.
  258. * </p>
  259. * <p>
  260. * The return value is cast to an integer.
  261. *
  262. * @since 5.1.0
  263. */
  264. public function count()
  265. {
  266. return \count($this->outEntries);
  267. }
  268. /**
  269. * Undo all changes done in the archive.
  270. */
  271. public function unchangeAll()
  272. {
  273. $this->outEntries = $this->inputEntries;
  274. $this->unchangeArchiveComment();
  275. }
  276. /**
  277. * Undo change archive comment.
  278. */
  279. public function unchangeArchiveComment()
  280. {
  281. $this->archiveCommentChanges = null;
  282. $this->archiveCommentChanged = false;
  283. }
  284. /**
  285. * Revert all changes done to an entry with the given name.
  286. *
  287. * @param string|ZipEntry $entry Entry name or ZipEntry
  288. *
  289. * @return bool
  290. */
  291. public function unchangeEntry($entry)
  292. {
  293. $entry = $entry instanceof ZipEntry ? $entry->getName() : (string) $entry;
  294. if (isset($this->outEntries[$entry], $this->inputEntries[$entry])) {
  295. $this->outEntries[$entry] = $this->inputEntries[$entry];
  296. return true;
  297. }
  298. return false;
  299. }
  300. /**
  301. * @param int $encryptionMethod
  302. */
  303. public function setEncryptionMethod($encryptionMethod = ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256)
  304. {
  305. $this->matcher()->all()->setEncryptionMethod($encryptionMethod);
  306. }
  307. /**
  308. * @return ZipEntryMatcher
  309. */
  310. public function matcher()
  311. {
  312. return new ZipEntryMatcher($this);
  313. }
  314. }