]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/Ploticus.php
No &new
[SourceForge/phpwiki.git] / lib / plugin / Ploticus.php
1 <?php
2
3 /*
4  * Copyright 2004 $ThePhpWikiProgrammingTeam
5  *
6  * This file is part of PhpWiki.
7  *
8  * PhpWiki is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * PhpWiki is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 /**
24  * The Ploticus plugin passes all its arguments to the ploticus
25  * binary and displays the result as PNG, GIF, EPS, SVG or SWF.
26  * Ploticus is a free, GPL, non-interactive software package
27  * for producing plots, charts, and graphics from data.
28  * See http://ploticus.sourceforge.net/doc/welcome.html
29  *
30  * @Author: Reini Urban
31  *
32  * Note:
33  * - For windows you need either a gd library with GIF support or
34  *   a ploticus with PNG support. This comes e.g. with the cygwin build.
35  * - We support only images supported by GD so far (PNG most likely).
36  *   No EPS, PS, SWF, SVG or SVGZ support yet, due to limitations in WikiPluginCached.
37  *   This will be fixed soon.
38  *
39  * Usage:
40 <<Ploticus device=png [ploticus options...]
41 multiline ploticus script ...
42 >>
43  * or without any script: (not tested)
44 <<Ploticus -prefab vbars data=myfile.dat delim=tab y=1 clickmapurl="http://mywiki.url/wiki/?pagename=@2" clickmaplabel="@3" -csmap >>
45  *
46  * TODO: PloticusSql - create intermediate data from SQL. Similar to SqlResult, just in graphic form.
47  * For example to produce nice looking pagehit statistics or ratings statistics.
48  * Ploticus has its own sql support within #getproc data, but this would expose security information.
49  */
50
51 if (!defined("PLOTICUS_EXE"))
52     if (isWindows())
53         define('PLOTICUS_EXE', 'pl.exe');
54     else
55         define('PLOTICUS_EXE', '/usr/local/bin/pl');
56 //TODO: check $_ENV['PLOTICUS_PREFABS'] and default directory
57
58 require_once 'lib/WikiPluginCached.php';
59
60 class WikiPlugin_Ploticus
61     extends WikiPluginCached
62 {
63     /**
64      * Sets plugin type to MAP if -csmap (-map or -mapdemo or -csmapdemo not supported)
65      * or HTML if the imagetype is not supported by GD (EPS, SVG, SVGZ) (not yet)
66      * or IMG_INLINE if device = png, gif or jpeg
67      */
68     function getPluginType()
69     {
70         if (!empty($this->_args['-csmap']))
71             return PLUGIN_CACHED_MAP; // not yet tested
72         // produce these on-demand so far, uncached.
73         // will get better support in WikiPluginCached soon.
74         // FIXME: html also? what about ''?
75         $type = $this->decideImgType($this->_args['device']);
76         if ($type == $this->_args['device'])
77             return PLUGIN_CACHED_IMG_INLINE;
78         $device = strtolower($this->_args['device']);
79         if (in_array($device, array('svg', 'swf', 'svgz', 'eps', 'ps', 'pdf', 'html'))) {
80             switch ($this->_args['device']) {
81                 case 'svg':
82                 case 'svgz':
83                     return PLUGIN_CACHED_STATIC | PLUGIN_CACHED_SVG_PNG;
84                 case 'swf':
85                     return PLUGIN_CACHED_STATIC | PLUGIN_CACHED_SWF;
86                 default:
87                     return PLUGIN_CACHED_STATIC | PLUGIN_CACHED_HTML;
88             }
89         } else
90             return PLUGIN_CACHED_IMG_INLINE; // normal cached libgd image handles
91     }
92
93     function getName()
94     {
95         return _("Ploticus");
96     }
97
98     function getDescription()
99     {
100         return _("Ploticus image creation.");
101     }
102
103     function managesValidators()
104     {
105         return true;
106     }
107
108     function getDefaultArguments()
109     {
110         return array(
111             'device' => 'png', // png,gif,svgz,svg,...
112             '-prefab' => '',
113             '-csmap' => false,
114             'data' => false, // <!plugin-list !> support
115             'alt' => false,
116             'help' => false,
117         );
118     }
119
120     function handle_plugin_args_cruft(&$argstr, &$args)
121     {
122         $this->source = $argstr;
123     }
124
125     /**
126      * Sets the expire time to one day (so the image producing
127      * functions are called seldomly) or to about two minutes
128      * if a help screen is created.
129      */
130     function getExpire($dbi, $argarray, $request)
131     {
132         if (!empty($argarray['help']))
133             return '+120'; // 2 minutes
134         return sprintf('+%d', 3 * 86000); // approx 3 days
135     }
136
137     /**
138      * Sets the imagetype according to user wishes and
139      * relies on WikiPluginCached to catch illegal image
140      * formats.
141      * (I feel unsure whether this option is reasonable in
142      *  this case, because png will definitely have the
143      *  best results.)
144      *
145      * @param WikiDB $dbi
146      * @param array $argarray
147      * @param Request $request
148      * @return string 'png', 'jpeg', 'gif'
149      */
150     function getImageType($dbi, $argarray, $request)
151     {
152         return $argarray['device'];
153     }
154
155     /**
156      * This gives an alternative text description of
157      * the image.
158      */
159     function getAlt($dbi, $argstr, $request)
160     {
161         return (!empty($this->_args['alt'])) ? $this->_args['alt']
162             : $this->getDescription();
163     }
164
165     /**
166      * Returns an image containing a usage description of the plugin.
167      *
168      * TODO: -csmap pointing to the Ploticus documentation at sf.net.
169      * @return string image handle
170      */
171     function helpImage()
172     {
173         $def = $this->defaultArguments();
174         //$other_imgtypes = $GLOBALS['PLUGIN_CACHED_IMGTYPES'];
175         //unset ($other_imgtypes[$def['imgtype']]);
176         $helparr = array(
177             '<<Ploticus ' .
178                 'device' => ' = "' . $def['device'] . "(default)|"
179                 . join('|', $GLOBALS['PLUGIN_CACHED_IMGTYPES']) . '"',
180             'data' => ' <!plugin-list !>: pagelist as input',
181             'alt' => ' = "alternate text"',
182             '-csmap' => ' bool: clickable map?',
183             'help' => ' bool: displays this screen',
184             '...' => ' all further lines below the first plugin line ',
185             '' => ' and inside the tags are the ploticus script.',
186             "\n  >>"
187         );
188         $length = 0;
189         foreach ($helparr as $alignright => $alignleft) {
190             $length = max($length, strlen($alignright));
191         }
192         $helptext = '';
193         foreach ($helparr as $alignright => $alignleft) {
194             $helptext .= substr('                                                        '
195                 . $alignright, -$length) . $alignleft . "\n";
196         }
197         return $this->text2img($helptext, 4, array(1, 0, 0),
198             array(255, 255, 255));
199     }
200
201     function withShellCommand($script)
202     {
203         $findme = 'shell';
204         $pos = strpos($script, $findme); // uppercase?
205         if ($pos === false)
206             return 0;
207         return 1;
208     }
209
210     function getImage($dbi, $argarray, $request)
211     {
212         //extract($this->getArgs($argstr, $request));
213         //extract($argarray);
214         $source =& $this->source;
215         if (!empty($source)) {
216             if ($this->withShellCommand($source)) {
217                 $this->_errortext .= _("shell commands not allowed in Ploticus");
218                 return false;
219             }
220             if (is_array($argarray['data'])) { // support <!plugin-list !> pagelists
221                 $src = "#proc getdata\ndata:";
222                 $i = 0;
223                 foreach ($argarray['data'] as $data) {
224                     // hash or array?
225                     if (is_array($data))
226                         $src .= ("\t" . join(" ", $data) . "\n");
227                     else
228                         $src .= ("\t" . '"' . $data . '" ' . $i++ . "\n");
229                 }
230                 $src .= $source;
231                 $source = $src;
232             }
233             $tempfile = $this->tempnam('Ploticus', 'plo');
234             @unlink($tempfile);
235             $gif = $argarray['device'];
236             $args = "-$gif -o $tempfile.$gif";
237             if (!empty($argarray['-csmap'])) {
238                 $args .= " -csmap -mapfile $tempfile.map";
239                 $this->_mapfile = "$tempfile.map";
240             }
241             if (!empty($argarray['-prefab'])) {
242                 //check $_ENV['PLOTICUS_PREFABS'] and default directory
243                 global $HTTP_ENV_VARS;
244                 if (empty($HTTP_ENV_VARS['PLOTICUS_PREFABS'])) {
245                     if (file_exists("/usr/share/ploticus"))
246                         $HTTP_ENV_VARS['PLOTICUS_PREFABS'] = "/usr/share/ploticus";
247                     elseif (defined('PLOTICUS_PREFABS'))
248                         $HTTP_ENV_VARS['PLOTICUS_PREFABS'] = constant('PLOTICUS_PREFABS');
249                 }
250                 $args .= (" -prefab " . $argarray['-prefab']);
251             }
252             if (isWindows()) {
253                 $fp = fopen("$tempfile.plo", "w");
254                 fwrite($fp, $source);
255                 fclose($fp);
256                 $code = $this->execute(PLOTICUS_EXE . " $tempfile.plo $args", $tempfile . ".$gif");
257             } else {
258                 $code = $this->filterThroughCmd($source, PLOTICUS_EXE . " -stdin $args");
259                 sleep(1);
260             }
261             //if (empty($code))
262             //    return $this->error(fmt("Couldn't start commandline ā€œ%sā€", $commandLine));
263             if (!file_exists($tempfile . ".$gif")) {
264                 $this->_errortext .= sprintf(_("%s error: outputfile ā€œ%sā€ not created"),
265                     "Ploticus", "$tempfile.$gif");
266                 if (isWindows())
267                     $this->_errortext .= ("\ncmd-line: " . PLOTICUS_EXE . " $tempfile.plo $args");
268                 else
269                     $this->_errortext .= ("\ncmd-line: cat script | " . PLOTICUS_EXE . " $args");
270                 @unlink("$tempfile.pl");
271                 @unlink("$tempfile");
272                 return false;
273             }
274             $ImageCreateFromFunc = "ImageCreateFrom$gif";
275             if (function_exists($ImageCreateFromFunc)) {
276                 $handle = $ImageCreateFromFunc("$tempfile.$gif");
277                 if ($handle) {
278                     @unlink("$tempfile.$gif");
279                     @unlink("$tempfile.plo");
280                     @unlink("$tempfile");
281                     return $handle;
282                 }
283             }
284             return "$tempfile.$gif";
285         } else {
286             return $this->error(fmt("empty source"));
287         }
288     }
289
290     // which argument must be set to 'png', for the fallback image when svg will fail on the client.
291     // type: SVG_PNG
292     function pngArg()
293     {
294         return 'device';
295     }
296
297     function getMap($dbi, $argarray, $request)
298     {
299         $img = $this->getImage($dbi, $argarray, $request);
300         return array($this->_mapfile, $img);
301     }
302 }
303
304 // Local Variables:
305 // mode: php
306 // tab-width: 8
307 // c-basic-offset: 4
308 // c-hanging-comment-ender-p: nil
309 // indent-tabs-mode: nil
310 // End: