ZipModel.php 8.2 KB

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