ExtraFieldsCollection.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php
  2. namespace PhpZip\Extra;
  3. use PhpZip\Exception\InvalidArgumentException;
  4. use PhpZip\Exception\ZipException;
  5. /**
  6. * Represents a collection of Extra Fields as they may
  7. * be present at several locations in ZIP files.
  8. *
  9. * @author Ne-Lexa alexey@nelexa.ru
  10. * @license MIT
  11. */
  12. class ExtraFieldsCollection implements \Countable, \ArrayAccess, \Iterator
  13. {
  14. /**
  15. * The map of Extra Fields.
  16. * Maps from Header ID to Extra Field.
  17. * Must not be null, but may be empty if no Extra Fields are used.
  18. * The map is sorted by Header IDs in ascending order.
  19. *
  20. * @var ExtraField[]
  21. */
  22. protected $collection = [];
  23. /**
  24. * Returns the number of Extra Fields in this collection.
  25. *
  26. * @return int
  27. */
  28. public function count()
  29. {
  30. return sizeof($this->collection);
  31. }
  32. /**
  33. * Returns the Extra Field with the given Header ID or null
  34. * if no such Extra Field exists.
  35. *
  36. * @param int $headerId The requested Header ID.
  37. * @return ExtraField The Extra Field with the given Header ID or
  38. * if no such Extra Field exists.
  39. * @throws ZipException If headerId is out of range.
  40. */
  41. public function get($headerId)
  42. {
  43. if (0x0000 > $headerId || $headerId > 0xffff) {
  44. throw new ZipException('headerId out of range');
  45. }
  46. if (isset($this->collection[$headerId])) {
  47. return $this->collection[$headerId];
  48. }
  49. return null;
  50. }
  51. /**
  52. * Stores the given Extra Field in this collection.
  53. *
  54. * @param ExtraField $extraField The Extra Field to store in this collection.
  55. * @return ExtraField The Extra Field previously associated with the Header ID of
  56. * of the given Extra Field or null if no such Extra Field existed.
  57. * @throws ZipException If headerId is out of range.
  58. */
  59. public function add(ExtraField $extraField)
  60. {
  61. $headerId = $extraField::getHeaderId();
  62. if (0x0000 > $headerId || $headerId > 0xffff) {
  63. throw new ZipException('headerId out of range');
  64. }
  65. $this->collection[$headerId] = $extraField;
  66. return $extraField;
  67. }
  68. /**
  69. * Returns Extra Field exists
  70. *
  71. * @param int $headerId The requested Header ID.
  72. * @return bool
  73. */
  74. public function has($headerId)
  75. {
  76. return isset($this->collection[$headerId]);
  77. }
  78. /**
  79. * Removes the Extra Field with the given Header ID.
  80. *
  81. * @param int $headerId The requested Header ID.
  82. * @return ExtraField The Extra Field with the given Header ID or null
  83. * if no such Extra Field exists.
  84. * @throws ZipException If headerId is out of range or extra field not found.
  85. */
  86. public function remove($headerId)
  87. {
  88. if (0x0000 > $headerId || $headerId > 0xffff) {
  89. throw new ZipException('headerId out of range');
  90. }
  91. if (isset($this->collection[$headerId])) {
  92. $ef = $this->collection[$headerId];
  93. unset($this->collection[$headerId]);
  94. return $ef;
  95. }
  96. throw new ZipException('ExtraField not found');
  97. }
  98. /**
  99. * Whether a offset exists
  100. * @link http://php.net/manual/en/arrayaccess.offsetexists.php
  101. * @param mixed $offset <p>
  102. * An offset to check for.
  103. * </p>
  104. * @return boolean true on success or false on failure.
  105. * </p>
  106. * <p>
  107. * The return value will be casted to boolean if non-boolean was returned.
  108. * @since 5.0.0
  109. */
  110. public function offsetExists($offset)
  111. {
  112. return isset($this->collection[$offset]);
  113. }
  114. /**
  115. * Offset to retrieve
  116. * @link http://php.net/manual/en/arrayaccess.offsetget.php
  117. * @param mixed $offset <p>
  118. * The offset to retrieve.
  119. * </p>
  120. * @return mixed Can return all value types.
  121. * @since 5.0.0
  122. * @throws ZipException
  123. */
  124. public function offsetGet($offset)
  125. {
  126. return $this->get($offset);
  127. }
  128. /**
  129. * Offset to set
  130. * @link http://php.net/manual/en/arrayaccess.offsetset.php
  131. * @param mixed $offset <p>
  132. * The offset to assign the value to.
  133. * </p>
  134. * @param mixed $value <p>
  135. * The value to set.
  136. * </p>
  137. * @return void
  138. * @throws ZipException
  139. * @since 5.0.0
  140. */
  141. public function offsetSet($offset, $value)
  142. {
  143. if ($value instanceof ExtraField) {
  144. if ($offset !== $value::getHeaderId()) {
  145. throw new InvalidArgumentException("Value header id !== array access key");
  146. }
  147. $this->add($value);
  148. } else {
  149. throw new InvalidArgumentException('value is not instanceof ' . ExtraField::class);
  150. }
  151. }
  152. /**
  153. * Offset to unset
  154. * @link http://php.net/manual/en/arrayaccess.offsetunset.php
  155. * @param mixed $offset <p>
  156. * The offset to unset.
  157. * </p>
  158. * @return void
  159. * @since 5.0.0
  160. * @throws ZipException
  161. */
  162. public function offsetUnset($offset)
  163. {
  164. $this->remove($offset);
  165. }
  166. /**
  167. * Return the current element
  168. * @link http://php.net/manual/en/iterator.current.php
  169. * @return mixed Can return any type.
  170. * @since 5.0.0
  171. */
  172. public function current()
  173. {
  174. return current($this->collection);
  175. }
  176. /**
  177. * Move forward to next element
  178. * @link http://php.net/manual/en/iterator.next.php
  179. * @return void Any returned value is ignored.
  180. * @since 5.0.0
  181. */
  182. public function next()
  183. {
  184. next($this->collection);
  185. }
  186. /**
  187. * Return the key of the current element
  188. * @link http://php.net/manual/en/iterator.key.php
  189. * @return mixed scalar on success, or null on failure.
  190. * @since 5.0.0
  191. */
  192. public function key()
  193. {
  194. return key($this->collection);
  195. }
  196. /**
  197. * Checks if current position is valid
  198. * @link http://php.net/manual/en/iterator.valid.php
  199. * @return boolean The return value will be casted to boolean and then evaluated.
  200. * Returns true on success or false on failure.
  201. * @since 5.0.0
  202. */
  203. public function valid()
  204. {
  205. return $this->offsetExists($this->key());
  206. }
  207. /**
  208. * Rewind the Iterator to the first element
  209. * @link http://php.net/manual/en/iterator.rewind.php
  210. * @return void Any returned value is ignored.
  211. * @since 5.0.0
  212. */
  213. public function rewind()
  214. {
  215. reset($this->collection);
  216. }
  217. /**
  218. * If clone extra fields.
  219. */
  220. public function __clone()
  221. {
  222. foreach ($this->collection as $k => $v) {
  223. $this->collection[$k] = clone $v;
  224. }
  225. }
  226. }