Mediawiki/Erweiterung/GnuplotBasic

Aus Mikiwiki
Zur Navigation springen Zur Suche springen

Die Mediawiki-Erweiterung GnuplotBasic erlaubt die Erzeugung und Anzeige von grafischen Darstellungen. Dabei wird das Programm Gnuplot verwendet.

Installation

1. Voraussetzung ist die Installation des Pakets "gnuplot".

# apt-get install gnuplot

2. Anlegen der Datei "extensions/Gnuplot.php" und Einfügen des folgenden PHP-Codes: GnuplotBasic 0.9.3 (2009-01-15).

# mkdir extensions/GnuplotBasic
# chown wiki:wiki extensions/GnuplotBasic
# vi extensions/GnuplotBasic/GnuplotBasic.php
<?php
/*****************************************************************************
* PURPOSE
*   Extension script to use Gnuplot in a MediaWiki instance.
*   Insert the Gnuplot code between the tags <gnuplot>...</gnuplot>.
*
*   Within <gnuplot> ... </gnuplot> this extension accepts (inline) plotdata 
*   within <plotdata> ... </plotdata>. If there is plotdata the source
*   is spilt in a plotscript-part and a plotdata-part. Note that <plotdata> is
*   not a MediaWiki hook.
*
* AUTHOR
*   Gérard de Smaele
*
* NOTES
*   Include this in the LocalSettings.php:
*   1) add 'require_once("extensions/GnuplotBasic/GnuplotBasic.php")'
*   2) Set $wgGnuplotCommand to the Gnuplot executable.
*      For windows: "C:\\Program files\\Gnuplot\\pgnuplot.exe"
*      Default:     "/usr/bin/gnuplot"
*   3) Set $wgGnuplotRefreshRate to desired refresh rate 
*      (in seconds) of a graph in case it already exists.
*      - (24*60*60) Refresh after one day (x seconds)
*      - (0)        Refresh always (zero)
*      - (-1)       Refresh never  (minus one)
*   4) Set $wgGnuplotDefaultTerminal to standard terminal e.g.
*      - set terminal png transparent small (default)
*      - set terminal png transparent font verdana 8
*******************************************************************************/
 
// Extension credits that will show up on Special:Version
$wgExtensionCredits['parserhook'][] = array(
	'name' => 'GnuplotBasic',
	'author' => 'Gérard de Smaele',
	'version' => '0.9.3',
	'description' => 'Adds the tag <code>&lt;gnuplot&gt;</code> to use Gnuplot',
	'url' => 'http://www.mediawiki.org/wiki/Extension:GnuplotBasic',
);
 
$wgGnuplotCommand = '/usr/bin/gnuplot'; // Unix
#$wgGnuplotCommand = 'C:\\Wamp\\bin\\gnuplot\\bin\\pgnuplot.exe';  // Windows
 
$wgGnuplotDefaultTerminal = 'set terminal png transparent small';
$wgGnuplotDefaultSize     = 'set size 0.5, 0.5';
$wgGnuplotRefreshRate     = -1; // Refresh never if gnuplot call hasn't changed (default)
 
// Avoid unstubbing $wgParser too early on modern (1.12+) MW versions, as per r35980
if ( defined( 'MW_SUPPORTS_PARSERFIRSTCALLINIT' ) ) {
	$wgHooks['ParserFirstCallInit'][] = 'wfGnuplotBasicExtension';
} else {
	$wgExtensionFunctions[] = 'wfGnuplotBasicExtension';
}
 
function wfGnuplotBasicExtension() {
	global $wgParser;
	$wgParser->setHook( 'gnuplot', 'renderPlot' );
	return true;
}
 
