]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/Ploticus.php
Argh .. get rid of silly DOS \rs
[SourceForge/phpwiki.git] / lib / plugin / Ploticus.php
1 <?php // -*-php-*-
2 rcs_id('$Id: Ploticus.php,v 1.5 2004-06-28 16:35:12 rurban Exp $');
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
19  along with PhpWiki; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 only with the cygwin built.
35  * - We support only images supported by GD so far (PNG most likely). 
36  *   No EPS, PS, SWF, SVG or SVGZ support due to limitations in WikiPluginCached.
37  *   This will be fixed soon.
38  *
39  * Usage:
40 <?plugin Ploticus device=png [ploticus options...]
41    multiline ploticus script ...
42 ?>
43  * or without any script: (not tested)
44 <?plugin 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  */
49
50 if (!defined("PLOTICUS_EXE"))
51   if (isWindows())
52     define('PLOTICUS_EXE','pl.exe');
53   else
54     define('PLOTICUS_EXE','/usr/local/bin/pl');
55
56 require_once "lib/WikiPluginCached.php"; 
57
58 class WikiPlugin_Ploticus
59 extends WikiPluginCached
60 {
61     /**
62      * Sets plugin type to MAP if -csmap (-map or -mapdemo or -csmapdemo not supported)
63      * or HTML if the imagetype is not supported by GD (EPS, SVG, SVGZ) (not yet)
64      * or IMAGE if device = png, gif or jpeg
65      */
66     function getPluginType() {
67         if (!empty($this->_args['-csmap']))
68             return PLUGIN_CACHED_MAP; // not yet tested
69         else    
70             return PLUGIN_CACHED_IMG_INLINE;
71     }
72     function getName () {
73         return _("Ploticus");
74     }
75     function getDescription () {
76         return _("Ploticus image creation");
77     }
78     function managesValidators() {
79         return true;
80     }
81     function getVersion() {
82         return preg_replace("/[Revision: $]/", '',
83                             "\$Revision: 1.5 $");
84     }
85     function getDefaultArguments() {
86         return array(
87                      'device' => 'png', // png,gif,svgz,svg,...
88                      '-csmap' => false,
89                      'alt'    => false,
90                      'help'   => false,
91                      );
92     }
93     function handle_plugin_args_cruft(&$argstr, &$args) {
94         $this->source = $argstr;
95     }
96     /**
97      * Sets the expire time to one day (so the image producing
98      * functions are called seldomly) or to about two minutes
99      * if a help screen is created.
100      */
101     function getExpire($dbi, $argarray, $request) {
102         if (!empty($argarray['help']))
103             return '+120'; // 2 minutes
104         return sprintf('+%d', 3*86000); // approx 3 days
105     }
106
107     /**
108      * Sets the imagetype according to user wishes and
109      * relies on WikiPluginCached to catch illegal image
110      * formats.
111      * (I feel unsure whether this option is reasonable in
112      *  this case, because png will definitely have the
113      *  best results.)
114      *
115      * @return string 'png', 'jpeg', 'gif'
116      */
117     function getImageType($dbi, $argarray, $request) {
118         return $argarray['device'];
119     }
120
121     /**
122      * This gives an alternative text description of
123      * the image.
124      */
125     function getAlt($dbi, $argstr, $request) {
126         return (!empty($this->_args['alt'])) ? $this->_args['alt']
127                                              : $this->getDescription();
128     }
129
130     /**
131      * Returns an image containing a usage description of the plugin.
132      *
133      * TODO: -csmap pointing to the Ploticus documentation at sf.net.
134      * @return string image handle
135      */
136     function helpImage() {
137         $def = $this->defaultArguments();
138         //$other_imgtypes = $GLOBALS['PLUGIN_CACHED_IMGTYPES'];
139         //unset ($other_imgtypes[$def['imgtype']]);
140         $helparr = array(
141             '<?plugin Ploticus ' .
142             'device'           => ' = "' . $def['device'] . "(default)|" . join('|',$GLOBALS['PLUGIN_CACHED_IMGTYPES']).'"',
143             'alt'              => ' = "alternate text"',
144             '-csmap'           => ' bool: clickable map?',
145             'help'             => ' bool: displays this screen',
146             '...'              => ' all further lines below the first plugin line ',
147             ''                 => ' and inside the tags are the ploticus script.',
148             "\n  ?>"
149             );
150         $length = 0;
151         foreach($helparr as $alignright => $alignleft) {
152             $length = max($length, strlen($alignright));
153         }
154         $helptext ='';
155         foreach($helparr as $alignright => $alignleft) {
156             $helptext .= substr('                                                        '
157                                 . $alignright, -$length).$alignleft."\n";
158         }
159         return $this->text2img($helptext, 4, array(1, 0, 0),
160                                array(255, 255, 255));
161     }
162  
163     function newFilterThroughCmd($input, $commandLine) {
164         $descriptorspec = array(
165                0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
166                1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
167                2 => array("pipe", "w"),  // stdout is a pipe that the child will write to
168         );
169
170         $process = proc_open("$commandLine", $descriptorspec, $pipes);
171         if (is_resource($process)) {
172             // $pipes now looks like this:
173             // 0 => writeable handle connected to child stdin
174             // 1 => readable  handle connected to child stdout
175             // 2 => readable  handle connected to child stderr
176             fwrite($pipes[0], $input);
177             fclose($pipes[0]);
178             $buf = "";
179             while(!feof($pipes[1])) {
180                 $buf .= fgets($pipes[1], 1024);
181             }
182             fclose($pipes[1]);
183             $stderr = '';
184             while(!feof($pipes[2])) {
185                 $stderr .= fgets($pipes[2], 1024);
186             }
187             fclose($pipes[2]);
188             // It is important that you close any pipes before calling
189             // proc_close in order to avoid a deadlock
190             $return_value = proc_close($process);
191             if (empty($buf)) printXML($this->error($stderr));
192             return $buf;
193         }
194     }
195
196     /* PHP versions < 4.3
197      * TODO: via temp file looks more promising
198      */
199     function OldFilterThroughCmd($input, $commandLine) {
200          $input = str_replace ("\\", "\\\\", $input);
201          $input = str_replace ("\"", "\\\"", $input);
202          $input = str_replace ("\$", "\\\$", $input);
203          $input = str_replace ("`", "\`", $input);
204          $input = str_replace ("'", "\'", $input);
205          //$input = str_replace (";", "\;", $input);
206
207          $pipe = popen("echo \"$input\"|$commandLine", 'r');
208          if (!$pipe) {
209             print "pipe failed.";
210             return "";
211          }
212          $output = '';
213          while (!feof($pipe)) {
214             $output .= fread($pipe, 1024);
215          }
216          pclose($pipe);
217          return $output;
218     }
219
220     function withShellCommand($script) {
221         $findme  = 'shell';
222         $pos = strpos($script, $findme);
223         if ($pos === false) 
224             return 0;
225         return 1;
226     }
227
228     function getImage($dbi, $argarray, $request) {
229         //extract($this->getArgs($argstr, $request));
230         //extract($argarray);
231         $source =& $this->source;
232         if (!empty($source)) {
233             if ($this->withShellCommand($source)) {
234                 $this->_errortext .= _("shell commands not allowed in Ploticus");
235                 return false;
236             }
237             $html = HTML();
238             //$cacheparams = $GLOBALS['CacheParams'];
239             $tempfiles = $this->tempnam('Ploticus');
240             $gif = $argarray['device'];
241             $args = " -stdin -$gif -o $tempfiles.$gif";
242             if (!empty($argarray['-csmap'])) {
243                 $args .= " -csmap -mapfile $tempfiles.map";
244                 $this->_mapfile = "$tempfiles.map";
245             }
246             $commandLine = PLOTICUS_EXE . "$args";
247             if (check_php_version(4,3,0))
248                 $code = $this->newFilterThroughCmd($source, $commandLine);
249             else 
250                 $code = $this->oldFilterThroughCmd($source, $commandLine);
251             //if (empty($code))
252             //    return $this->error(fmt("Couldn't start commandline '%s'", $commandLine));
253             if (! file_exists("$tempfiles.$gif") ) {
254                 $this->_errortext .= fmt("Ploticus error: Outputfile '%s' not created", $tempfiles.$gif);
255                 return false;
256             }
257             $ImageCreateFromFunc = "ImageCreateFrom$gif";
258             $img = $ImageCreateFromFunc( "$tempfiles.$gif" );
259             return $img;
260         } else {
261             return $this->error(fmt("empty source"));
262         }
263     }
264     
265     function getMap($dbi, $argarray, $request) {
266         $img = $this->getImage($dbi, $argarray, $request);
267         return array($this->_mapfile, $img);
268     }
269 };
270
271 // $Log: not supported by cvs2svn $
272 // Revision 1.4  2004/06/19 10:06:38  rurban
273 // Moved lib/plugincache-config.php to config/*.ini
274 // use PLUGIN_CACHED_* constants instead of global $CacheParams
275 //
276 // Revision 1.3  2004/06/03 09:40:57  rurban
277 // WikiPluginCache improvements
278 //
279 // Revision 1.2  2004/06/02 19:37:07  rurban
280 // extended description
281 //
282 // Revision 1.1  2004/06/02 19:12:42  rurban
283 // new Ploticus plugin
284 //
285 //
286
287 // For emacs users
288 // Local Variables:
289 // mode: php
290 // tab-width: 8
291 // c-basic-offset: 4
292 // c-hanging-comment-ender-p: nil
293 // indent-tabs-mode: nil
294 // End:
295 ?>