<?php /** * Plugin Chain: Execute a sys command and create output file in a current directory for a next chain command. * * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) * @author Riccardo Pisanu <rkpisanu@yahoo.it> * based on the format plugin * * <chain alias=program_alias output=file_ouput render=[yes/no] > * text to feed into the program * </chain> * * program_alias is defined in conf/default.php similat to: * $conf['<program-name>']=array('name' => "<user name>", * '<mode>' => array('iext' => "<input extension>", 'oext' => "<output extension>", * 'pre' => "<pre>", * 'post' => "<post>", 'command_wintel' => "<wintel command line>" * 'command' => "<non wintel command line>" )); * * **/ // must be run within DokuWiki if(!defined('DOKU_INC')) die(); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once DOKU_PLUGIN.'syntax.php'; /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_chain extends DokuWiki_Syntax_Plugin { function getInfo() { return array('author' => 'Riccardo Pisanu', 'email' => 'rkpisanu@yahoo.it', 'date' => '2010-01-16', 'name' => 'Chain Plugin', 'desc' => 'Execute a sys command and create output file in a current directory for a next chain command.', 'url' => 'http://www.dokuwiki.org/plugin:chain'); } function getType() { return 'substition'; } function getSort() { return 32; } function connectTo($mode) { $this->Lexer->addEntryPattern('<chain(?=.*?>.*?</chain>)',$mode,'plugin_chain'); } function postConnect() { $this->Lexer->addExitPattern('</chain>','plugin_chain'); } function handle($match, $state, $pos, &$handler) { return array($match, $state, $pos); } function render($mode, &$renderer, $data) { //Query not have time limit set_time_limit(0); //No cache pages $renderer->info['cache'] = false; //Refer to global Dokuwiki vars to get directory configuration and namespace:page global $conf; global $ID; //Only xhtml if ($mode!='xhtml') return; //Split data received from handle function @list($match, $state, $pos) = $data; switch ($state) { case DOKU_LEXER_ENTER: break; case DOKU_LEXER_UNMATCHED: //** Split $match in Parameters $matches[0] and Text $matches[1] ** $matches = preg_split('/>/u',$match,2); $matches[0] = trim($matches[0]); if ( trim($matches[0]) == '' ) { $matches[0] = NULL; } //** Parsing Parameters ** preg_match('/alias=([a-zA-Z_0-9]+)/i', $matches[0], $match_alias); preg_match('/output=([a-zA-Z_0-9]+)/i', $matches[0], $match_output); preg_match('/render=([a-zA-Z_0-9]+)/i', $matches[0], $match_render); preg_match('/delim=([a-zA-Z_0-9]+)/i', $matches[0], $match_delim); preg_match('/debug=([a-zA-Z_0-9]+)/i', $matches[0], $match_debug); //Manage Delimitator switch (trim($match_delim[1])) { case 'tab' : $match_delim[1] = "\t"; break; case 'mtab' : $match_delim[1] = "[ \t]+"; break; case 'pipe' : $match_delim[1] = "\|"; break; case 'scol' : $match_delim[1] = ";"; break; default : $match_delim[1] = ","; } //** Begin Application Logic Plugin ** //Get alias configuration array conf[$match_alias[1]] in conf/default.php and exit with error message if it not well configured $config = $this->getConf($match_alias[1]); if(!$config || !$config[$mode]) { //_xmlEntities encode html correctly $renderer->doc .= $renderer->_xmlEntities($match_alias[1].' ** <chain alias=AliasName > not configured for '.$mode.' output in /lib/plugins/chain/default.php **'); return true; } //Create/Verify Directory to store files $ns_path = $ID; $ns_path = str_replace(":","/",$ns_path); // Work out the namespace and page $dirname = $conf['mediadir'].'/temp/chain'.$program.'/'.$ns_path; //Set relative url_base for image path rendering list($drive_path,$url_base) = split(DOKU_BASE,$dirname); $url_base = DOKU_BASE.$url_base; //If directory not exist then create it and grant permission with .htaccess if(!is_dir($dirname)) { io_mkdir_p($dirname); //Using dokuwiki framework } //Output Filename $OutFileName = $dirname.'/'.$match_output[1].'.'.$config[$mode]['oext']; $RelFileName = $url_base.'/'.$match_output[1].'.'.$config[$mode]['oext']; //Delete old OutFileName if exist if (is_file($OutFileName)) unlink($OutFileName); //Input Filename with contain all data wrapped pre + text + post $InpFileName = $dirname.'/'.$match_output[1].'.'.$config[$mode]['iext']; $NSPath = $dirname.'/'; if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') $NSPath=str_replace('/', '\\', $NSPath); $pre = str_replace(array('@InputFile@','@OutputFile@','@Path@'), array($InpFileName, $OutFileName, $NSPath), $config[$mode]['pre']); $post = str_replace(array('@InputFile@','@OutputFile@','@Path@'), array($InpFileName, $OutFileName, $NSPath), $config[$mode]['post']); $text = str_replace(array('@InputFile@','@OutputFile@','@Path@'), array($InpFileName, $OutFileName, $NSPath), $matches[1]); $wrappeddata = $pre.$text.$post; //Save File Using Dokuwiki Framework io_saveFile($InpFileName, $wrappeddata); // Replace the variable strings if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { //This is a command using Windows! $command=str_replace(array('@InputFile@','@OutputFile@','@Path@'), array($InpFileName, $OutFileName, $NSPath), $config[$mode]['command_wintel']); $command=str_replace('/', '\\', $command); $command=str_replace('Program Files','progra~1', $command); } else { //This is a command not using Windows! $command=str_replace(array('@InputFile@','@OutputFile@','@Path@'), array($InpFileName, $OutFileName, $NSPath), $config[$mode]['command']); } $output = shell_exec($command); //** Trace vars for debug ** if ( trim($match_debug[1]) == 'yes' ) { $DebProgs=1; $this->DebugWindowsOpen(); $this->DebugWindowsWrite("</table>\n<table border=1 >"); $this->DebugWindowsWrite("<TH colspan=2 >CHAIN DEBUG CONSOLE"); $this->DebugWindowsWrite("<TD colspan=2 > Begin Trace Chain Plugin: ".date('l jS \of F Y h:i:s A')); $this->DebugWindowsWrite("<TD>".$DebProgs++.") ns_path =<TD>-->$ns_path"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") dirname =<TD>-->$dirname"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") DOKU_BASE =<TD>-->".DOKU_BASE); $this->DebugWindowsWrite("<TD>".$DebProgs++.") url_base =<TD>-->$url_base"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") The pre text is:<TD>-->$pre"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") The input text is:<TD>-->$matches[1]"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") The post text is:<TD>-->$post"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") Parameters:<TD>-->$matches[0]"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") alias =<TD>-->$match_alias[1]"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") output =<TD>-->$match_output[1]"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") render =<TD>-->$match_render[1]"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") delim =<TD>-->$match_delim[1]"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") NSPath =<TD>-->$NSPath"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") The input file is:<TD>-->$InpFileName"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") The output file is:<TD>-->$OutFileName"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") The command is:<TD>-->$command"); $this->DebugWindowsWrite("<TD>".$DebProgs++.") The output is:<TD>-->$output"); $this->DebugWindowsWrite("<TD colspan=2 >End Trace Chain Plugin: ".date('l jS \of F Y h:i:s A')); } //** Rendering ** //Save Always File Output for next chain command except png,tbl files if ($config[$mode]['oext'] !== 'png' && $config[$mode]['oext'] !== 'tbl' ) io_saveFile($OutFileName, $output); //if render=yes then render it if ( trim($match_render[1]) == 'yes' ) { switch ($config[$mode]['oext']) { case 'out' : $renderer->doc .= "<pre>$output</pre>"; break; case 'csv' : if ( trim($match_debug[1]) == 'yes' ) { $renderer->doc .= "<pre>$output</pre>"; } //Convert csv to html table //Clean sqlplus standard output string session $output = preg_replace("/Session altered\./","",$output); if (trim($match_delim[1]) == "[ \t]+") //mtab { //Clean sqlplus standard output string session $output = preg_replace("/[0-9]+ rows selected\./","",$output); $output = preg_replace("/[-]+\s/","",$output); } //$renderer->doc .= "<pre>$output</pre>"; //Clean any trailing or leading empty lines from the data set $output = preg_replace("/[\r\n]*$/","",$output); $output = preg_replace("/^\s*[\r\n]*/","",$output); //Replace EOL for all O.S. $output = preg_replace("/(?<!\\n)\\r+(?!\\n)/", "\r\n", $output); //replace just CR with CRLF $output = preg_replace("/(?<!\\r)\\n+(?!\\r)/", "\r\n", $output); //replace just LF with CRLF $output = preg_replace("/(?<!\\r)\\n\\r+(?!\\n)/", "\r\n", $output); //replace misordered LFCR with CRLF //Split output in a array of lines //End of Line delimiter <end> is optional if (strpos($output, '<end>')) { $lines = preg_split("/<end>\\r\\n/", $output); } else { $lines = preg_split("/\\r\\n/", $output); } //Loop for each line $numlines = 0; $table =""; foreach ($lines as $line) { if ($numlines===0) { //First line is table header $line = "<tr><th>".$line."\r\n"; $table .= preg_replace("/$match_delim[1]/","<th>",$line); } else { //Other lines are data $line = "<tr><td>".$line."\r\n"; $table .= preg_replace("/$match_delim[1]/","<td>",$line); } ++$numlines; } $renderer->doc .= "\r\n<table class='inline' >\r\n".$table."</table>"; break; case 'tbl' : if ( trim($match_debug[1]) == 'yes' ) { $renderer->doc .= "<pre>$output</pre>"; } //Convert csv to html table //$renderer->doc .= "<pre>$output</pre>"; //Clean any trailing or leading empty lines from the data set $output = preg_replace("/[\r\n]*$/","",$output); $output = preg_replace("/^\s*[\r\n]*/","",$output); //Replace EOL for all O.S. $output = preg_replace("/(?<!\\n)\\r+(?!\\n)/", "\r\n", $output); //replace just CR with CRLF $output = preg_replace("/(?<!\\r)\\n+(?!\\r)/", "\r\n", $output); //replace just LF with CRLF $output = preg_replace("/(?<!\\r)\\n\\r+(?!\\n)/", "\r\n", $output); //replace misordered LFCR with CRLF //Split output in a array of lines $lines = preg_split("/\\r\\n/", $output); //Loop for each line $numlines = 0; $table =""; foreach ($lines as $line) { if ($numlines===0) { //First line is table header $line = "<tr><th>".$line."\r\n"; $table .= preg_replace("/$match_delim[1]/","<th>",$line); } else { //Other lines are data $line = "<tr><td>".$line."\r\n"; $line_temp = preg_replace("/$match_delim[1]/","<td>",$line); $table .= preg_replace("/<td><td>/","<td>",$line_temp); } ++$numlines; } $renderer->doc .= "\r\n<table class='inline' >\r\n".$table."</table>"; break; case 'png' : //To avoid browser cache insert random number in a filename $random=rand(); $OutFileNameRnd =$dirname.'/'.'tempchain_'.$random.'_'.$match_output[1].'.'.$config[$mode]['oext']; //Copy file copy($OutFileName, $OutFileNameRnd); //Render a file png $OutFileNamePng = 'temp/chain'.$program.'/'.$ns_path.'/'.'tempchain_'.$random.'_'.$match_output[1].'.'.$config[$mode]['oext']; $OutFileNamePng = str_replace("/",":",$OutFileNamePng); // Work out the namespace and page $renderer->doc .= '<img src='.DOKU_BASE.'lib/exe/fetch.php?media='.$OutFileNamePng.' alt="Png Image Chain Plugin Error" />'; break; } } break; case DOKU_LEXER_EXIT: break; } return true; } function DebugWindowsOpen() { $GLOBALS[status_window_open] = 1; ?> <script language="JavaScript"> <!-- var winOpts = "width=400,height=250,scrollbars,resizable"; sw = window.open("", "Status", winOpts); if (sw.document == null) { sw = window.open("", "Status", winOpts); } sw.document.open(); sw.bgcolor = "white"; </script> <?php } function DebugWindowsWrite($s) { if (!$GLOBALS[status_window_open]) return; ?> <script> <!-- if (!sw.closed) { sw.document.write("<?php $s=str_replace(array("\n","\\"), array("<BR>","\\\\"), $s); echo "<TR>" . $s; ?>"); } </script> <?php flush(); } function DebugWindowsClose() { if (!$GLOBALS[status_window_open]) return; $GLOBALS[status_window_open] = 0; ?> <script language="JavaScript"> <!-- if (!sw.closed) { sw.close(); } </script> <?php } } ?>