EPub requires Zip.php at version " . self::REQ_ZIP_VERSION . " or higher.
You can obtain the latest version from http://www.phpclasses.org/browse/package/6110.html.

"); } include_once("EPubChapterSplitter.class.php"); $this->docRoot = $_SERVER["DOCUMENT_ROOT"] . "/"; $this->zip = new Zip(); $this->zip->addFile("application/epub+zip", "mimetype"); $this->zip->addDirectory("META-INF/"); $this->content = "\n\n\t\n\t\t\n\t\n\n"; $this->zip->addFile($this->content, "META-INF/container.xml"); $this->content = NULL; $this->opf_manifest = "\t\t\n"; $this->chapterCount = 0; $this->isGdInstalled = extension_loaded('gd') && function_exists('gd_info'); } /** * Class destructor * * @return void */ function __destruct() { $this->zip = NULL; $this->title = ""; $this->author = ""; $this->publisher = ""; $this->publishDate = 0; $this->bookId = ""; $this->opf_manifest = ""; $this->opf_spine = ""; $this->ncx_navmap = ""; $this->opf = ""; $this->ncx = ""; $this->chapterCount = 0; $this->subject = ""; $this->coverage = ""; $this->relation = ""; $this->generator = ""; } /** * * @param String $fileName Filename to use for the file, must be unique for the book. * @param String $fileId Unique identifier for the file. * @param String $fileData File data * @param String $mimetype file mime type * @return bool $success */ function addFile($fileName, $fileId, $fileData, $mimetype) { if ($this->isFinalized || array_key_exists($fileName, $this->fileList)) { return FALSE; } $fileName = preg_replace('#\\\#i', "/", $fileName); $fileName = preg_replace('#^[/\.]+#i', "", $fileName); $this->zip->addFile($fileData, $fileName); $this->fileList[$fileName] = $fileName; $this->opf_manifest .= "\t\t\n"; return TRUE; } /** * Add a CSS file to the book. * * @param String $fileName Filename to use for the CSS file, must be unique for the book. * @param String $fileId Unique identifier for the file. * @param String $fileData CSS data * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? See documentation for processCSSExternalReferences for explanation. Default is EPub::EXTERNAL_REF_IGNORE. * @param String $baseDir Default is "", meaning it is pointing to the document root. NOT used if $externalReferences is set to EPub::EXTERNAL_REF_IGNORE. * * @return bool $success */ function addCSSFile($fileName, $fileId, $fileData, $externalReferences = EPub::EXTERNAL_REF_IGNORE, $baseDir = "") { if ($this->isFinalized || array_key_exists($fileName, $this->fileList)) { return FALSE; } $fileName = preg_replace('#\\\#i', "/", $fileName); $fileName = preg_replace('#^[/\.]+#i', "", $fileName); $cssDir = pathinfo($fileName); $cssDir = preg_replace('#^[/\.]+#i', "", $cssDir["dirname"] . "/"); if (!empty($cssDir)) { $cssDir = preg_replace('#[^/]+/#i', "../", $cssDir); } if ($externalReferences !== EPub::EXTERNAL_REF_IGNORE) { $this->processCSSExternalReferences($fileData, $externalReferences, $baseDir, $cssDir); } $this->zip->addFile($fileData, $fileName); $this->fileList[$fileName] = $fileName; $this->opf_manifest .= "\t\t\n"; return TRUE; } /** * Add a chapter to the book, as a chapter should not exceed 250kB, you can parse an array with multiple parts as $chapterData. * These will still only show up as a single chapter in the book TOC. * * @param String $chapterName Name of the chapter, will be use din the TOC * @param String $fileName Filename to use for the chapter, must be unique for the book. * @param String $chapter Chapter text in XHTML or array $chapterData valid XHTML data for the chapter. File should NOT exceed 250kB. * @param Bool $autoSplit Should the chapter be split if it exceeds the default split size? Default=FALSE, only used if $chapterData is a String. * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? See documentation for processChapterExternalReferences for explanation. Default is EPub::EXTERNAL_REF_IGNORE. * @param String $baseDir Default is "", meaning it is pointing to the document root. NOT used if $externalReferences is set to EPub::EXTERNAL_REF_IGNORE. * @return bool $success */ function addChapter($chapterName, $fileName, $chapterData, $autoSplit = FALSE, $externalReferences = EPub::EXTERNAL_REF_IGNORE, $baseDir = "") { if ($this->isFinalized) { return FALSE; } $fileName = preg_replace('#\\\#i', "/", $fileName); $fileName = preg_replace('#^[/\.]+#i', "", $fileName); $htmlDir = pathinfo($fileName); $htmlDir = preg_replace('#^[/\.]+#i', "", $htmlDir["dirname"] . "/"); $chapter = $chapterData; if ($autoSplit && is_string($chapterData) && mb_strlen($chapterData) > $this->splitDefaultSize) { $splitter = new EPubChapterSplitter(); $chapterArray = $splitter->splitChapter($chapterData); if (count($chapterArray) > 1) { $chapter = $chapterArray; } } if (!empty($chapter) && is_string($chapter)) { if ($externalReferences !== EPub::EXTERNAL_REF_IGNORE) { $this->processChapterExternalReferences($chapter, $externalReferences, $baseDir, $htmlDir); } $this->zip->addFile($chapter, $fileName); $this->fileList[$fileName] = $fileName; $this->chapterCount++; $this->opf_manifest .= "\t\tchapterCount . "\" href=\"" . $fileName . "\" media-type=\"application/xhtml+xml\" />\n"; $this->opf_spine .= "\t\tchapterCount . "\" />\n"; $this->ncx_navmap .= "\n\t\tchapterCount . "\" playOrder=\"" . $this->chapterCount . "\">\n\t\t\t" . $chapterName . "\n\t\t\t\n\t\t\n"; } else if (is_array($chapter)) { $partCount = 0; $this->chapterCount++; $oneChapter = each($chapter); while ($oneChapter) { list($k, $v) = $oneChapter; $c = $v; if ($externalReferences !== EPub::EXTERNAL_REF_IGNORE) { $this->processChapterExternalReferences($c, $externalReferences, $baseDir); } $partCount++; $this->zip->addFile($c, $fileName . "-" . $partCount); $this->fileList[$fileName . "-" . $partCount] = $fileName . "-" . $partCount; $this->opf_manifest .= "\t\tchapterCount . "-" . $partCount . "\" href=\"" . $fileName . "-" . $partCount . "\" media-type=\"application/xhtml+xml\" />\n"; $this->opf_spine .= "\t\tchapterCount . "-" . $partCount . "\" />\n"; $oneChapter = each($chapter); } $this->ncx_navmap .= "\n\t\tchapterCount . "-1\" playOrder=\"" . $this->chapterCount . "\">\n\t\t\t" . $chapterName . "\n\t\t\t\n\t\t\n"; } return TRUE; } /** * Process external references from a HTML to the book. The chapter itself is not stored. * the HTML is scanned for <link..., <style..., and <img tags. * Embedded CSS styles and links will also be processed. * Script tags are not processed, as scripting should be avoided in e-books. * * EPub keeps track of added files, and duplicate files referenced across multiple * chapters, are only added once. * * If the $doc is a string, it is assumed to be the content of an HTML file, * else is it assumes to be a DOMDocument. * * Basedir is the root dir the HTML is supposed to "live" in, used to resolve * relative references such as <img src="../images/image.png"/> * * $externalReferences determins how the function will handle external references. * * @param mixed $doc (referenced) * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD. * @param String $baseDir Default is "", meaning it is pointing to the document root. * @param String $htmlDir The path to the parent HTML file's directory from the root of the archive. * * @return Bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE). */ protected function processChapterExternalReferences(&$doc, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $htmlDir = "") { if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) { return FALSE; } $backPath = preg_replace('#[^/]+/#i', "../", $htmlDir); $isDocAString = is_string($doc); $xmlDoc = NULL; if ($isDocAString) { $xmlDoc = new DOMDocument(); @$xmlDoc->loadHTML($doc); } else { $xmlDoc = $doc; } $this->processChapterStyles($xmlDoc, $externalReferences, $baseDir, $htmlDir); $this->processChapterLinks($xmlDoc, $externalReferences, $baseDir, $htmlDir, $backPath); $this->processChapterImages($xmlDoc, $externalReferences, $baseDir, $htmlDir, $backPath); if ($isDocAString) { $html = $xmlDoc->saveXML(); $head = $xmlDoc->getElementsByTagName("head"); $body = $xmlDoc->getElementsByTagName("body"); $xml = new DOMDocument('1.0', "utf-8"); $xml->lookupPrefix("http://www.w3.org/1999/xhtml"); $xml->preserveWhiteSpace = FALSE; $xml->formatOutput = TRUE; $xml2Doc = new DOMDocument('1.0', "utf-8"); $xml2Doc->lookupPrefix("http://www.w3.org/1999/xhtml"); $xml2Doc->loadXML("\n\n\n\n"); $html = $xml2Doc->getElementsByTagName("html")->item(0); $html->appendChild($xml2Doc->importNode($head->item(0), TRUE)); $html->appendChild($xml2Doc->importNode($body->item(0), TRUE)); // force pretty printing and correct formatting, should not be needed, but it is. $xml->loadXML($xml2Doc->saveXML()); $doc = $xml->saveXML(); } return TRUE; } /** * Process images referenced from an CSS file to the book. * * $externalReferences determins how the function will handle external references. * * @param String $cssFile (referenced) * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD. * @param String $baseDir Default is "", meaning it is pointing to the document root. * @param String $cssDir The of the CSS file's directory from the root of the archive. * * @return Bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE). */ protected function processCSSExternalReferences(&$cssFile, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $cssDir = "") { if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) { return FALSE; } $backPath = preg_replace('#[^/]+/#i', "../", $cssDir); preg_match_all('#url\s*\([\'\"\s]*(.+?)[\'\"\s]*\)#im', $cssFile, $imgs, PREG_SET_ORDER); $itemCount = count($imgs); for ($idx = 0; $idx < $itemCount; $idx++) { $img = $imgs[$idx]; if ($externalReferences === EPub::EXTERNAL_REF_REMOVE_IMAGES || $externalReferences === EPub::EXTERNAL_REF_REPLACE_IMAGES) { $cssFile = str_replace($img[0], "", $cssFile); } else { $source = $img[1]; $pathData = pathinfo($source); $internalSrc = $pathData['basename']; $internalPath = ""; $isSourceExternal = FALSE; if ($this->resolveImage($source, $internalPath, $internalSrc, $isSourceExternal, $baseDir, $cssDir, $backPath)) { $cssFile = str_replace($img[0], "url('" . $backPath . $internalPath . "')", $cssFile); } else if ($isSourceExternal) { $cssFile = str_replace($img[0], "", $cssFile); // External image is missing } // else do nothing, if the image is local, and missing, assume it's been generated. } } return TRUE; } /** * Process style tags in a DOMDocument. Styles will be passed as CSS files and reinserted into the document. * * @param DOMDocument $xmlDoc (referenced) * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD. * @param String $baseDir Default is "", meaning it is pointing to the document root. * @param String $htmlDir The path to the parent HTML file's directory from the root of the archive. * * @return Bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE). */ protected function processChapterStyles(&$xmlDoc, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $htmlDir = "") { if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) { return FALSE; } // process inlined CSS styles in style tags. $styles = $xmlDoc->getElementsByTagName("style"); $styleCount = $styles->length; for ($styleIdx = 0; $styleIdx < $styleCount; $styleIdx++) { $style = $styles->item($styleIdx); $styleData = $style->nodeValue; $styleData = preg_replace('#[/\*\s]*\<\!\[CDATA\[[\s\*/]*#im', "", $styleData); $styleData = preg_replace('#[/\*\s]*\]\]\>[\s\*/]*#im', "", $styleData); $this->processCSSExternalReferences($styleData, $externalReferences, $baseDir, $htmlDir); $style->nodeValue = "\n" . trim($styleData) . "\n"; } return TRUE; } /** * Process link tags in a DOMDocument. Linked files will be loaded into the archive, and the link src will be rewritten to point to that location. * Link types text/css will be passed as CSS files. * * @param DOMDocument $xmlDoc (referenced) * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD. * @param String $baseDir Default is "", meaning it is pointing to the document root. * @param String $htmlDir The path to the parent HTML file's directory from the root of the archive. * @param String $backPath The path to get back to the root of the archive from $htmlDir. * * @return Bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE). */ protected function processChapterLinks(&$xmlDoc, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $htmlDir = "", $backPath = "") { if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) { return FALSE; } // process link tags. $links = $xmlDoc->getElementsByTagName("link"); $linkCount = $links->length; for ($linkIdx = 0; $linkIdx < $linkCount; $linkIdx++) { $link = $links->item($linkIdx); $source = $link->attributes->getNamedItem("href")->nodeValue; $sourceData = NULL; $pathData = pathinfo($source); $internalSrc = $pathData['basename']; if (preg_match('#^(http|ftp)s?://#i', $source) == 1) { $urlinfo = parse_url($source); if (strpos($urlinfo['path'], $baseDir."/") !== FALSE) { $internalSrc = substr($urlinfo['path'], strpos($urlinfo['path'], $baseDir."/") + strlen($basedir) + 1); } @$sourceData = file_get_contents($source); } else if (strpos($source, "/") === 0) { @$sourceData = file_get_contents($this->docRoot . $source); } else { @$sourceData = file_get_contents($this->docRoot . $baseDir . "/" . $source); } if (!empty($sourceData)) { if (!array_key_exists($internalSrc, $this->fileList)) { $mime = $link->attributes->getNamedItem("type")->nodeValue; if (empty($mime)) { $mime = "text/plain"; } if ($mime == "text/css") { $this->processCSSExternalReferences($sourceData, $externalReferences, $baseDir, $htmlDir); $this->addCSSFile($internalSrc, $internalSrc, $sourceData, EPub::EXTERNAL_REF_IGNORE, $baseDir); $link->setAttribute("href", $backPath . $internalSrc); } else { $this->addFile($internalSrc, $internalSrc, $sourceData, $mime); } $this->fileList[$internalSrc] = $source; } else { $link->setAttribute("href", $backPath . $internalSrc); } } // else do nothing, if the link is local, and missing, assume it's been generated. } return TRUE; } /** * Process img tags in a DOMDocument. * $externalReferences will determine what will happen to these images, and the img src will be rewritten accordingly. * * @param DOMDocument $xmlDoc (referenced) * @param int $externalReferences How to handle external references, EPub::EXTERNAL_REF_IGNORE, EPub::EXTERNAL_REF_ADD or EPub::EXTERNAL_REF_REMOVE_IMAGES? Default is EPub::EXTERNAL_REF_ADD. * @param String $baseDir Default is "", meaning it is pointing to the document root. * @param String $htmlDir The path to the parent HTML file's directory from the root of the archive. * @param String $backPath The path to get back to the root of the archive from $htmlDir. * * @return Bool FALSE if uncuccessful (book is finalized or $externalReferences == EXTERNAL_REF_IGNORE). */ protected function processChapterImages(&$xmlDoc, $externalReferences = EPub::EXTERNAL_REF_ADD, $baseDir = "", $htmlDir = "", $backPath = "") { if ($this->isFinalized || $externalReferences === EPub::EXTERNAL_REF_IGNORE) { return FALSE; } // process img tags. $postProcDomElememts = array(); $images = $xmlDoc->getElementsByTagName("img"); $itemCount = $images->length; for ($idx = 0; $idx < $itemCount; $idx++) { $img = $images->item($idx); if ($externalReferences === EPub::EXTERNAL_REF_REMOVE_IMAGES) { $postProcDomElememts[] = $img; } else if ($externalReferences === EPub::EXTERNAL_REF_REPLACE_IMAGES) { $postProcDomElememts[] = array($img, $this->createDomFragment($xmlDoc, "[image]")); } else { $source = $img->attributes->getNamedItem("src")->nodeValue; $pathData = pathinfo($source); $internalSrc = $pathData['basename']; $internalPath = ""; $isSourceExternal = FALSE; if ($this->resolveImage($source, $internalPath, $internalSrc, $isSourceExternal, $baseDir, $htmlDir, $backPath)) { $img->setAttribute("src", $backPath . $internalPath); } else if ($isSourceExternal) { $postProcDomElememts[] = $img; // External image is missing } // else do nothing, if the image is local, and missing, assume it's been generated. } } foreach ($postProcDomElememts as $target) { if (is_array($target)) { $target[0]->parentNode->replaceChild($target[1], $target[0]); } else { $target->parentNode->removeChild($target); } } return TRUE; } /** * Resolve an image src and determine it's target location and add it to the book. * * @param String $source Image Source link. * @param String $internalPath (referenced) Return value, will be set to the target path and name in the book. * @param String $internalSrc (referenced) Return value, will be set to the target name in the book. * @param String $isSourceExternal (referenced) Return value, will be set to TRUE if the image originated from a full URL. * @param String $baseDir Default is "", meaning it is pointing to the document root. * @param String $htmlDir The path to the parent HTML file's directory from the root of the archive. * @param String $backPath The path to get back to the root of the archive from $htmlDir. */ protected function resolveImage($source, &$internalPath, &$internalSrc, &$isSourceExternal, $baseDir = "", $htmlDir = "", $backPath = "") { if ($this->isFinalized) { return FALSE; } $imageData = NULL; if (preg_match('#^(http|ftp)s?://#i', $source) == 1) { $urlinfo = parse_url($source); if (strpos($urlinfo['path'], $baseDir."/") !== FALSE) { $internalSrc = substr($urlinfo['path'], strpos($urlinfo['path'], $baseDir."/") + strlen($basedir) + 1); } $internalPath = $urlinfo["scheme"] . "/" . $urlinfo["host"] . "/" . pathinfo($urlinfo["path"], PATHINFO_DIRNAME); $isSourceExternal = TRUE; $imageData = $this->getImage($source); } else if (strpos($source, "/") === 0) { $internalPath = pathinfo($source, PATHINFO_DIRNAME); $imageData = $this->getImage($this->docRoot . $source); } else { $internalPath = $htmlDir . "/" . preg_replace('#^[/\.]+#', '', pathinfo($source, PATHINFO_DIRNAME)); $imageData = $this->getImage($this->docRoot . $baseDir . "/" . $source); } if ($imageData !== FALSE) { $internalPath = Zip::getRelativePath("images/" . $internalPath . "/" . $internalSrc); if (!array_key_exists($internalPath, $this->fileList)) { $this->addFile($internalPath, "i_" . $internalSrc, $imageData['image'], $imageData['mime']); $this->fileList[$internalPath] = $source; } return TRUE; } return FALSE; } /** * Add a cover image to the book. * * The styling and structure of the generated XHTML is heavily inspired by the XHTML generated by Calibre. * * @param String $fileName Filename to use for the image, must be unique for the book. * @param String $imageData Binary image data * @param String $mimetype Image mimetype, such as "image/jpeg" or "image/png". * @return bool $success */ function setCoverImage($fileName, $imageData = NULL, $mimetype = NULL) { if ($this->isFinalized || $this->isCoverImageSet || array_key_exists("CoverPage.html", $this->fileList)) { return FALSE; } if ($imageData == NULL) { // assume $fileName is the valig file path. $image = $this->getImage($this->docRoot . $fileName); $imageData = $image['image']; $mimetype = $image['mime']; } $path = pathinfo($this->docRoot . $fileName); $imgPath = "images/" . $path["basename"]; $coverPage = "\n\n\t\n\t\t\n\t\tCover Image\n\t\t\n\t\n\t\n\t\t
\n\t\t\t\"Cover\n\t\t
\n\t\n\n"; $this->zip->addFile($coverPage, "CoverPage.html"); $this->zip->addFile($imageData, $imgPath); $this->fileList["CoverPage.html"] = "CoverPage.html"; $this->fileList[$imgPath] = $fileName; $this->opf_manifest = "\t\t\n" . $this->opf_manifest; $this->opf_manifest = "\t\t\n" . $this->opf_manifest; $this->opf_spine = "\t\t\n" . $this->opf_spine; $this->opf_guide .= "\t\t\n"; $this->ncx_navmap = "\n\t\t\n\t\t\tCover\n\t\t\t\n\t\t\n" . $this->ncx_navmap; $this->isCoverImageSet = TRUE; return TRUE; } /** * Get Book Chapter count. * * @access public * @return number of chapters */ function getChapterCount() { return $this->chapterCount; } /** * Book title, mandatory. * * Used for the dc:title metadata parameter in the OPF file as well as the DocTitle attribute in the NCX file. * * @param string $title * @access public * @return bool $success */ function setTitle($title) { if ($this->isFinalized) { return FALSE; } $this->title = $title; return TRUE; } /** * Get Book title. * * @access public * @return $title */ function getTitle() { return $this->title; } /** * Book language, mandatory * * Use the RFC3066 Language codes, such as "en", "da", "fr" etc. * Defaults to "en". * * Used for the dc:language metadata parameter in the OPF file. * * @param string $language * @access public * @return bool $success */ function setLanguage($language) { if ($this->isFinalized || mb_strlen($language) != 2) { return FALSE; } $this->language = $language; return TRUE; } /** * Get Book language. * * @access public * @return $language */ function getLanguage() { return $this->language; } /** * Unique book identifier, mandatory. * Use the URI, or ISBN if available. * * An unambiguous reference to the resource within a given context. * * Recommended best practice is to identify the resource by means of a * string conforming to a formal identification system. * * Used for the dc:identifier metadata parameter in the OPF file, as well * as dtb:uid in the NCX file. * * Identifier type should only be: * EPub::IDENTIFIER_URI * EPub::IDENTIFIER_ISBN * EPub::IDENTIFIER_UUID * * @param string $identifier * @param string $identifierType * @access public * @return bool $success */ function setIdentifier($identifier, $identifierType) { if ($this->isFinalized || ($identifierType !== EPub::IDENTIFIER_URI && $identifierType !== EPub::IDENTIFIER_ISBN && $identifierType !== EPub::IDENTIFIER_UUID)) { return FALSE; } $this->identifier = $identifier; $this->identifierType = $identifierType; return TRUE; } /** * Get Book identifier. * * @access public * @return $identifier */ function getIdentifier() { return $this->identifier; } /** * Get Book identifierType. * * @access public * @return $identifierType */ function getIdentifierType() { return $this->identifierType; } /** * Book description, optional. * * An account of the resource. * * Description may include but is not limited to: an abstract, a table of * contents, a graphical representation, or a free-text account of the * resource. * * Used for the dc:source metadata parameter in the OPF file * * @param string $description * @access public * @return bool $success */ function setDescription($description) { if ($this->isFinalized) { return FALSE; } $this->description = $description; return TRUE; } /** * Get Book description. * * @access public * @return $description */ function getDescription() { return $this->description; } /** * Book author or creator, optional. * The $authorSortKey is basically how the name is to be sorted, usually * it's "Lastname, First names" where the $author is the straight * "Firstnames Lastname" * * An entity primarily responsible for making the resource. * * Examples of a Creator include a person, an organization, or a service. * Typically, the name of a Creator should be used to indicate the entity. * * Used for the dc:creator metadata parameter in the OPF file and the * docAuthor attribure in the NCX file. * The sort key is used for the opf:file-as attribute in dc:creator. * * @param string $author * @param string $authorSortKey * @access public * @return bool $success */ function setAuthor($author, $authorSortKey) { if ($this->isFinalized) { return FALSE; } $this->author = $author; $this->authorSortKey = $authorSortKey; return TRUE; } /** * Get Book author. * * @access public * @return $author */ function getAuthor() { return $this->author; } /** * Publisher Information, optional. * * An entity responsible for making the resource available. * * Examples of a Publisher include a person, an organization, or a service. * Typically, the name of a Publisher should be used to indicate the entity. * * Used for the dc:publisher and dc:relation metadata parameters in the OPF file. * * @param string $publisherName * @param string $publisherURL * @access public * @return bool $success */ function setPublisher($publisherName, $publisherURL) { if ($this->isFinalized) { return FALSE; } $this->publisherName = $publisherName; $this->publisherURL = $publisherURL; return TRUE; } /** * Get Book publisherName. * * @access public * @return $publisherName */ function getPublisherName() { return $this->publisherName; } /** * Get Book publisherURL. * * @access public * @return $publisherURL */ function getPublisherURL() { return $this->publisherURL; } /** * Release date, optional. If left blank, the time of the finalization will * be used. * * A point or period of time associated with an event in the lifecycle of * the resource. * * Date may be used to express temporal information at any level of * granularity. Recommended best practice is to use an encoding scheme, * such as the W3CDTF profile of ISO 8601 [W3CDTF]. * * Used for the dc:date metadata parameter in the OPF file * * @param long $timestamp * @access public * @return bool $success */ function setDate($timestamp) { if ($this->isFinalized) { return FALSE; } $this->date = $timestamp; return TRUE; } /** * Get Book date. * * @access public * @return $date */ function getDate() { return $this->date; } /** * Book (copy)rights, optional. * * Information about rights held in and over the resource. * * Typically, rights information includes a statement about various * property rights associated with the resource, including intellectual * property rights. * * Used for the dc:rights metadata parameter in the OPF file * * @param string $rightsText * @access public * @return bool $success */ function setRights($rightsText) { if ($this->isFinalized) { return FALSE; } $this->rights = $rightsText; return TRUE; } /** * Get Book rights. * * @access public * @return $rights */ function getRights() { return $this->rights; } /** * Set book Subject. * * The topic of the resource. * * Typically, the subject will be represented using keywords, key phrases, * or classification codes. Recommended best practice is to use a * controlled vocabulary. To describe the spatial or temporal topic of the * resource, use the Coverage element. * * @param String $subject */ function setSubject($subject) { if ($this->isFinalized) { return; } $this->subject = $subject; } /** * Get the book subject. * * @return String The Subject. */ function getSubject() { return $this->subject; } /** * Book source URL, optional. * * A related resource from which the described resource is derived. * * The described resource may be derived from the related resource in whole * or in part. Recommended best practice is to identify the related * resource by means of a string conforming to a formal identification system. * * Used for the dc:source metadata parameter in the OPF file * * @param string $sourceURL * @access public * @return bool $success */ function setSourceURL($sourceURL) { if ($this->isFinalized) { return FALSE; } $this->sourceURL = $sourceURL; return TRUE; } /** * Get Book sourceURL. * * @access public * @return $sourceURL */ function getSourceURL() { return $this->sourceURL; } /** * Coverage, optional. * * The spatial or temporal topic of the resource, the spatial applicability * of the resource, or the jurisdiction under which the resource is relevant. * * Spatial topic and spatial applicability may be a named place or a location * specified by its geographic coordinates. Temporal topic may be a named * period, date, or date range. A jurisdiction may be a named administrative * entity or a geographic place to which the resource applies. Recommended * best practice is to use a controlled vocabulary such as the Thesaurus of * Geographic Names [TGN]. Where appropriate, named places or time periods * can be used in preference to numeric identifiers such as sets of * coordinates or date ranges. * * Used for the dc:coverage metadata parameter in the OPF file * * @param string $coverage * @access public * @return bool $success */ function setCoverage($coverage) { if ($this->isFinalized) { return FALSE; } $this->coverage = $coverage; return TRUE; } /** * Get Book coverage. * * @access public * @return $coverage */ function getCoverage() { return $this->coverage; } /** * Set book Relation. * * A related resource. * * Recommended best practice is to identify the related resource by means * of a string conforming to a formal identification system. * * @param String $relation */ function setRelation($relation) { if ($this->isFinalized) { return; } $this->relation = $relation; } /** * Get the book relation. * * @return String The relation. */ function getRelation() { return $this->relation; } /** * Set book Generator. * * The generator is a meta tag added to the ncx file, it is not visible * from within the book, but is a kind of electronic watermark. * * @param String $generator */ function setGenerator($generator) { if ($this->isFinalized) { return; } $this->generator = $generator; } /** * Get the book relation. * * @return String The generator identity string. */ function getGenerator() { return $this->generator; } /** * Set ePub date formate to the short yyyy-mm-dd form, for compliance with * a bug in EpubCheck, prior to its version 1.1. * * The latest version of ePubCheck can be obtained here: * http://code.google.com/p/epubcheck/ * * @access public * @return bool $success */ function setShortDateFormat() { if ($this->isFinalized) { return FALSE; } $this->dateformat = $this->dateformatShort; return TRUE; } /** * @Deprecated */ function setIgnoreEmptyBuffer($ignoreEmptyBuffer = TRUE) { return TRUE; } /** * Get Book status. * * @access public * @return boolean */ function isFinalized() { return $this->isFinalized; } /** * Check for mandatory parameters and finalize the e-book. * Once finalized, the book is locked for further additions. * * @return bool $success */ function finalize() { if ($this->isFinalized || $this->chapterCount == 0 || empty($this->title) || empty($this->language)) { return FALSE; } if (empty($this->identifier) || empty($this->identifierType)) { $this->setIdentifier($this->createUUID(4), EPub::IDENTIFIER_UUID); } if ($this->date == 0) { $this->date = time(); } if(empty($this->sourceURL)) { $this->sourceURL = $this->getCurrentPageURL(); } if(empty($this->publisherURL)) { $this->sourceURL = $this->getCurrentServerURL(); } // Generate OPF data: $this->opf = "\n\n\t\n\t\t" . $this->title . "\n\t\t" . $this->language . "\n\t\tidentifierType . "\">" . $this->identifier . "\n"; if (!empty($this->description)) { $this->opf .= "\t\t" . $this->description . "\n"; } if (!empty($this->publisherName)) { $this->opf .= "\t\t" . $this->publisherName . "\n"; } if (!empty($this->publisherURL)) { $this->opf .= "\t\t" . $this->publisherURL . "\n"; } if (!empty($this->author)) { $this->opf .= "\t\tauthorSortKey)) { $this->opf .= " opf:file-as=\"" . $this->authorSortKey . "\""; } $this->opf .= " opf:role=\"aut\">" . $this->author . "\n"; } $this->opf .= "\t\t" . gmdate($this->dateformat, $this->date) . "\n"; if (!empty($this->rights)) { $this->opf .= "\t\t" . $this->rights . "\n"; } if(!empty($this->subject)) { $this->opf .= "\t\t" . $this->subject . "\n"; } if(!empty($this->coverage)) { $this->opf .= "\t\t" . $this->coverage . "\n"; } if (!empty($this->sourceURL)) { $this->opf .= "\t\t" . $this->sourceURL . "\n"; } if(!empty($this->relation)) { $this->opf .= "\t\t" . $this->relation . "\n"; } if ($this->isCoverImageSet) { $this->opf .= "\t\t\n"; } if ($this->EPubMark) { $this->ncx .= "\t\t\n"; } if (!empty($this->generator)) { $this->ncx .= "\t\tgenerator . "\" />\n"; } $this->opf .= "\t\n\n\t\n" . $this->opf_manifest . "\t\n\n\t\n" . $this->opf_spine . "\t\n"; if (!empty($this->opf_guide)) { $this->opf .= "\n\t\n" . $this->opf_guide . "\t\n"; } $this->opf .= "\n"; $this->ncx = "\n\n\n\t\n" . "\t\tidentifier . "\" />\n\t\t\n\t\t\n\t\t\n"; if ($this->EPubMark) { $this->ncx .= "\t\t\n"; } if (!empty($this->generator)) { $this->ncx .= "\t\tgenerator . "\" />\n"; } $this->ncx .= "\t\n\n\t\n\t\t" . $this->title . "\n\t\n\n"; if (!empty($this->author)) { $this->ncx .= "\t\n\t\t" . $this->author . "\n\t\n\n"; } $this->ncx .= "\t\n" . $this->ncx_navmap . "\t\n\n"; $this->zip->addFile($this->opf, "book.opf"); $this->zip->addFile($this->ncx, "book.ncx"); $this->opf = ""; $this->ncx = ""; $this->isFinalized = TRUE; return TRUE; } /** * Return the finalized book. * * @return String with the book in binary form. */ function getBook() { if(!$this->isFinalized) { $this->finalize(); } return $this->zip->getZipData(); } /** * Return the finalized book. * * @return String */ function getBookSize() { if(!$this->isFinalized) { $this->finalize(); } return $this->zip->getArchiveSize(); } /** * Send the book as a zip download * * Sending will fail if the output buffer is in use. You can override this limit by * calling setIgnoreEmptyBuffer(TRUE), though the function will still fail if that * buffer is not empty. * * @param String $fileName The name of the book without the .epub at the end. * @return bool $success */ function sendBook($fileName) { if(!$this->isFinalized) { $this->finalize(); } if (stripos(strrev($fileName), "bupe.") !== 0) { $fileName .= ".epub"; } return $this->zip->sendZip($fileName, "application/epub+zip"); } /** * Generates an UUID. * * Default version (4) will generate a random UUID, version 3 will URL based UUID. * * Added for convinience * * @param $version UUID version to retrieve, See lib.uuid.manual.html for details. * @return string The formatted uuid */ function createUUID($version = 4, $url = NULL) { include_once("lib.uuid.php"); return UUID::mint($version, $url, UUID::nsURL); } /** * Get the url of the current page. * Example use: Default Source URL * * $return Page URL as a string. */ function getCurrentPageURL() { return null; $pageURL = 'http'; if ($_SERVER["HTTPS"] == "on") { $pageURL .= "s"; } $pageURL .= "://" . $_SERVER["SERVER_NAME"]; if ($_SERVER["SERVER_PORT"] != "80") { $pageURL .= ":" . $_SERVER["SERVER_PORT"]; } $pageURL .= $_SERVER["REQUEST_URI"]; return $pageURL; } /** * Get the url of the server. * Example use: Default Publisher URL * * $return Server URL as a string. */ function getCurrentServerURL() { return null; $serverURL = 'http'; if ($_SERVER["HTTPS"] == "on") { $serverURL .= "s"; } $serverURL .= "://" . $_SERVER["SERVER_NAME"]; if ($_SERVER["SERVER_PORT"] != "80") { $serverURL .= ":" . $_SERVER["SERVER_PORT"]; } return $serverURL . '/'; } /** * Get an image from a file or url, return it resized if the image exceeds the $maxImageWidth or $maxImageHeight directives. * * The return value is an array. * ['width'] is the width of the image. * ['height'] is the height of the image. * ['mime'] is the mime type of the image. Resized images are always in jpeg format. * ['image'] is the image data. * * @param String $source path or url to file. * $return array */ function getImage($source) { list($width, $height, $type, $attr) = getimagesize($source); $mime = image_type_to_mime_type($type); if ($width == 0 || $height == 0) { return FALSE; } @$image = file_get_contents($source); if ($image === FALSE) { return FALSE; } $ratio = 1; if ($this->isGdInstalled) { if ($width > $this->maxImageWidth) { $ratio = $this->maxImageWidth/$width; } if ($height*$ratio > $this->maxImageHeight) { $ratio = $this->maxImageHeight/$height; } if ($ratio < 1) { $image_o = imagecreatefromstring($image); $image_p = imagecreatetruecolor($width*$ratio, $height*$ratio); imagecopyresampled($image_p, $image_o, 0, 0, 0, 0, ($width*$ratio), ($height*$ratio), $width, $height); ob_start(); imagejpeg($image_p,NULL,80); $image = ob_get_contents(); ob_end_clean(); imagedestroy($image_o); imagedestroy($image_p); $mime = "image/jpeg"; } } $rv = array(); $rv['width'] = $width*$ratio; $rv['height'] = $height*$ratio; $rv['mime'] = $mime; $rv['image'] = $image; return $rv; } /** * Helper function to create a DOM fragment with given markup. * * @author Adam Schmalhofer * * @param DOMDocument $dom * @param String $markup * @return DOMNode fragment in a node. */ protected function createDomFragment($dom, $markup) { $node = $dom->createDocumentFragment(); $node->appendXML($markup); return $node; } /** * Retrieve an array of file names currently added to the book. * $key is the filename used in the book * $value is the original filename, will be the same as $key for most entries * * @return array file list */ function getFileList() { return $this->fileList; } /** * Clean up a path * If the path starts with a "/", it is deemed absolute and any /../ in the beginning is stripped off. * The returned path will not end in a "/". * * @param String $relPath The path to clean up * @return String the clean path * @deprecated Redundant, please use Zip::getRelativePath($relPath) instead. */ function relPath($relPath) { return Zip::getRelativePath($relPath); } /** * Set default chapter target size. * Default is 250000 bytes, and minimum is 10240 bytes. * * @param $size * @return void */ function setSplitSize($size) { $this->splitDefaultSize = (int)$size; if ($size < 10240) { $this->splitDefaultSize = 10240; // Making the file smaller than 10k is not a good idea. } } /** * Get the chapter target size. * * @return $size */ function getSplitSize() { return $this->splitDefaultSize; } } ?>