1<?php
2/**
3 * plot-Plugin: Parses gnuplot-blocks
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Wizardry and Steamworks <wizardry.steamworks@outlook.com>,
7 *             Alexander 'E-Razor' Krause <alexander.krause@erazor-zone.de>
8 *
9 * [WaS] The following plugin is a revision of the GNUplot Plugin by
10 * Alexander 'E-Razor' Krause from 2005 that uses the original gnuplot binary
11 * in order to render graphs that has been patched up to work on modern
12 * DokuWiki versions.
13 *
14 */
15
16if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
17
18/**
19 * All DokuWiki plugins to extend the parser/rendering mechanism
20 * need to inherit from this class
21 */
22class syntax_plugin_plotwas extends DokuWiki_Syntax_Plugin {
23
24    function getType() { return 'protected'; }
25    function getPType() { return 'normal'; }
26    function getSort() { return 200; }
27
28    /**
29     * Connect pattern to lexer
30     */
31    function connectTo($mode) {
32        $this->Lexer->addEntryPattern('<plot(?=.*\x3C/plot\x3E)', $mode, 'plugin_plotwas');
33    }
34
35    function postConnect() {
36        $this->Lexer->addExitPattern('</plot>', 'plugin_plotwas');
37    }
38
39    /**
40     * Handle the match
41     */
42    function handle($match, $state, $pos, Doku_Handler $handler) {
43        if ( $state == DOKU_LEXER_UNMATCHED ) {
44            $matches = preg_split('/>/u', $match, 2);
45            $matches[0] = trim($matches[0]);
46            if ( trim($matches[0]) == '' ) {
47                $matches[0] = NULL;
48            }
49            return array($matches[1],$matches[0]);
50        }
51        return array($state, '', '');
52    }
53
54    /**
55     * Create output
56     */
57    function render($mode, Doku_Renderer $renderer, $data) {
58        global $conf;
59        if($mode == 'xhtml' && strlen($data[0]) > 1) {
60            $plotdir = $conf['mediadir'] . '/plot';
61            if ( !is_dir($plotdir) ) {
62                mkdir($plotdir, 0777 - $conf['dmask'], true);
63            }
64
65            $hash = md5(serialize($data[0]));
66            $filename = $plotdir.'/'.$hash.'.png';
67            $size_str = $data[1];
68
69            // If image already exists, render it immediately
70            if ( is_readable($filename) ) {
71                $renderer->doc .=  $this->plugin_render('{{'.'plot:'.$hash.'.png'."$size_str}}");
72                return true;
73            }
74
75            // Attempt to create image and check for true success
76            if ($this->createImage($filename, $data[0])) {
77                $renderer->doc .=  $this->plugin_render('{{'.'plot:'.$hash.'.png'."$size_str}}");
78            } else {
79                $renderer->doc .= '**ERROR RENDERING GNUPLOT**';
80            }
81            return true;
82        }
83
84        return false;
85    }
86
87    function createImage($filename, &$data) {
88        $tmpfname = tempnam(sys_get_temp_dir(), "dokuwiki.plot");
89
90        $gnuplot_data = 'set terminal png transparent nocrop enhanced font arial 8 size 420,320'."\n".
91                        "set output '".$filename."'\n" . $data;
92
93        file_put_contents($tmpfname, $gnuplot_data);
94
95        // Execute and capture status
96        exec('/usr/bin/gnuplot '.$tmpfname, $output, $return_var);
97
98        unlink($tmpfname);
99
100        // gnuplot returns 0 on success
101        return ($return_var === 0);
102    }
103
104    // output text string through the parser, allows dokuwiki markup to be used
105    function plugin_render($text, $format='xhtml') {
106        $info = array();
107        return p_render($format, p_get_instructions($text), $info);
108    }
109}
110