1<?php 2/** 3 * Utilities for collecting data from config files 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Harry Fuecks <hfuecks@gmail.com> 7 * @author Andreas Gohr <andi@splitbrain.org> 8 */ 9 10 if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../').'/'); 11 12 require_once(DOKU_INC.'inc/confutils.php'); 13 require_once(DOKU_INC.'inc/pageutils.php'); 14 require_once(DOKU_INC.'inc/pluginutils.php'); 15 16/** 17 * Returns the parsed Wikitext in XHTML for the given id and revision. 18 * 19 * If $excuse is true an explanation is returned if the file 20 * wasn't found 21 * 22 * @author Andreas Gohr <andi@splitbrain.org> 23 */ 24function p_wiki_xhtml($id, $rev='', $excuse=true){ 25 $file = wikiFN($id,$rev); 26 $ret = ''; 27 28 //ensure $id is in global $ID (needed for parsing) 29 global $ID; 30 $ID = $id; 31 32 if($rev){ 33 if(@file_exists($file)){ 34 $ret = p_render('xhtml',p_get_instructions(io_readfile($file)),$info); //no caching on old revisions 35 }elseif($excuse){ 36 $ret = p_locale_xhtml('norev'); 37 } 38 }else{ 39 if(@file_exists($file)){ 40 $ret = p_cached_xhtml($file); 41 }elseif($excuse){ 42 $ret = p_locale_xhtml('newpage'); 43 } 44 } 45 46 return $ret; 47} 48 49/** 50 * Returns the specified local text in parsed format 51 * 52 * @author Andreas Gohr <andi@splitbrain.org> 53 */ 54function p_locale_xhtml($id){ 55 //fetch parsed locale 56 $html = p_cached_xhtml(localeFN($id)); 57 return $html; 58} 59 60/** 61 * Returns the given file parsed to XHTML 62 * 63 * Uses and creates a cachefile 64 * 65 * @author Andreas Gohr <andi@splitbrain.org> 66 * @todo rewrite to use mode instead of hardcoded XHTML 67 */ 68function p_cached_xhtml($file){ 69 global $conf; 70 $cache = $conf['datadir'].'/_cache/xhtml/'; 71 $cache .= md5($file.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT']); 72 $purge = $conf['datadir'].'/_cache/purgefile'; 73 74 // check if cache can be used 75 $cachetime = @filemtime($cache); // 0 if not exists 76 77 if( @file_exists($file) // does the source exist 78 && $cachetime > @filemtime($file) // cache is fresh 79 && ((time() - $cachetime) < $conf['cachetime']) // and is cachefile young enough 80 && !isset($_REQUEST['purge']) // no purge param was set 81 && ($cachetime > @filemtime($purge)) // and newer than the purgefile 82 && ($cachetime > @filemtime(DOKU_INC.'conf/dokuwiki.php')) // newer than the config file 83 && ($cachetime > @filemtime(DOKU_INC.'conf/local.php')) // newer than the local config file 84 && ($cachetime > @filemtime(DOKU_INC.'inc/parser/xhtml.php')) // newer than the renderer 85 && ($cachetime > @filemtime(DOKU_INC.'inc/parser/parser.php')) // newer than the parser 86 && ($cachetime > @filemtime(DOKU_INC.'inc/parser/handler.php')))// newer than the handler 87 { 88 //well then use the cache 89 $parsed = io_readfile($cache); 90 $parsed .= "\n<!-- cachefile $cache used -->\n"; 91 }else{ 92 $parsed = p_render('xhtml', p_cached_instructions($file),$info); //try to use cached instructions 93 94 if($info['cache']){ 95 io_saveFile($cache,$parsed); //save cachefile 96 $parsed .= "\n<!-- no cachefile used, but created -->\n"; 97 }else{ 98 @unlink($cache); //try to delete cachefile 99 $parsed .= "\n<!-- no cachefile used, caching forbidden -->\n"; 100 } 101 } 102 103 return $parsed; 104} 105 106/** 107 * Returns the render instructions for a file 108 * 109 * Uses and creates a serialized cache file 110 * 111 * @author Andreas Gohr <andi@splitbrain.org> 112 */ 113function p_cached_instructions($file,$cacheonly=false){ 114 global $conf; 115 $cache = $conf['datadir'].'/_cache/instructions/'; 116 $cache .= md5($file.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT']); 117 118 // check if cache can be used 119 $cachetime = @filemtime($cache); // 0 if not exists 120 121 // cache forced? 122 if($cacheonly){ 123 if($cachetime){ 124 return unserialize(io_readfile($cache)); 125 }else{ 126 return array(); 127 } 128 } 129 130 if( @file_exists($file) // does the source exist 131 && $cachetime > @filemtime($file) // cache is fresh 132 && !isset($_REQUEST['purge']) // no purge param was set 133 && ($cachetime > @filemtime(DOKU_INC.'conf/dokuwiki.php')) // newer than the config file 134 && ($cachetime > @filemtime(DOKU_INC.'conf/local.php')) // newer than the local config file 135 && ($cachetime > @filemtime(DOKU_INC.'inc/parser/parser.php')) // newer than the parser 136 && ($cachetime > @filemtime(DOKU_INC.'inc/parser/handler.php')))// newer than the handler 137 { 138 //well then use the cache 139 return unserialize(io_readfile($cache)); 140 }elseif(@file_exists($file)){ 141 // no cache - do some work 142 $ins = p_get_instructions(io_readfile($file)); 143 io_savefile($cache,serialize($ins)); 144 return $ins; 145 } 146 147 return NULL; 148} 149 150/** 151 * turns a page into a list of instructions 152 * 153 * @author Harry Fuecks <hfuecks@gmail.com> 154 * @author Andreas Gohr <andi@splitbrain.org> 155 */ 156function p_get_instructions($text){ 157 158 $modes = p_get_parsermodes(); 159 160 // Create the parser 161 $Parser = & new Doku_Parser(); 162 163 // Add the Handler 164 $Parser->Handler = & new Doku_Handler(); 165 166 //add modes to parser 167 foreach($modes as $mode){ 168 $Parser->addMode($mode['mode'],$mode['obj']); 169 } 170 171 // Do the parsing 172 $p = $Parser->parse($text); 173// dbg($p); 174 return $p; 175} 176 177/** 178 * returns all available parser syntax modes in correct order 179 * 180 * @author Andreas Gohr <andi@splitbrain.org> 181 */ 182function p_get_parsermodes(){ 183 global $conf; 184 185 //reuse old data 186 static $modes = null; 187 if($modes != null){ 188 return $modes; 189 } 190 191 //import parser classes and mode definitions 192 require_once DOKU_INC . 'inc/parser/parser.php'; 193 194 // we now collect all syntax modes and their objects, then they will 195 // be sorted and added to the parser in correct order 196 $modes = array(); 197 198 // add syntax plugins 199 $pluginlist = plugin_list('syntax'); 200 if(count($pluginlist)){ 201 global $PARSER_MODES; 202 $obj = null; 203 foreach($pluginlist as $p){ 204 plugin_load('syntax',$p,$obj); //load plugin into $obj 205 $PARSER_MODES[$obj->getType()][] = "plugin_$p"; //register mode type 206 //add to modes 207 $modes[] = array( 208 'sort' => $obj->getSort(), 209 'mode' => "plugin_$p", 210 'obj' => $obj, 211 ); 212 } 213 } 214 215 // add default modes 216 $std_modes = array('listblock','preformatted','notoc','nocache', 217 'header','table','linebreak','footnote','hr', 218 'unformatted','php','html','code','file','quote', 219 'multiplyentity','quotes','internallink','rss', 220 'media','externallink','emaillink','windowssharelink', 221 'eol'); 222 foreach($std_modes as $m){ 223 $class = "Doku_Parser_Mode_$m"; 224 $obj = new $class(); 225 $modes[] = array( 226 'sort' => $obj->getSort(), 227 'mode' => $m, 228 'obj' => $obj 229 ); 230 } 231 232 // add formatting modes 233 $fmt_modes = array('strong','emphasis','underline','monospace', 234 'subscript','superscript','deleted'); 235 foreach($fmt_modes as $m){ 236 $obj = new Doku_Parser_Mode_formatting($m); 237 $modes[] = array( 238 'sort' => $obj->getSort(), 239 'mode' => $m, 240 'obj' => $obj 241 ); 242 } 243 244 // add modes which need files 245 $obj = new Doku_Parser_Mode_smiley(array_keys(getSmileys())); 246 $modes[] = array('sort' => $obj->getSort(), 'mode' => 'smiley','obj' => $obj ); 247 $obj = new Doku_Parser_Mode_acronym(array_keys(getAcronyms())); 248 $modes[] = array('sort' => $obj->getSort(), 'mode' => 'acronym','obj' => $obj ); 249 $obj = new Doku_Parser_Mode_entity(array_keys(getEntities())); 250 $modes[] = array('sort' => $obj->getSort(), 'mode' => 'entity','obj' => $obj ); 251 252 253 // add optional camelcase mode 254 if($conf['camelcase']){ 255 $obj = new Doku_Parser_Mode_camelcaselink(); 256 $modes[] = array('sort' => $obj->getSort(), 'mode' => 'camelcaselink','obj' => $obj ); 257 } 258 259 //sort modes 260 usort($modes,'p_sort_modes'); 261 262 return $modes; 263} 264 265/** 266 * Callback function for usort 267 * 268 * @author Andreas Gohr <andi@splitbrain.org> 269 */ 270function p_sort_modes($a, $b){ 271 if($a['sort'] == $b['sort']) return 0; 272 return ($a['sort'] < $b['sort']) ? -1 : 1; 273} 274 275/** 276 * Renders a list of instruction to the specified output mode 277 * 278 * In the $info array are informations from the renderer returned 279 * 280 * @author Harry Fuecks <hfuecks@gmail.com> 281 * @author Andreas Gohr <andi@splitbrain.org> 282 */ 283function p_render($mode,$instructions,& $info){ 284 if(is_null($instructions)) return ''; 285 286 // Create the renderer 287 if(!@file_exists(DOKU_INC."inc/parser/$mode.php")){ 288 msg("No renderer for $mode found",-1); 289 return null; 290 } 291 292 require_once DOKU_INC."inc/parser/$mode.php"; 293 $rclass = "Doku_Renderer_$mode"; 294 $Renderer = & new $rclass(); #FIXME any way to check for class existance? 295 296 $Renderer->smileys = getSmileys(); 297 $Renderer->entities = getEntities(); 298 $Renderer->acronyms = getAcronyms(); 299 $Renderer->interwiki = getInterwiki(); 300 #$Renderer->badwords = getBadWords(); 301 302 // Loop through the instructions 303 foreach ( $instructions as $instruction ) { 304 // Execute the callback against the Renderer 305 call_user_func_array(array(&$Renderer, $instruction[0]),$instruction[1]); 306 } 307 308 //set info array 309 $info = $Renderer->info; 310 311 // Return the output 312 return $Renderer->doc; 313} 314 315/** 316 * Gets the first heading from a file 317 * 318 * @author Jan Decaluwe <jan@jandecaluwe.com> 319 */ 320function p_get_first_heading($id){ 321 $file = wikiFN($id); 322 if (@file_exists($file)) { 323 $instructions = p_cached_instructions($file,true); 324 foreach ( $instructions as $instruction ) { 325 if ($instruction[0] == 'header') { 326 return $instruction[1][0]; 327 } 328 } 329 } 330 return NULL; 331} 332 333//Setup VIM: ex: et ts=2 enc=utf-8 : 334