1<?php 2/** 3 * DokuWiki Plugin ebookexport (Action Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Nomen Nescio <info@nomennesc.io> 7 */ 8 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12class action_plugin_ebookexport extends DokuWiki_Action_Plugin { 13 14 /** 15 * Registers a callback function for a given event 16 * 17 * @param Doku_Event_Handler $controller DokuWiki's event controller object 18 * @return void 19 */ 20 public function register(Doku_Event_Handler $controller) { 21 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'exportepub', array()); 22 $controller->register_hook('TEMPLATE_PAGETOOLS_DISPLAY', 'BEFORE', $this, 'addepubbutton', array()); 23 } 24 25 public function exportepub(Doku_Event $event) { 26 global $ACT; 27 global $ID; 28 global $conf; 29 30 // our event? 31 if($ACT != 'export_epub') return false; 32 33 // check user's rights 34 if(auth_quickaclcheck($ID) < AUTH_READ) return false; 35 36 // it's ours, no one else's 37 $event->preventDefault(); 38 39 $tempdir=tempnam(sys_get_temp_dir(),''); 40 if (file_exists($tempdir)) { unlink($tempdir); } 41 mkdir($tempdir); 42 43 require_once DOKU_INC . 'inc/parser/parser.php'; 44 45 $mypage = pageinfo(); 46 $mypath = $mypage["filepath"]; 47 $doc = file_get_contents($mypath); 48 49 $instructions = p_get_instructions($doc); 50 require_once DOKU_INC . 'inc/parser/xhtml.php'; 51 $Renderer = new Doku_Renderer_XHTML(); 52 foreach ( $instructions as $instruction ) { 53 call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]); 54 } 55 56 $tocarray = $Renderer->toc; 57 $pages = $Renderer->doc; 58 59 if(isset($conf['baseurl']) && ($conf['baseurl'] != '')){ 60 $url = $conf['baseurl'] . '/'; 61 } 62 else{ 63 $self = parse_url(DOKU_URL); 64 $url = $self['scheme'] . '://' . $self['host']; 65 if($self['port']) { 66 $url .= ':' . $self['port']; 67 } 68 $url .= '/'; 69 } 70 $pages = preg_replace('/href="\//',"href=\"$url",$pages); 71 72 file_put_contents($tempdir . "/pages.xhtml",$pages); 73 74 $mimetype = "application/epub+zip"; 75 file_put_contents($tempdir . "/mimetype",$mimetype); 76 77 $pagestyle = "@page {\nmargin-bottom: 5pt;\nmargin-top: 5pt;\n}\n"; 78 file_put_contents($tempdir . "/page_styles.css",$pagestyle); 79 80 $stylesheet = "h2 {\nfont-size: large;\n}\n"; 81 file_put_contents($tempdir . "/stylesheet.css",$stylesheet); 82 83 mkdir($tempdir . "/META-INF"); 84 85 $container = '<?xml version="1.0"?><container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container"><rootfiles><rootfile full-path="content.opf" media-type="application/oebps-package+xml"/></rootfiles></container>'; 86 file_put_contents($tempdir . "/META-INF/container.xml", $container); 87 88 if(isset($mypage["meta"]["title"])){ 89 $mytitle = $mypage["meta"]["title"]; 90 } else{ 91 $mytitle = preg_replace('/^.*:/','',$ID); 92 $mytitle = ucwords(preg_replace('/_/',' ',$mytitle)); 93 } 94 95 $epubuuid = preg_replace('/^(........)(....)(....)(....)(............).*/','${1}-${2}-${3}-${4}-${5}',md5($conf['title'] . $mytitle . $mypage['lastmod'])); 96 $files = array('content.opf','mimetype','page_styles.css','pages.xhtml','stylesheet.css','titlepage.xhtml','toc.ncx','META-INF/container.xml'); 97 98 $content = "<?xml version='1.0' encoding='utf-8'?>"; 99 $content .= '<package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="uuid_id">'; 100 $content .= '<metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:opf="http://www.idpf.org/2007/opf" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:calibre="http://calibre.kovidgoyal.net/2009/metadata" xmlns:dc="http://purl.org/dc/elements/1.1/">'; 101 $content .= '<dc:language>en</dc:language>'; 102 $content .= '<dc:title>' . $mytitle . '</dc:title>'; 103 $content .= '<dc:creator opf:file-as="' . $conf['title'] . '" opf:role="aut">' . $conf['title'] . '</dc:creator>'; 104 $content .= '<meta name="cover" content="cover"/>'; 105 $content .= '<dc:date>' . date("Y-m-d\TH:i:s:P",$mypage['lastmod']) . '</dc:date>'; 106 $content .= '<dc:contributor opf:role="bkp"></dc:contributor>'; 107 $content .= '<dc:identifier id="uuid_id" opf:scheme="uuid">' . $epubuuid . '</dc:identifier>'; 108 $content .= '</metadata>'; 109 $content .= '<manifest>'; 110 if(isset($mypage["meta"]["relation"]["media"])){ 111 foreach($mypage["meta"]["relation"]["media"] as $mediaitem => $whatever){ 112 $mediafile = mediaFN($mediaitem); 113 $mediamime = mime_content_type($mediafile); 114 $medialink = ml($mediaitem); 115 $mediadir = dirname($medialink); 116 if(!is_dir($tempdir . $mediadir)) 117 mkdir($tempdir . $mediadir, 0777, true); 118 copy($mediafile,$tempdir . $medialink); 119 array_push($files,substr($medialink,1)); 120 $content .= '<item href="' . $medialink . '" id="' . $mediaitem . '" media-type="' . $mediamime . '"/>'; 121 } 122 } 123 $content .= '<item href="pages.xhtml" id="id1" media-type="application/xhtml+xml"/>'; 124 $content .= '<item href="page_styles.css" id="page_css" media-type="text/css"/>'; 125 $content .= '<item href="stylesheet.css" id="css" media-type="text/css"/>'; 126 $content .= '<item href="titlepage.xhtml" id="titlepage" media-type="application/xhtml+xml"/>'; 127 $content .= '<item href="toc.ncx" media-type="application/x-dtbncx+xml" id="ncx"/>'; 128 $content .= '</manifest>'; 129 $content .= '<spine toc="ncx">'; 130 $content .= '<itemref idref="titlepage"/>'; 131 $content .= '<itemref idref="id1"/>'; 132 $content .= '</spine>'; 133 $content .= '<guide>'; 134 $content .= '<reference href="titlepage.xhtml" type="cover" title="Cover"/>'; 135 $content .= '</guide></package>'; 136 file_put_contents($tempdir . "/content.opf",$content); 137 138 $titlepage = "<?xml version='1.0' encoding='utf-8'?>"; 139 $titlepage .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'; 140 $titlepage .= '<head>'; 141 $titlepage .= '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>'; 142 $titlepage .= '<title>Cover</title>'; 143 $titlepage .= '<style type="text/css" title="override_css">'; 144 $titlepage .= '@page {padding: 0pt; margin:0pt}'; 145 $titlepage .= 'body { text-align: center; padding:0pt; margin: 0pt; }'; 146 $titlepage .= '</style>'; 147 $titlepage .= '</head>'; 148 $titlepage .= '<body>'; 149 $titlepage .= '<div>'; 150 $titlepage .= '<h1>' . $mytitle . '</h1>'; 151 $titlepage .= '<h2>' . $conf['title'] . '</h2>'; 152 $titlepage .= '</div>'; 153 $titlepage .= '</body></html>'; 154 file_put_contents($tempdir . "/titlepage.xhtml",$titlepage); 155 156 $toc = "<?xml version='1.0' encoding='utf-8'?>"; 157 $toc .= '<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1" xml:lang="eng">'; 158 $toc .= '<head>'; 159 $toc .= '<meta content="0c159d12-f5fe-4323-8194-f5c652b89f5c" name="dtb:uid"/>'; 160 $toc .= '<meta content="2" name="dtb:depth"/>'; 161 $toc .= '<meta content="calibre (0.8.68)" name="dtb:generator"/>'; 162 $toc .= '<meta content="0" name="dtb:totalPageCount"/>'; 163 $toc .= '<meta content="0" name="dtb:maxPageNumber"/>'; 164 $toc .= '</head>'; 165 $toc .= '<docTitle>'; 166 $toc .= '<text>Titel</text>'; 167 $toc .= '</docTitle>'; 168 $toc .= '<navMap>'; 169 for($i=0;$i<sizeof($tocarray);$i++){ 170 $toc .= '<navPoint id="' . substr($tocarray[$i]["link"],1) . '" playOrder="' . $i . '">'; 171 $toc .= '<navLabel><text>' . $tocarray[$i]["title"] . '</text>'; 172 $toc .= '</navLabel><content src="pages.xhtml' . $tocarray[$i]["link"] . '"/>'; 173 $toc .= '</navPoint>'; 174 } 175 $toc .= '</navMap></ncx>'; 176 file_put_contents($tempdir . "/toc.ncx",$toc); 177 178 $zip = new ZipArchive(); 179 $zipfile = $tempdir . "/" . $ID . ".epub"; 180 $zip->open($zipfile,ZipArchive::CREATE); 181 foreach($files as $file){ 182 $zip->addFile($tempdir . "/" . $file,$file); 183 } 184 $zip->close(); 185 186 header('Content-Type: application/epub+zip'); 187 header('Cache-Control: must-revalidate, no-cache'); 188 header('Pragma: no-cache'); 189 190 $filename = preg_replace('/ /','_',$mytitle) . ".epub"; 191 header('Content-Disposition: attachment; filename="' . $filename . '";'); 192 193 //Bookcreator uses jQuery.fileDownload.js, which requires a cookie. 194 header('Set-Cookie: fileDownload=true; path=/'); 195 196 $fp = @fopen($zipfile, "rb"); 197 if($fp) { 198 $size = filesize($zipfile); 199 header('Accept-Ranges: bytes'); 200 header("Content-Length: $size"); 201 fseek($fp,0); 202 $chunk = ($size > HTTP_CHUNK_SIZE) ? HTTP_CHUNK_SIZE : $size; 203 while (!feof($fp) && $chunk > 0) { 204 @set_time_limit(30); 205 print fread($fp, $chunk); 206 flush(); 207 $size -= $chunk; 208 $chunk = ($size > HTTP_CHUNK_SIZE) ? HTTP_CHUNK_SIZE : $size; 209 } 210 } else { 211 header("HTTP/1.0 500 Internal Server Error"); 212 print "Could not read file - bad permissions?"; 213 $ranges[] = array(0,$size,$size); 214 } 215 $this->rrmdir($tempdir); 216 exit; 217 } 218 219 private function rrmdir($dir) { 220 if (is_dir($dir)) { 221 $objects = scandir($dir); 222 foreach ($objects as $object) { 223 if ($object != "." && $object != "..") { 224 if (is_dir($dir."/".$object)) 225 $this->rrmdir($dir."/".$object); 226 else 227 unlink($dir."/".$object); 228 } 229 } 230 rmdir($dir); 231 } 232 } 233 234 public function addepubbutton(Doku_Event $event) { 235 global $ID, $REV; 236 237 if($event->data['view'] == 'main') { 238 $params = array('do' => 'export_epub'); 239 if($REV) { 240 $params['rev'] = $REV; 241 } 242 243 // insert button at position before last (up to top) 244 $event->data['items'] = array_slice($event->data['items'], 0, -1, true) + 245 array('export_epub' => 246 '<li>' 247 . '<a href="' . wl($ID, $params) . '" class="action export_epub" rel="nofollow" title="Export to EPUB">' 248 . '<span>Export to EPUB</span>' 249 . '</a>' 250 . '</li>' 251 ) + 252 array_slice($event->data['items'], -1, 1, true); 253 } 254 } 255} 256 257// vim:ts=4:sw=4:et: 258