1<?php 2/** 3* Plugin Chain: Execute a sys command and create output file in a current directory for a next chain command. 4* 5* @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6* @author Riccardo Pisanu <rkpisanu@yahoo.it> 7* based on the format plugin 8* 9* <chain alias=program_alias output=file_ouput render=[yes/no] > 10* text to feed into the program 11* </chain> 12* 13* program_alias is defined in conf/default.php similat to: 14* $conf['<program-name>']=array('name' => "<user name>", 15* '<mode>' => array('iext' => "<input extension>", 16 'oext' => "<output extension>", 17* 'pre' => "<pre>", 18* 'post' => "<post>", 19 'command_wintel' => "<wintel command line>" 20* 'command' => "<non wintel command line>" )); 21* 22* 23**/ 24 25// must be run within DokuWiki 26if(!defined('DOKU_INC')) die(); 27 28if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 29require_once DOKU_PLUGIN.'syntax.php'; 30 31 32/** 33* All DokuWiki plugins to extend the parser/rendering mechanism 34* need to inherit from this class 35*/ 36class syntax_plugin_chain extends DokuWiki_Syntax_Plugin 37 { 38 39 function getInfo() 40 { 41 return array('author' => 'Riccardo Pisanu', 42 'email' => 'rkpisanu@yahoo.it', 43 'date' => '2010-01-16', 44 'name' => 'Chain Plugin', 45 'desc' => 'Execute a sys command and create output file in a current directory for a next chain command.', 46 'url' => 'http://www.dokuwiki.org/plugin:chain'); 47 } 48 49 function getType() 50 { 51 return 'substition'; 52 } 53 54 function getSort() 55 { 56 return 32; 57 } 58 59 function connectTo($mode) 60 { 61 $this->Lexer->addEntryPattern('<chain(?=.*?>.*?</chain>)',$mode,'plugin_chain'); 62 } 63 64 function postConnect() 65 { 66 $this->Lexer->addExitPattern('</chain>','plugin_chain'); 67 } 68 69 function handle($match, $state, $pos, &$handler) 70 { 71 return array($match, $state, $pos); 72 } 73 74 function render($mode, &$renderer, $data) 75 { 76 //Query not have time limit 77 set_time_limit(0); 78 //No cache pages 79 $renderer->info['cache'] = false; 80 //Refer to global Dokuwiki vars to get directory configuration and namespace:page 81 global $conf; 82 global $ID; 83 //Only xhtml 84 if ($mode!='xhtml') return; 85 //Split data received from handle function 86 @list($match, $state, $pos) = $data; 87 switch ($state) 88 { 89 case DOKU_LEXER_ENTER: 90 break; 91 case DOKU_LEXER_UNMATCHED: 92 //** Split $match in Parameters $matches[0] and Text $matches[1] ** 93 $matches = preg_split('/>/u',$match,2); 94 $matches[0] = trim($matches[0]); 95 if ( trim($matches[0]) == '' ) 96 { 97 $matches[0] = NULL; 98 } 99 //** Parsing Parameters ** 100 preg_match('/alias=([a-zA-Z_0-9]+)/i', $matches[0], $match_alias); 101 preg_match('/output=([a-zA-Z_0-9]+)/i', $matches[0], $match_output); 102 preg_match('/render=([a-zA-Z_0-9]+)/i', $matches[0], $match_render); 103 preg_match('/delim=([a-zA-Z_0-9]+)/i', $matches[0], $match_delim); 104 preg_match('/debug=([a-zA-Z_0-9]+)/i', $matches[0], $match_debug); 105 //Manage Delimitator 106 switch (trim($match_delim[1])) 107 { 108 case 'tab' : $match_delim[1] = "\t"; break; 109 case 'mtab' : $match_delim[1] = "[ \t]+"; break; 110 case 'pipe' : $match_delim[1] = "\|"; break; 111 case 'scol' : $match_delim[1] = ";"; break; 112 default : $match_delim[1] = ","; 113 } 114 //** Begin Application Logic Plugin ** 115 //Get alias configuration array conf[$match_alias[1]] in conf/default.php and exit with error message if it not well configured 116 $config = $this->getConf($match_alias[1]); 117 if(!$config || !$config[$mode]) 118 { 119 //_xmlEntities encode html correctly 120 $renderer->doc .= $renderer->_xmlEntities($match_alias[1].' ** <chain alias=AliasName > not configured for '.$mode.' output in /lib/plugins/chain/default.php **'); 121 return true; 122 } 123 //Create/Verify Directory to store files 124 $ns_path = $ID; 125 $ns_path = str_replace(":","/",$ns_path); // Work out the namespace and page 126 $dirname = $conf['mediadir'].'/temp/chain'.$program.'/'.$ns_path; 127 //Set relative url_base for image path rendering 128 list($drive_path,$url_base) = split(DOKU_BASE,$dirname); 129 $url_base = DOKU_BASE.$url_base; 130 //If directory not exist then create it and grant permission with .htaccess 131 if(!is_dir($dirname)) 132 { 133 io_mkdir_p($dirname); //Using dokuwiki framework 134 } 135 //Output Filename 136 $OutFileName = $dirname.'/'.$match_output[1].'.'.$config[$mode]['oext']; 137 $RelFileName = $url_base.'/'.$match_output[1].'.'.$config[$mode]['oext']; 138 //Delete old OutFileName if exist 139 if (is_file($OutFileName)) unlink($OutFileName); 140 //Input Filename with contain all data wrapped pre + text + post 141 $InpFileName = $dirname.'/'.$match_output[1].'.'.$config[$mode]['iext']; 142 $NSPath = $dirname.'/'; 143 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') $NSPath=str_replace('/', '\\', $NSPath); 144 $pre = str_replace(array('@InputFile@','@OutputFile@','@Path@'), 145 array($InpFileName, $OutFileName, $NSPath), 146 $config[$mode]['pre']); 147 $post = str_replace(array('@InputFile@','@OutputFile@','@Path@'), 148 array($InpFileName, $OutFileName, $NSPath), 149 $config[$mode]['post']); 150 $text = str_replace(array('@InputFile@','@OutputFile@','@Path@'), 151 array($InpFileName, $OutFileName, $NSPath), 152 $matches[1]); 153 $wrappeddata = $pre.$text.$post; 154 //Save File Using Dokuwiki Framework 155 io_saveFile($InpFileName, $wrappeddata); 156 // Replace the variable strings 157 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') 158 { 159 //This is a command using Windows! 160 $command=str_replace(array('@InputFile@','@OutputFile@','@Path@'), 161 array($InpFileName, $OutFileName, $NSPath), 162 $config[$mode]['command_wintel']); 163 $command=str_replace('/', '\\', $command); 164 $command=str_replace('Program Files','progra~1', $command); 165 } 166 else 167 { 168 //This is a command not using Windows! 169 $command=str_replace(array('@InputFile@','@OutputFile@','@Path@'), 170 array($InpFileName, $OutFileName, $NSPath), 171 $config[$mode]['command']); 172 } 173 $output = shell_exec($command); 174 //** Trace vars for debug ** 175 if ( trim($match_debug[1]) == 'yes' ) 176 { 177 $DebProgs=1; 178 $this->DebugWindowsOpen(); 179 $this->DebugWindowsWrite("</table>\n<table border=1 >"); 180 $this->DebugWindowsWrite("<TH colspan=2 >CHAIN DEBUG CONSOLE"); 181 $this->DebugWindowsWrite("<TD colspan=2 > Begin Trace Chain Plugin: ".date('l jS \of F Y h:i:s A')); 182 $this->DebugWindowsWrite("<TD>".$DebProgs++.") ns_path =<TD>-->$ns_path"); 183 $this->DebugWindowsWrite("<TD>".$DebProgs++.") dirname =<TD>-->$dirname"); 184 $this->DebugWindowsWrite("<TD>".$DebProgs++.") DOKU_BASE =<TD>-->".DOKU_BASE); 185 $this->DebugWindowsWrite("<TD>".$DebProgs++.") url_base =<TD>-->$url_base"); 186 $this->DebugWindowsWrite("<TD>".$DebProgs++.") The pre text is:<TD>-->$pre"); 187 $this->DebugWindowsWrite("<TD>".$DebProgs++.") The input text is:<TD>-->$matches[1]"); 188 $this->DebugWindowsWrite("<TD>".$DebProgs++.") The post text is:<TD>-->$post"); 189 $this->DebugWindowsWrite("<TD>".$DebProgs++.") Parameters:<TD>-->$matches[0]"); 190 $this->DebugWindowsWrite("<TD>".$DebProgs++.") alias =<TD>-->$match_alias[1]"); 191 $this->DebugWindowsWrite("<TD>".$DebProgs++.") output =<TD>-->$match_output[1]"); 192 $this->DebugWindowsWrite("<TD>".$DebProgs++.") render =<TD>-->$match_render[1]"); 193 $this->DebugWindowsWrite("<TD>".$DebProgs++.") delim =<TD>-->$match_delim[1]"); 194 $this->DebugWindowsWrite("<TD>".$DebProgs++.") NSPath =<TD>-->$NSPath"); 195 $this->DebugWindowsWrite("<TD>".$DebProgs++.") The input file is:<TD>-->$InpFileName"); 196 $this->DebugWindowsWrite("<TD>".$DebProgs++.") The output file is:<TD>-->$OutFileName"); 197 $this->DebugWindowsWrite("<TD>".$DebProgs++.") The command is:<TD>-->$command"); 198 $this->DebugWindowsWrite("<TD>".$DebProgs++.") The output is:<TD>-->$output"); 199 $this->DebugWindowsWrite("<TD colspan=2 >End Trace Chain Plugin: ".date('l jS \of F Y h:i:s A')); 200 } 201 //** Rendering ** 202 //Save Always File Output for next chain command except png,tbl files 203 if ($config[$mode]['oext'] !== 'png' && $config[$mode]['oext'] !== 'tbl' ) io_saveFile($OutFileName, $output); 204 //if render=yes then render it 205 if ( trim($match_render[1]) == 'yes' ) 206 { 207 switch ($config[$mode]['oext']) 208 { 209 case 'out' : 210 $renderer->doc .= "<pre>$output</pre>"; 211 break; 212 213 case 'csv' : 214 if ( trim($match_debug[1]) == 'yes' ) 215 { 216 $renderer->doc .= "<pre>$output</pre>"; 217 } 218 //Convert csv to html table 219 //Clean sqlplus standard output string session 220 $output = preg_replace("/Session altered\./","",$output); 221 if (trim($match_delim[1]) == "[ \t]+") //mtab 222 { 223 //Clean sqlplus standard output string session 224 $output = preg_replace("/[0-9]+ rows selected\./","",$output); 225 $output = preg_replace("/[-]+\s/","",$output); 226 } 227 //$renderer->doc .= "<pre>$output</pre>"; 228 //Clean any trailing or leading empty lines from the data set 229 $output = preg_replace("/[\r\n]*$/","",$output); 230 $output = preg_replace("/^\s*[\r\n]*/","",$output); 231 //Replace EOL for all O.S. 232 $output = preg_replace("/(?<!\\n)\\r+(?!\\n)/", "\r\n", $output); //replace just CR with CRLF 233 $output = preg_replace("/(?<!\\r)\\n+(?!\\r)/", "\r\n", $output); //replace just LF with CRLF 234 $output = preg_replace("/(?<!\\r)\\n\\r+(?!\\n)/", "\r\n", $output); //replace misordered LFCR with CRLF 235 //Split output in a array of lines 236 //End of Line delimiter <end> is optional 237 if (strpos($output, '<end>')) 238 { 239 $lines = preg_split("/<end>\\r\\n/", $output); 240 } 241 else 242 { 243 $lines = preg_split("/\\r\\n/", $output); 244 } 245 //Loop for each line 246 $numlines = 0; 247 $table =""; 248 foreach ($lines as $line) 249 { 250 if ($numlines===0) 251 { 252 //First line is table header 253 $line = "<tr><th>".$line."\r\n"; 254 $table .= preg_replace("/$match_delim[1]/","<th>",$line); 255 } 256 else 257 { 258 //Other lines are data 259 $line = "<tr><td>".$line."\r\n"; 260 $table .= preg_replace("/$match_delim[1]/","<td>",$line); 261 } 262 ++$numlines; 263 } 264 $renderer->doc .= "\r\n<table class='inline' >\r\n".$table."</table>"; 265 break; 266 267 case 'tbl' : 268 if ( trim($match_debug[1]) == 'yes' ) 269 { 270 $renderer->doc .= "<pre>$output</pre>"; 271 } 272 //Convert csv to html table 273 //$renderer->doc .= "<pre>$output</pre>"; 274 //Clean any trailing or leading empty lines from the data set 275 $output = preg_replace("/[\r\n]*$/","",$output); 276 $output = preg_replace("/^\s*[\r\n]*/","",$output); 277 //Replace EOL for all O.S. 278 $output = preg_replace("/(?<!\\n)\\r+(?!\\n)/", "\r\n", $output); //replace just CR with CRLF 279 $output = preg_replace("/(?<!\\r)\\n+(?!\\r)/", "\r\n", $output); //replace just LF with CRLF 280 $output = preg_replace("/(?<!\\r)\\n\\r+(?!\\n)/", "\r\n", $output); //replace misordered LFCR with CRLF 281 //Split output in a array of lines 282 $lines = preg_split("/\\r\\n/", $output); 283 //Loop for each line 284 $numlines = 0; 285 $table =""; 286 foreach ($lines as $line) 287 { 288 if ($numlines===0) 289 { 290 //First line is table header 291 $line = "<tr><th>".$line."\r\n"; 292 $table .= preg_replace("/$match_delim[1]/","<th>",$line); 293 } 294 else 295 { 296 //Other lines are data 297 $line = "<tr><td>".$line."\r\n"; 298 $line_temp = preg_replace("/$match_delim[1]/","<td>",$line); 299 $table .= preg_replace("/<td><td>/","<td>",$line_temp); 300 } 301 ++$numlines; 302 } 303 $renderer->doc .= "\r\n<table class='inline' >\r\n".$table."</table>"; 304 break; 305 306 case 'png' : 307 //To avoid browser cache insert random number in a filename 308 $random=rand(); 309 $OutFileNameRnd =$dirname.'/'.'tempchain_'.$random.'_'.$match_output[1].'.'.$config[$mode]['oext']; 310 //Copy file 311 copy($OutFileName, $OutFileNameRnd); 312 //Render a file png 313 $OutFileNamePng = 'temp/chain'.$program.'/'.$ns_path.'/'.'tempchain_'.$random.'_'.$match_output[1].'.'.$config[$mode]['oext']; 314 $OutFileNamePng = str_replace("/",":",$OutFileNamePng); // Work out the namespace and page 315 $renderer->doc .= '<img src='.DOKU_BASE.'lib/exe/fetch.php?media='.$OutFileNamePng.' alt="Png Image Chain Plugin Error" />'; 316 break; 317 } 318 } 319 break; 320 case DOKU_LEXER_EXIT: 321 break; 322 } 323 return true; 324 } 325 326 327 function DebugWindowsOpen() 328 { 329 $GLOBALS[status_window_open] = 1; 330 ?> 331 <script language="JavaScript"> 332 <!-- 333 var winOpts = "width=400,height=250,scrollbars,resizable"; 334 sw = window.open("", "Status", winOpts); 335 if (sw.document == null) 336 { 337 sw = window.open("", "Status", winOpts); 338 } 339 sw.document.open(); 340 sw.bgcolor = "white"; 341 </script> 342 <?php 343 } 344 345 function DebugWindowsWrite($s) 346 { 347 if (!$GLOBALS[status_window_open]) 348 return; 349 ?> 350 <script> 351 <!-- 352 if (!sw.closed) { sw.document.write("<?php $s=str_replace(array("\n","\\"), array("<BR>","\\\\"), $s); echo "<TR>" . $s; ?>"); } 353 </script> 354 <?php 355 flush(); 356 } 357 358 function DebugWindowsClose() 359 { 360 if (!$GLOBALS[status_window_open]) 361 return; 362 363 $GLOBALS[status_window_open] = 0; 364 ?> 365 <script language="JavaScript"> 366 <!-- 367 if (!sw.closed) { sw.close(); } 368 </script> 369 <?php 370 } 371 372 373 } 374 375?> 376