diff options
Diffstat (limited to 'vendor/mikespub/php-epub-meta/src/Data')
-rw-r--r-- | vendor/mikespub/php-epub-meta/src/Data/Item.php | 193 | ||||
-rw-r--r-- | vendor/mikespub/php-epub-meta/src/Data/Manifest.php | 174 |
2 files changed, 367 insertions, 0 deletions
diff --git a/vendor/mikespub/php-epub-meta/src/Data/Item.php b/vendor/mikespub/php-epub-meta/src/Data/Item.php new file mode 100644 index 000000000..271462920 --- /dev/null +++ b/vendor/mikespub/php-epub-meta/src/Data/Item.php @@ -0,0 +1,193 @@ +<?php + +namespace SebLucas\EPubMeta\Data; + +use SebLucas\EPubMeta\Tools\HtmlTools; +use DOMDocument; +use DOMElement; +use DOMText; +use DOMXPath; +use Exception; + +/** + * An item of the EPUB manifest. + * + * @author Simon Schrape <simon@epubli.com> + */ +class Item +{ + public const XHTML = 'application/xhtml+xml'; + /** @var string */ + protected $id; + /** @var string The path to the corresponding file. */ + protected $href; + /** @var string */ + protected $mediaType; + /** @var callable|null A callable to get data from the referenced file. */ + protected $dataCallable; + /** @var string The data read from the referenced file. */ + protected $data; + /** @var int The size of the referenced file. */ + protected $size; + + /** + * @param string $id This Item’s identifier. + * @param string $href The path to the corresponding file. + * @param callable $dataCallable A callable to get data from the referenced file. + * @param int $size The size of the referenced file. + * @param string|null $mediaType The media type of the corresponding file. If omitted XHTML is assumed. + */ + public function __construct($id, $href, $dataCallable, $size, $mediaType = null) + { + $this->id = $id; + $this->href = $href; + $this->dataCallable = $dataCallable; + $this->size = $size; + $this->mediaType = $mediaType ?: static::XHTML; + } + + /** + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getHref() + { + return $this->href; + } + + /** + * @return string + */ + public function getMediaType() + { + return $this->mediaType; + } + + /** + * Extract (a part of) the contents from the referenced XML file. + * + * @param string|null $fragmentBegin ID of the element where to start reading the contents. + * @param string|null $fragmentEnd ID of the element where to stop reading the contents. + * @param bool $keepMarkup Whether to keep the XHTML markup rather than extracted plain text. + * @return string The contents of that fragment. + * @throws Exception + */ + public function getContents($fragmentBegin = null, $fragmentEnd = null, $keepMarkup = false) + { + $dom = new DOMDocument(); + $dom->loadXML(HtmlTools::convertEntitiesNamedToNumeric($this->getData())); + + // get the starting point + if ($fragmentBegin) { + $xp = new DOMXPath($dom); + $node = $xp->query("//*[@id='$fragmentBegin']")->item(0); + if (!$node) { + throw new Exception("Begin of fragment not found: No element with ID $fragmentBegin!"); + } + } else { + $node = $dom->getElementsByTagName('body')->item(0) ?: $dom->documentElement; + } + + $allowableTags = [ + 'br', + 'p', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'span', + 'div', + 'i', + 'strong', + 'b', + 'table', + 'td', + 'th', + 'tr', + ]; + $contents = ''; + $endTags = []; + /** @var DOMElement|DOMText $node */ + // traverse DOM structure till end point is reached, accumulating the contents + while ($node && (!$fragmentEnd || !$node->hasAttributes() || $node->getAttribute('id') != $fragmentEnd)) { + if ($node instanceof DOMText) { + // when encountering a text node append its value to the contents + $contents .= $keepMarkup ? htmlspecialchars($node->nodeValue) : $node->nodeValue; + } elseif ($node instanceof DOMElement) { + $tag = $node->localName; + if ($keepMarkup && in_array($tag, $allowableTags)) { + $contents .= "<$tag>"; + $endTags[] = "</$tag>"; + } elseif (HtmlTools::isBlockLevelElement($tag)) { + // add whitespace between contents of adjacent blocks + $endTags[] = PHP_EOL; + } else { + $endTags[] = ''; + } + + if ($node->hasChildNodes()) { + // step into + $node = $node->firstChild; + continue; + } + } + + // leave node + while ($node) { + if ($node instanceof DOMElement) { + $contents .= array_pop($endTags); + } + + if ($node->nextSibling) { + // step right + $node = $node->nextSibling; + break; + } elseif ($node = $node->parentNode) { + // step out + continue; + } elseif ($fragmentEnd) { + // reached end of DOM without finding fragment end + throw new Exception("End of fragment not found: No element with ID $fragmentEnd!"); + } + } + } + while ($endTags) { + $contents .= array_pop($endTags); + } + + return $contents; + } + + /** + * Get the file data. + * + * @return string The binary data of the corresponding file. + */ + public function getData() + { + if ($this->dataCallable) { + $this->data = call_user_func($this->dataCallable); + $this->dataCallable = null; + } + + return $this->data; + } + + /** + * Get the size of the corresponding file. + * + * @return int + */ + public function getSize() + { + return $this->size ?: strlen($this->getData()); + } +} diff --git a/vendor/mikespub/php-epub-meta/src/Data/Manifest.php b/vendor/mikespub/php-epub-meta/src/Data/Manifest.php new file mode 100644 index 000000000..428b2cc02 --- /dev/null +++ b/vendor/mikespub/php-epub-meta/src/Data/Manifest.php @@ -0,0 +1,174 @@ +<?php + +namespace SebLucas\EPubMeta\Data; + +use ArrayAccess; +use Countable; +use Exception; +use BadMethodCallException; +use Iterator; + +/** + * EPUB manifest structure + * + * @author Simon Schrape <simon@epubli.com> + * @implements \Iterator<string, Item> + * @implements \ArrayAccess<string, Item> + */ +class Manifest implements Iterator, Countable, ArrayAccess +{ + /** @var array|Item[] The map of all Items in this Manifest indexed by their IDs. */ + protected $items = []; + + /** + * Create and add an Item with the given properties. + * + * @param string $id The identifier of the new item. + * @param string $href The relative path of the referenced file in the EPUB. + * @param callable $callable A callable to get data from the referenced file in the EPUB. + * @param int $size The size of the referenced file in the EPUB. + * @param string|null $mediaType + * @return Item The newly created Item. + * @throws Exception If $id is already taken. + */ + public function createItem($id, $href, $callable, $size, $mediaType = null) + { + if (isset($this->items[$id])) { + throw new Exception("Item with ID $id already exists!"); + } + $item = new Item($id, $href, $callable, $size, $mediaType); + $this->items[$id] = $item; + + return $item; + } + + /** + * Return the current Item while iterating this Manifest. + * + * @link http://php.net/manual/en/iterator.current.php + * @return Item + */ + public function current(): Item + { + return current($this->items); + } + + /** + * Move forward to next Item while iterating this Manifest. + * @link http://php.net/manual/en/iterator.next.php + * @return void Any returned value is ignored. + */ + public function next(): void + { + next($this->items); + } + + /** + * Return the ID of the current Item while iterating this Manifest. + * + * @link http://php.net/manual/en/iterator.key.php + * @return string|null on success, or null on failure. + */ + public function key(): ?string + { + return key($this->items); + } + + /** + * Checks if current Iterator position is valid. + * + * @link http://php.net/manual/en/iterator.valid.php + * @return boolean true on success or false on failure. + */ + public function valid(): bool + { + return (bool) current($this->items); + } + + /** + * Rewind the Iterator to the first element. + * + * @link http://php.net/manual/en/iterator.rewind.php + * @return void Any returned value is ignored. + */ + public function rewind(): void + { + reset($this->items); + } + + /** + * Get the first Item of this Manifest. + * + * @return Item + */ + public function first() + { + return reset($this->items); + } + + /** + * Get the last Item of this Manifest. + * + * @return Item + */ + public function last() + { + return end($this->items); + } + + /** + * Count items of this Manifest. + * + * @link https://php.net/manual/en/countable.count.php + * @return int The number of Items contained in this Manifest. + */ + public function count(): int + { + return count($this->items); + } + + /** + * Whether a offset exists + * @link https://php.net/manual/en/arrayaccess.offsetexists.php + * @param string $offset An offset to check for. + * @return boolean true on success or false on failure. + */ + public function offsetExists($offset): bool + { + return isset($this->items[$offset]); + } + + /** + * Offset to retrieve + * @link https://php.net/manual/en/arrayaccess.offsetget.php + * @param string $offset The offset to retrieve. + * @return Item + */ + public function offsetGet($offset): Item + { + return $this->items[$offset]; + } + + /** + * Offset to set + * @link https://php.net/manual/en/arrayaccess.offsetset.php + * @param mixed $offset The offset to assign the value to. + * @param mixed $value The value to set. + * @throws BadMethodCallException + */ + public function offsetSet($offset, $value): void + { + throw new BadMethodCallException("Only reading array access is supported!"); + } + + /** + * Offset to unset + * @link https://php.net/manual/en/arrayaccess.offsetunset.php + * @param mixed $offset The offset to unset. + * @throws BadMethodCallException + */ + public function offsetUnset($offset): void + { + throw new BadMethodCallException("Only reading array access is supported!"); + } +} |