File indexing completed on 2024-12-22 05:33:15

0001 <?php
0002 
0003 /**
0004  * ePub Reader class
0005  *
0006  * @package       CodeIgniter
0007  * @subpackage    Libraries
0008  * @author        Tristan Siebers
0009  * @link          n/a
0010  * @license       LGPL
0011  * @version       0.1.0
0012  */
0013 class EPubReader
0014 {
0015     /**
0016      * Contains the path to the dir with the ePub files
0017      *
0018      * @var string Path to the extracted ePub files
0019      */
0020     var $ebookDir;
0021     /**
0022      * Holds the (relative to $ebookDir) path to the OPF file
0023      *
0024      * @var string Location + name of OPF file
0025      */
0026     var $opfFile;
0027     /**
0028      * Relative (to $ebookDir) OPF (ePub files) dir
0029      *
0030      * @var type Files dir
0031      */
0032     var $opfDir;
0033     /**
0034      * Holds all the found DC elements in the OPF file
0035      *
0036      * @var array All found DC elements in the OPF file
0037      */
0038     var $dcElements;
0039     /**
0040      * Holds all the manifest items of the OPF file
0041      *
0042      * @var array All manifest items
0043      */
0044     var $manifest;
0045     /**
0046      * Holds all the spin data
0047      *
0048      * @var array Spine data
0049      */
0050     var $spine;
0051     /**
0052      * Holds the ToC data
0053      *
0054      * @var array Array with ToC items
0055      */
0056     var $toc;
0057 
0058     public function init($ebookDir)
0059     {
0060         $this->ebookDir = $ebookDir;
0061 
0062         $this->_getOPF();
0063         $this->_getDcData();
0064         $this->_getManifest();
0065         $this->_getSpine();
0066         $this->_getTOC();
0067 
0068         //$this->debug();
0069     }
0070 
0071     /**
0072      * Get the path to the OPF file from the META-INF/container.xml file
0073      *
0074      * @return string Relative path to the OPF file
0075      */
0076     private function _getOPF()
0077     {
0078         $opfContents = simplexml_load_file($this->ebookDir . '/META-INF/container.xml');
0079         $opfAttributes = $opfContents->rootfiles->rootfile->attributes();
0080 
0081         foreach ($opfAttributes as $key => $value) {
0082             if ($key == "full-path") {
0083                 $this->opfFile = (string)$value;
0084             }
0085         }
0086 
0087         //$this->opfFile = (string) $opfAttributes[0]; // Typecasting to string to get rid of the XML object
0088 
0089         // Set also the dir to the OPF (and ePub files)
0090         $opfDirParts = explode('/', $this->opfFile);
0091         unset($opfDirParts[(count($opfDirParts) - 1)]); // remove the last part (it's the .opf file itself)
0092         $this->opfDir = implode('/', $opfDirParts);
0093 
0094         return $this->opfFile;
0095     }
0096 
0097     /**
0098      * Read the metadata DC details (title, author, etc.) from the OPF file
0099      */
0100     private function _getDcData()
0101     {
0102         $opfContents = simplexml_load_file($this->ebookDir . '/' . $this->opfFile);
0103         $this->dcElements = (array)$opfContents->metadata->children('dc', true);
0104     }
0105 
0106     /**
0107      * Gets the manifest data from the OPF file
0108      */
0109     private function _getManifest()
0110     {
0111         $opfContents = simplexml_load_file($this->ebookDir . '/' . $this->opfFile);
0112         $iManifest = 0;
0113         foreach ($opfContents->manifest->item as $item) {
0114             $attr = $item->attributes();
0115             $id = (string)$attr->id;
0116             $this->manifest[$id]['href'] = (string)$attr->href;
0117             $this->manifest[$id]['media-type'] = (string)$attr->{'media-type'};
0118             $iManifest++;
0119         }
0120     }
0121 
0122     /**
0123      * Get the spine data from the OPF file
0124      */
0125     private function _getSpine()
0126     {
0127         $opfContents = simplexml_load_file($this->ebookDir . '/' . $this->opfFile);
0128         foreach ($opfContents->spine->itemref as $item) {
0129             $attr = $item->attributes();
0130             $this->spine[] = (string)$attr->idref;
0131         }
0132     }
0133 
0134     /**
0135      * Build an array with the TOC
0136      */
0137     private function _getTOC()
0138     {
0139         $tocFile = $this->getManifest('ncx');
0140         $tocContents = @simplexml_load_file($this->ebookDir . '/' . $this->opfDir . '/' . $tocFile['href']);
0141         if (!$tocContents) {
0142             return false;
0143         }
0144 
0145         $toc = array();
0146         foreach ($tocContents->navMap->navPoint as $navPoint) {
0147             $toc = $this->_process_navPoint($toc, $navPoint);
0148         }
0149 
0150         $this->toc = $toc;
0151     }
0152 
0153     /**
0154      * Get the specified manifest item
0155      *
0156      * @param string $item The manifest ID
0157      *
0158      * @return string/boolean String when manifest item exists, otherwise false
0159      */
0160     public function getManifest($item)
0161     {
0162         if (key_exists($item, $this->manifest)) {
0163             return $this->manifest[$item];
0164         } else {
0165             return false;
0166         }
0167     }
0168     // Private functions
0169 
0170     private function _process_navPoint($toc, $navPoint)
0171     {
0172         $navPointData = $navPoint->attributes();
0173         $toc[(string)$navPointData['playOrder']]['id'] = (string)$navPointData['id'];
0174         $toc[(string)$navPointData['playOrder']]['name'] = (string)$navPoint->navLabel->text;
0175         $toc[(string)$navPointData['playOrder']]['src'] = (string)$navPoint->content->attributes();
0176 
0177         if ($navPoint->navPoint) {  // If there are more navPoints within the current one
0178             foreach ($navPoint->navPoint as $nested_navPoint) {  // Process them too
0179                 $toc = $this->_process_navPoint($toc, $nested_navPoint);
0180             }
0181         }
0182 
0183         return $toc;
0184     }
0185 
0186     /**
0187      * Get the specified DC item
0188      *
0189      * @param string $item The DC Item key
0190      *
0191      * @return string/boolean String when DC item exists, otherwise false
0192      */
0193     public function getDcItem($item)
0194     {
0195         if (key_exists($item, $this->dcElements)) {
0196             return $this->dcElements[$item];
0197         } else {
0198             return false;
0199         }
0200     }
0201 
0202     /**
0203      * Get the specified manifest by type
0204      *
0205      * @param string $type The manifest type
0206      *
0207      * @return string/boolean String when manifest item exists, otherwise false
0208      */
0209     public function getManifestByType($type)
0210     {
0211         foreach ($this->manifest as $manifestID => $manifest) {
0212             if ($manifest['media-type'] == $type) {
0213                 $return[$manifestID]['href'] = $manifest['href'];
0214                 $return[$manifestID]['media-type'] = $manifest['media-type'];
0215             }
0216         }
0217 
0218         return (count($return) == 0) ? false : $return;
0219     }
0220 
0221     /**
0222      * Retrieve the ToC
0223      *
0224      * @return array Array with ToC Data
0225      */
0226     public function getTOC()
0227     {
0228         return $this->toc;
0229     }
0230 
0231 
0232     /**
0233      * Build an array with the TOC
0234      *
0235      * private function _getTOC() {
0236      * $tocFile = $this->getManifest('ncx');
0237      * $tocContents = simplexml_load_file($this->ebookDir.'/'.$this->opfDir.'/'.$tocFile['href']);
0238      *
0239      * $toc = array();
0240      * foreach($tocContents->navMap->navPoint AS $navPoint) {
0241      * $navPointData = $navPoint->attributes();
0242      * $toc[(string)$navPointData['playOrder']]['id'] = (string)$navPointData['id'];
0243      * $toc[(string)$navPointData['playOrder']]['naam'] = (string)$navPoint->navLabel->text;
0244      * $toc[(string)$navPointData['playOrder']]['src'] = (string)$navPoint->content->attributes();
0245      * }
0246      *
0247      * $this->toc = $toc;
0248      * }
0249      */
0250 
0251     /**
0252      * Returns the OPF/Data dir
0253      *
0254      * @return string The OPF/data dir
0255      */
0256     public function getOPFDir()
0257     {
0258         return $this->opfDir;
0259     }
0260 
0261     /*
0262      * Recursive function to get all navPoints, which may be nested
0263      */
0264 
0265     /**
0266      * Prints all contents of the class directly to the screen
0267      */
0268     public function debug()
0269     {
0270         echo sprintf('<pre>%s</pre>', print_r($this, true));
0271     }
0272 }