function renderPlot( $gnuplotsrc ) {
	global $wgGnuplotDefaultTerminal, $wgGnuplotDefaultSize;
	global $wgGnuplotCommand, $wgGnuplotRefreshRate;
	global $wgUploadDirectory, $wgUploadPath;
 
	// create directory for storing the plot files
	$gnuplotDir = "/gnuplot/";
	$dest = $wgUploadDirectory . $gnuplotDir;
	if( !is_dir( $dest ) ) {
		mkdir($dest, 0777);
		chmod($dest, 0777);
	}
	// make sure the path is correct for both Windows and UNIX
	chdir($dest);
	$dest = getcwd(); 
 
	// get the filename of the graph to be produced
	$name = getFileName( $gnuplotsrc );
	$graphname = $dest . DIRECTORY_SEPARATOR .$name;
	$fname = $graphname . ".tmp";  //gnuplot plotscript
	$dname = $graphname . ".dat";  //gnuplot plotdata
 
	$makeGraph = true;
	if( ( file_exists( $graphname ) ) and ( ( $wgGnuplotRefreshRate ) <> 0 ) ) {
		// the file already exists it won't be refreshed when
		// it is newer than the refreshrate OR setting set to never refresh
		if( (time() - filemtime($graphname)) < ($wgGnuplotRefreshRate) ) $makeGraph = false;
		if( ($wgGnuplotRefreshRate) == -1 ) $makeGraph = false;
	}
 
	if( $makeGraph ) {
		// Step 1: Check if there is plotdata defined
		$pos1 = strpos($gnuplotsrc, "<plotdata>");
		if( $pos1 !== false ){
			// split gnuplotsrc in a plotscript-part and a plotdata-part
			$pos2 = strpos($gnuplotsrc, "</plotdata>");
			if( $pos2 === false ) $pos2 = strlen($gnuplotsrc);
			$plotdata = substr($gnuplotsrc, $pos1+10, $pos2-($pos1+10));
			$gnuplotsrc = substr($gnuplotsrc, 0, $pos1);
			// replace gnuplot inline filename(s) '-' to the plotdata filename
			$gnuplotsrc = str_replace("'-'", "'$dname'", $gnuplotsrc);
			// save the plotdata-part 
			$handle2 = fopen($dname, 'w');
			fwrite($handle2, trim($plotdata));
			fclose($handle2); 
		}
 
		// Step 2: Parse the plotscript-part and do some basic syntax checking
		$unparsedScriptArray = explode( "\n", $gnuplotsrc );
		$parsedScriptArray = array_filter( $unparsedScriptArray, "parsePlotScript" );
		$gnuplotsrc = implode( "\n", $parsedScriptArray );
 
		// write the default settings and the input code from wiki into a
		// temporary file to be executed by gnuplot, then execute the command
		$handle = fopen($fname, 'w');
 
		// if terminal and size are not set in the gnuplot source we do it here
		if( strpos($gnuplotsrc, 'set terminal ') === false ) {
			fwrite($handle, $wgGnuplotDefaultTerminal . "\n");
		}
		if( strpos($gnuplotsrc, 'set size ') === false ) {
			fwrite($handle, $wgGnuplotDefaultSize . "\n");
		}
 
		fwrite($handle, "\nset output '" . $graphname . "'\n");
 
		// save the plotscript-part
		fwrite($handle, $gnuplotsrc . "\n");
		fwrite($handle, "exit" . "\n");
		fclose($handle); 
 
		// execute the gnuplot command
		$cmdlinePlot = $wgGnuplotCommand . ' ' . $fname;
		shell_exec($cmdlinePlot);
 
		// cleanup temporary files
		unlink($fname);
		if( $pos1 !== false ) unlink($dname);
	}
 
	return '<p><b><img src="' . htmlspecialchars($wgUploadPath . $gnuplotDir . $name) .
		'" alt="GnuplotBasic Plot"></b></p>';
}
 
/***
 * Function: parsePlotScript
 * Purpose : Basic syntax checks and replaces unwanted and potentially harmful commands.
 *           Note that gnuplot allows far more advanced syntax than is allowed
 *           and recognised here. This should however suffice most graph needs from 
 *           within a MediaWiki instance. 
 * Input   : &$scriptline - a line from the scriptpart (by reference because we do 
 *           some modifications here).
 * Output  : false if the line ends up empty.
 */
function parsePlotScript( &$scriptline ) {
 
	$unwantedCommands = array(
		"`" => "",
		"set output " => "xxx xxxxxx ",
		"shell" => "xxxxx", // potentially harmful
		"system" => "xxxxxx", // potentially harmful
		"load " => "xxxx ", 
		"call " => "xxxx ", 
		"save " => "xxxx ", 
		"cd '" => "xx ", 
		"cd \"" => "xx ", 
		"update " => "xxxxxx "
	);
 
	$scriptline = trim($scriptline);
	if( strlen($scriptline) == 0 ) return false;
 
	// Step 1: Delete everything after the first comment character
	$p = strpos($scriptline, "#");
	if( $p !== false ) {
		$scriptline = substr($scriptline, 0, $p);
		$scriptline = trim($scriptline);
		if( strlen($scriptline) == 0 ) return false;
	}
	// Step 2: Replace unwanted commands with substitutes
	$scriptline = strtr($scriptline, $unwantedCommands);
	$scriptline = trim($scriptline);
	if( strlen($scriptline) == 0 ) return false;
 
	return true;
}
 
/***
 * Function: getFileName
 * Purpose : Determines the unique name of the output file.  
 *           The filename is computed by a hash function and therefore always unique 
 *           for the script plus its (optional) inline plotdata.
 *           The file extension is extracted from de format in the "set terminal" 
 *           command. If this format is not found or there is a syntax error it is 
 *           set to "xxx".
 * Input   : $gnuplotsrc - the <gnuplot> input code from the wiki markup
 * Output  : The file name with its extension
 */
function getFileName ( $gnuplotsrc ) {
	// determine the file format of the plotted graph image - default is png
	$format = "png";
	$tpos = strpos($gnuplotsrc, "set terminal ");
	if( $tpos !== false ) {
		$format = '';
		$tpos = $tpos + strlen("set terminal ");
		// extract the fileformat from this command, this is considered
		// to be the next word either ending with " ", "\n" or "\t"
		$done = false;
		do {
			$char = substr($gnuplotsrc, $tpos, 1);
			$tpos = $tpos + 1;
			if( $char !== false ) {
				if( ($char == " ") || ($char == "\n") || ($char == "\t") ) {
					$done = true;
				} else {
					$format .= $char;
				}
			} else {
				$done = true;
			}
		} while( !$done );
 
		$format = trim($format);
		if( (strlen($format) == 0) || (strlen($format) > 6) ) $format = "xxx";
	}
	$filename = md5($gnuplotsrc) . "." . $format;
	return $filename;
}
?>

3. Anpassung der Rechte.

# chown wiki:wiki extensions/GnuplotBasic/GnuplotBasic.php

4. Einfügen der folgenden Zeile in die Datei "LocalSettings.php".

## Extension: GnuplotBasic
require_once("$IP/extensions/GnuplotBasic/GnuplotBasic.php");
$wgGnuplotCommand = "/usr/bin/gnuplot";

Weblinks