]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/WikiPluginCached.php
fix rename: Change pagename in all linked pages
[SourceForge/phpwiki.git] / lib / WikiPluginCached.php
1 <?php rcs_id('$Id: WikiPluginCached.php,v 1.9 2004-06-02 19:12:43 rurban Exp $');
2 /*
3  Copyright (C) 2002 Johannes Große (Johannes Gro&szlig;e)
4
5  This file is (not yet) part of PhpWiki.
6
7  PhpWiki is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11
12  PhpWiki is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.
16
17  You should have received a copy of the GNU General Public License
18  along with PhpWiki; if not, write to the Free Software
19  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */ 
21
22 /**
23  * You should set up the options in plugincache-config.php
24  * $ pear install http://pear.php.net/get/Cache
25  * This file belongs to WikiPluginCached.
26  * @author  Johannes Große
27  * @version 0.8
28  */
29
30 require_once "lib/WikiPlugin.php";
31 require_once "lib/plugincache-config.php";
32 // Try the installed pear class first. It might be newer. Not yet.
33 // @require_once('Cache.php');
34 // if (!class_exists('Cache'))
35 require_once('Cache.php'); // We have to create your own copy here.
36
37 define('PLUGIN_CACHED_HTML',0);
38 define('PLUGIN_CACHED_IMG_INLINE',1);
39 define('PLUGIN_CACHED_IMG_ONDEMAND',2);
40 define('PLUGIN_CACHED_MAP',3);
41
42 /**
43  * An extension of the WikiPlugin class to allow image output and      
44  * cacheing.                                                         
45  * There are several abstract functions to be overloaded. 
46  * Have a look at the example files
47  * <ul><li>plugin/TexToPng.php</li>
48  *     <li>plugin/CacheTest.php (extremely simple example)</li>
49  *     <li>plugin/RecentChanges.php</li>
50  *     <li>plugin/VisualWiki.php</li></ul>
51  *
52  * @author  Johannes Große
53  * @version 0.8
54  */                                                                
55 class WikiPluginCached extends WikiPlugin
56 {   
57     /** 
58      * Produces URL and id number from plugin arguments which later on,
59      * will allow to find a cached image or to reconstruct the complete 
60      * plugin call to recreate the image.
61      * 
62      * @param cache    object the cache object used to store the images
63      * @param argarray array  all parameters (including those set to 
64      *                        default values) of the plugin call to be
65      *                        prepared
66      * @access private
67      * @return array(id,url)  
68      */
69     function genUrl($cache,$argarray) {
70         global $request;
71         $cacheparams = $GLOBALS['CacheParams'];
72
73         $plugincall = serialize( array( 
74             'pluginname' => $this->getName(),
75             'arguments'  => $argarray ) ); 
76         $id = $cache->generateId( $plugincall );
77
78         $url = $cacheparams['cacheurl']; // FIXME: SERVER_URL ?
79         if (($lastchar = substr($url,-1)) == '/') {
80             $url = substr($url, 0, -1);
81         }
82         if (strlen($plugincall)>$cacheparams['maxarglen']) {
83             // we can't send the data as URL so we just send the id  
84
85             if (!$request->getSessionVar('imagecache'.$id)) {
86                 $request->setSessionVar('imagecache'.$id, $plugincall);
87             } 
88             $plugincall = false; // not needed anymore
89         }
90
91         if ($lastchar=='?') {
92             // this indicates that a direct call of the image creation
93             // script is wished ($url is assumed to link to the script)
94             $url .= "id=$id" . ($plugincall ? '&args='.rawurlencode($plugincall) : '');
95         } else {
96             // we are supposed to use the indirect 404 ErrorDocument method
97             // ($url is assumed to be the url of the image in 
98             //  cache_dir and the image creation script is referred to in the 
99             //  ErrorDocument 404 directive.)
100             $url .= '/' . $cacheparams['filename_prefix'] . $id . '.img' 
101                     . ($plugincall ? '?args='.rawurlencode($plugincall) : '');
102         }
103         if ($request->getArg("start_debug"))
104             $url .= "&start_debug=1";
105         return array($id, $url);
106     } // genUrl
107
108     /** 
109      * Replaces the abstract run method of WikiPlugin to implement
110      * a cache check which can avoid redundant runs. 
111      * <b>Do not override this method in a subclass. Instead you may
112      * rename your run method to getHtml, getImage or getMap.
113      * Have a close look on the arguments and required return values,
114      * however. </b>  
115      * 
116      * @access protected
117      * @param  dbi       WikiDB  database abstraction class
118      * @param  argstr    string  plugin arguments in the call from PhpWiki
119      * @param  request   Request ???
120      * @param  string    basepage Pagename to use to interpret links [/relative] page names.
121      * @return           string  HTML output to be printed to browser
122      *
123      * @see #getHtml
124      * @see #getImage
125      * @see #getMap
126      */
127     function run($dbi, $argstr, &$request, $basepage) {
128         $cache = WikiPluginCached::newCache();
129         $cacheparams = $GLOBALS['CacheParams'];
130
131         $sortedargs = $this->getArgs($argstr, $request);
132         if (is_array($sortedargs) )
133             ksort($sortedargs);
134         $this->_args =& $sortedargs;
135         list($id,$url) = $this->genUrl($cache, $sortedargs);
136
137         // ---------- html and img gen. -----------------
138         if ($this->getPluginType() == PLUGIN_CACHED_IMG_ONDEMAND) {
139             return $this->embedImg($url, $dbi, $sortedargs, $request);
140         }
141
142         $do_save = false;
143         $content = $cache->get($id, 'imagecache');
144         switch($this->getPluginType()) {
145             case PLUGIN_CACHED_HTML:
146                 if (!$content || !$content['html']) {
147                     $this->resetError();
148                     $content['html'] = $this->getHtml($dbi,$sortedargs,$request,$basepage);
149                     if ($errortext = $this->getError()) {
150                         WikiPluginCached::printError($errortext,'html');
151                         return HTML();
152                     }
153                     $do_save = true;
154                 } 
155                 break;
156             case PLUGIN_CACHED_IMG_INLINE:
157                 if ($cacheparams['usecache']&&(!$content || !$content['image'])) {
158                     $do_save = WikiPluginCached::produceImage($content, $this, $dbi, $sortedargs, $request, 'html');
159                     $content['html'] = $do_save?$this->embedImg($url, $dbi, $sortedargs, $request) : false;
160                 }
161                 break;
162             case PLUGIN_CACHED_MAP:
163                 if (!$content || !$content['image'] || !$content['html'] ) {
164                     $do_save = WikiPluginCached::produceImage($content, $this, $dbi, $sortedargs, $request, 'html');
165                     $content['html'] = $do_save?WikiPluginCached::embedMap($id,
166                         $url,$content['html'],$dbi,$sortedargs,$request):false;
167                 }
168                 break;
169         }
170         if ($do_save) {
171             $expire = $this->getExpire($dbi,$sortedargs,$request);
172             $cache->save($id, $content, $expire,'imagecache');
173         }
174         if ($content['html'])
175             return $content['html'];
176         return HTML();
177     } // run
178
179
180     /* --------------------- virtual or abstract functions ----------- */
181
182     /**
183      * Sets the type of the plugin to html, image or map 
184      * production
185      *
186      * @access protected 
187      * @return int determines the plugin to produce either html, 
188      *             an image or an image map; uses on of the 
189      *             following predefined values
190      *             <ul> 
191      *             <li>PLUGIN_CACHED_HTML</li>
192      *             <li>PLUGIN_CACHED_IMG_INLINE</li>
193      *             <li>PLUGIN_CACHED_IMG_ONDEMAND</li>
194      *             <li>PLUGIN_CACHED_MAP</li>
195      *             </ul>    
196      */
197     function getPluginType() {
198         return PLUGIN_CACHED_IMG_ONDEMAND;
199     }
200
201     /** 
202      * Creates an image handle from the given user arguments. 
203      * This method is only called if the return value of 
204      * <code>getPluginType</code> is set to 
205      * PLUGIN_CACHED_IMG_INLINE or PLUGIN_CACHED_IMG_ONDEMAND.
206      *
207      * @access protected pure virtual
208      * @param  dbi       WikiDB       database abstraction class
209      * @param  argarray  array        complete (!) arguments to produce 
210      *                                image. It is not necessary to call 
211      *                                WikiPlugin->getArgs anymore.
212      * @param  request   Request      ??? 
213      * @return           imagehandle  image handle if successful
214      *                                false if an error occured
215      */
216     function getImage($dbi,$argarray,$request) {
217         trigger_error('WikiPluginCached::getImage: pure virtual function in file ' 
218                       . __FILE__ . ' line ' . __LINE__, E_USER_ERROR);
219         return false;
220     }
221
222     /** 
223      * Sets the life time of a cache entry in seconds. 
224      * Expired entries are not used anymore.
225      * During a garbage collection each expired entry is
226      * removed. If removing all expired entries is not
227      * sufficient, the expire time is ignored and removing
228      * is determined by the last "touch" of the entry.
229      * 
230      * @access protected virtual
231      * @param  dbi       WikiDB       database abstraction class
232      * @param  argarray  array        complete (!) arguments. It is
233      *                                not necessary to call 
234      *                                WikiPlugin->getArgs anymore.
235      * @param  request   Request      ??? 
236      * @return           string       format: '+seconds'
237      *                                '0' never expires
238      */
239     function getExpire($dbi,$argarray,$request) {
240         return '0'; // persist forever
241     }
242
243     /** 
244      * Decides the image type of an image output. 
245      * Always used unless plugin type is PLUGIN_CACHED_HTML.
246      * 
247      * @access protected virtual
248      * @param  dbi       WikiDB       database abstraction class
249      * @param  argarray  array        complete (!) arguments. It is
250      *                                not necessary to call 
251      *                                WikiPlugin->getArgs anymore.
252      * @param  request   Request      ??? 
253      * @return           string       'png', 'jpeg' or 'gif'
254      */    
255     function getImageType($dbi,$argarray,$request) {
256         if (in_array($argarray['imgtype'], $GLOBAL['CacheParams']['imgtypes']))
257             return $argarray['imgtype'];
258         else
259             return 'png';
260     }
261
262     /** 
263      * Produces the alt text for an image.
264      * <code> &lt;img src=... alt="getAlt(...)"&gt; </code> 
265      *
266      * @access protected virtual
267      * @param  dbi       WikiDB       database abstraction class
268      * @param  argarray  array        complete (!) arguments. It is
269      *                                not necessary to call 
270      *                                WikiPlugin->getArgs anymore.
271      * @param  request   Request      ??? 
272      * @return           string       "alt" description of the image
273      */
274     function getAlt($dbi,$argarray,$request) {
275         return '<?plugin '.$this->getName().' '.$this->glueArgs($argarray).'?>';
276     }
277
278     /** 
279      * Creates HTML output to be cached.  
280      * This method is only called if the plugin_type is set to 
281      * PLUGIN_CACHED_HTML.
282      *
283      * @access protected pure virtual
284      * @param  dbi       WikiDB       database abstraction class
285      * @param  argarray  array        complete (!) arguments to produce 
286      *                                image. It is not necessary to call 
287      *                                WikiPlugin->getArgs anymore.
288      * @param  request   Request      ??? 
289      * @param  string    $basepage    Pagename to use to interpret links [/relative] page names.
290      * @return           string       html to be printed in place of the plugin command
291      *                                false if an error occured
292      */
293     function getHtml($dbi, $argarray, $request, $basepage) {
294         trigger_error('WikiPluginCached::getHtml: pure virtual function in file ' 
295                       . __FILE__ . ' line ' . __LINE__, E_USER_ERROR);
296     }
297
298     /** 
299      * Creates HTML output to be cached.  
300      * This method is only called if the plugin_type is set to 
301      * PLUGIN_CACHED_HTML.
302      *
303      * @access protected pure virtual
304      * @param  dbi       WikiDB       database abstraction class
305      * @param  argarray  array        complete (!) arguments to produce 
306      *                                image. It is not necessary to call 
307      *                                WikiPlugin->getArgs anymore.
308      * @param  request   Request      ??? 
309      * @return array(html,handle)     html for the map interior (to be specific,
310      *                                only &lt;area;&gt; tags defining hot spots)
311      *                                handle is an imagehandle to the corresponding
312      *                                image.
313      *                                array(false,false) if an error occured
314      */
315     function getMap($dbi, $argarray, $request) {
316         trigger_error('WikiPluginCached::getHtml: pure virtual function in file ' 
317                       . __FILE__ . ' line ' . __LINE__, E_USER_ERROR);
318     }
319
320     /* --------------------- produce Html ----------------------------- */
321
322     /** 
323      * Creates an HTML map hyperlinked to the image specified
324      * by url and containing the hotspots given by map.
325      *
326      * @access private
327      * @param  id       string  unique id for the plugin call
328      * @param  url      string  url pointing to the image part of the map
329      * @param  map      string  &lt;area&gt; tags defining active
330      *                          regions in the map
331      * @param  dbi      WikiDB  database abstraction class
332      * @param  argarray array   complete (!) arguments to produce 
333      *                          image. It is not necessary to call 
334      *                          WikiPlugin->getArgs anymore.
335      * @param  request  Request ??? 
336      * @return          string  html output
337      */
338     function embedMap($id,$url,$map,$dbi,$argarray,$request) {
339         // id is not unique if the same map is produced twice
340         $key = substr($id,0,8).substr(microtime(),0,6);
341         return HTML(HTML::map(array( 'name' => $key ), $map ),
342                     HTML::img( array(
343                    'src'    => $url, 
344                    //  'alt'    => htmlspecialchars($this->getAlt($dbi,$argarray,$request)) 
345                    'usemap' => '#'.$key ))
346                );
347     }
348
349     /** 
350      * Creates an HTML &lt;img&gt; tag hyperlinking to the specified
351      * url and produces an alternative text for non-graphical
352      * browsers.
353      *
354      * @access private
355      * @param  url      string  url pointing to the image part of the map
356      * @param  map      string  &lt;area&gt; tags defining active
357      *                          regions in the map
358      * @param  dbi      WikiDB  database abstraction class
359      * @param  argarray array   complete (!) arguments to produce 
360      *                          image. It is not necessary to call 
361      *                          WikiPlugin->getArgs anymore.
362      * @param  request  Request ??? 
363      * @return          string  html output
364      */
365     function embedImg($url,$dbi,$argarray,$request) {
366         return HTML::img( array( 
367             'src' => $url,
368             'alt' => htmlspecialchars($this->getAlt($dbi,$argarray,$request)) ) );         
369     }
370
371
372 // --------------------------------------------------------------------------
373 // ---------------------- static member functions ---------------------------
374 // --------------------------------------------------------------------------
375
376     /** 
377      * Creates one static PEAR Cache object and returns copies afterwards.
378      * FIXME: There should be references returned
379      *
380      * @access static protected
381      * @return Cache  copy of the cache object
382      */
383     function newCache() {
384         static $staticcache;
385   
386         $cacheparams = $GLOBALS['CacheParams'];
387
388         if (!is_object($staticcache)) {
389          /*  $pearFinder = new PearFileFinder;
390             $pearFinder->includeOnce('Cache.php');*/
391
392             $staticcache = new Cache($cacheparams['database'],$cacheparams); 
393             $staticcache->gc_maxlifetime = $cacheparams['maxlifetime'];
394  
395             if (!$cacheparams['usecache']) {
396                 $staticcache->setCaching(false);
397             }
398         }
399         return $staticcache; // FIXME: use references ?
400     }
401
402     /** 
403      * Determines whether a needed image type may is available 
404      * from the GD library and gives an alternative otherwise.
405      *
406      * @access  public static
407      * @param   wish   string one of 'png', 'gif', 'jpeg', 'jpg'
408      * @return         string the image type to be used ('png', 'gif', 'jpeg')
409      *                        'html' in case of an error
410      */
411
412     function decideImgType($wish) {
413         if ($wish=='html') return $wish;                 
414         if ($wish=='jpg') { $wish = 'jpeg'; }
415
416         $supportedtypes = array();
417         // Todo: swf, pdf, ...
418         $imagetypes = array(  
419             'png'   => IMG_PNG,
420             'gif'   => IMG_GIF,                             
421             'jpeg'  => IMG_JPEG,
422             'wbmp'  => IMG_WBMP,
423             'xpm'   => IMG_XPM,
424             /* // these do work but not with the ImageType bitmask
425             'gd'    => IMG_GD,
426             'gd2'   => IMG_GD,
427             'xbm'   => IMG_XBM,
428             */
429             );
430
431         $presenttypes = ImageTypes();
432         foreach($imagetypes as $imgtype => $bitmask)
433             if ( $presenttypes && $bitmask )
434                 array_push($supportedtypes, $imgtype);        
435
436         if (in_array($wish, $supportedtypes)) 
437             return $wish;
438         elseif (!empty($supportedtypes))
439             return reset($supportedtypes);
440         else
441             return 'html';
442         
443     } // decideImgType
444
445
446     /** 
447      * Writes an image into a file or to the browser.
448      * Note that there is no check if the image can 
449      * be written.
450      *
451      * @access  public static
452      * @param   imgtype   string 'png', 'gif' or 'jpeg'
453      * @param   imghandle string image handle containing the image
454      * @param   imgfile   string file name of the image to be produced
455      * @return  void
456      * @see     decideImageType
457      */
458     function writeImage($imgtype, $imghandle, $imgfile=false) {
459         if ($imgtype != 'html') {
460             $func = "Image" . strtoupper($imgtype);    
461             if ($imgfile) {
462                 $func($imghandle,$imgfile);
463             } else {
464                 $func($imghandle);
465             }
466         }
467     } // writeImage
468
469
470     /** 
471      * Sends HTTP Header for some predefined file types.
472      * There is no parameter check.
473      *
474      * @access  public static
475      * @param   doctype string 'gif', 'png', 'jpeg', 'html'
476      * @return  void 
477      */
478     function writeHeader($doctype) {
479         $IMAGEHEADER = array( 
480             'gif'  => 'Content-type: image/gif',
481             'png'  => 'Content-type: image/png',
482             'jpeg' => 'Content-type: image/jpeg',
483             'xbm'  => 'Content-type: image/xbm',
484             'xpm'  => 'Content-type: image/xpm',
485             'gd'   => 'Content-type: image/gd',
486             'gd2'  => 'Content-type: image/gd2',
487             'wbmp' => 'Content-type: image/vnd.wap.wbmp', // wireless bitmaps for PDA's and such.
488             'html' => 'Content-type: text/html' );
489         // Todo: swf
490        Header($IMAGEHEADER[$doctype]);
491     } // writeHeader
492
493
494     /** 
495      * Converts argument array to a string of format option="value". 
496      * This should only be used for displaying plugin options for 
497      * the quoting of arguments is not safe, yet.
498      *
499      * @access public static
500      * @param  argarray array   contains all arguments to be converted
501      * @return          string  concated arguments
502      */
503     function glueArgs($argarray) {
504         if (!empty($argarray)) {
505             $argstr = '';
506             while (list($key,$value)=each($argarray)) {
507                 $argstr .= $key. '=' . '"' . $value . '" ';  
508             // FIXME FIXME: How are values quoted? Can a value contain " ?
509             }
510             return substr($argstr,0,strlen($argstr)-1);
511         }
512         return '';
513     } // glueArgs
514
515     // ---------------------- FetchImageFromCache ------------------------------
516
517     /** 
518      * Extracts the cache entry id from the url and the plugin call
519      * parameters if available.
520      *
521      * @access private static
522      * @param  id           string   return value. Image is stored under this id.
523      * @param  plugincall   string   return value. Only returned if present in url.
524      *                               Contains all parameters to reconstruct
525      *                               plugin call.
526      * @param  cache        Cache    PEAR Cache object
527      * @param  request      Request  ???
528      * @param  errorformat  string   format which should be used to
529      *                               output errors ('html', 'png', 'gif', 'jpeg')
530      * @return boolean               false if an error occurs, true otherwise.
531      *                               Param id and param plugincall are
532      *                               also return values.
533      */
534     function checkCall1(&$id, &$plugincall,$cache,$request, $errorformat) {
535         $id=$request->getArg('id');
536         $plugincall=rawurldecode($request->getArg('args')); 
537
538         if (!$id) {
539            if (!$plugincall) {
540                 // This should never happen, so do not gettextify.
541                 $errortext = "Neither 'args' nor 'id' given. Cannot proceed without parameters.";
542                 WikiPluginCached::printError($errorformat, $errortext);
543                 return false;
544             } else {
545                 $id = $cache->generateId( $plugincall );
546             }
547         }   
548         return true;     
549     } // checkCall1
550
551
552     /** 
553      * Extracts the parameters necessary to reconstruct the plugin
554      * call needed to produce the requested image. 
555      *
556      * @access static private  
557      * @param  plugincall string   reference to serialized array containing both 
558      *                             name and parameters of the plugin call
559      * @param  request    Request  ???
560      * @return            boolean  false if an error occurs, true otherwise.
561      *                 
562      */
563     function checkCall2(&$plugincall,$request) {
564         // if plugincall wasn't sent by URL, it must have been
565         // stored in a session var instead and we can retreive it from there
566         if (!$plugincall) {
567             if (!$plugincall=$request->getSessionVar('imagecache'.$id)) {
568                 // I think this is the only error which may occur
569                 // without having written bad code. So gettextify it.
570                 $errortext = sprintf(
571                     gettext ("There is no image creation data available to id '%s'. Please reload referring page." ),
572                     $id );  
573                 WikiPluginCached::printError($errorformat, $errortext);
574                 return false; 
575             }       
576         }
577         $plugincall = unserialize($plugincall);
578         return true;
579     } // checkCall2
580
581
582     /** 
583      * Creates an image or image map depending on the plugin type. 
584      * @access static private 
585      * @param  content array             reference to created array which overwrite the keys
586      *                                   'image', 'imagetype' and possibly 'html'
587      * @param  plugin  WikiPluginCached  plugin which is called to create image or map
588      * @param  dbi     WikiDB            handle to database
589      * @param  argarray array            Contains all arguments needed by plugin
590      * @param  request Request           ????
591      * @param  errorformat string        outputs errors in 'png', 'gif', 'jpg' or 'html'
592      * @return boolean                   error status; true=ok; false=error
593      */
594     function produceImage(&$content, $plugin, $dbi, $argarray, $request, $errorformat) {
595         $plugin->resetError();
596         $content['html'] = $imagehandle = false;
597         if ($plugin->getPluginType() == PLUGIN_CACHED_MAP ) {
598             list($imagehandle,$content['html']) = $plugin->getMap($dbi, $argarray, $request);
599         } else {
600             $imagehandle = $plugin->getImage($dbi, $argarray, $request);
601         }
602
603         $content['imagetype'] 
604             = WikiPluginCached::decideImgType($plugin->getImageType($dbi, $argarray, $request));
605         $errortext = $plugin->getError();
606
607         if (!$imagehandle||$errortext) {
608             if (!$errortext) {
609                 $errortext = "'<?plugin ".$plugin->getName(). ' '
610                     . WikiPluginCached::glueArgs($argarray)." ?>' returned no image, " 
611                     . " although no error was reported.";
612             }
613             WikiPluginCached::printError($errorformat, $errortext);
614             return false; 
615         }
616
617         // image handle -> image data        
618         $cacheparams = $GLOBALS['CacheParams'];
619         $tmpfile = tempnam($cacheparams['cache_dir'],$cacheparams['filename_prefix']);
620         WikiPluginCached::writeImage($content['imagetype'], $imagehandle, $tmpfile);             
621         ImageDestroy($imagehandle);
622         if (file_exists($tmpfile)) {
623             $fp = fopen($tmpfile,'rb');
624             $content['image'] = fread($fp,filesize($tmpfile));
625             fclose($fp);
626             unlink($tmpfile);
627             if ($content['image'])
628                 return true;
629         }
630         return false;
631     } // produceImage
632
633
634     /** 
635      * Main function for obtaining images from cache or generating on-the-fly
636      * from parameters sent by url or session vars.
637      *
638      * @access static public
639      * @param  dbi     WikiDB            handle to database
640      * @param  request Request           ???
641      * @param  errorformat string        outputs errors in 'png', 'gif', 'jpeg' or 'html'
642      */
643     function fetchImageFromCache($dbi,$request,$errorformat='png') {
644         $cache   = WikiPluginCached::newCache();      
645         $errorformat = WikiPluginCached::decideImgType($errorformat);
646
647         if (!WikiPluginCached::checkCall1($id,$plugincall,$cache,$request,$errorformat)) return false;
648
649         // check cache 
650         $content = $cache->get($id,'imagecache');
651
652         if ($content && $content['image']) {
653             WikiPluginCached::writeHeader($content['imagetype']);
654             print $content['image']; 
655             return true;
656         } 
657
658         // produce image, now. At first, we need plugincall parameters
659         if (!WikiPluginCached::checkCall2($plugincall,$request)) return false;
660
661         $pluginname = $plugincall['pluginname'];
662         $argarray   = $plugincall['arguments'];
663
664         $loader = new WikiPluginLoader;
665         $plugin = $loader->getPlugin($pluginname);
666
667         // cache empty, but image maps have to be created _inline_
668         // so ask user to reload wiki page instead
669         $cacheparams = $GLOBALS['CacheParams'];
670         if (($plugin->getPluginType() == PLUGIN_CACHED_MAP) && $cacheparams['force_syncmap']) {
671             $errortext = gettext('Image map expired. Reload wiki page to recreate its html part.');
672             WikiPluginCached::printError($errorformat, $errortext);
673         }
674
675         
676         if (!WikiPluginCached::produceImage($content, $plugin, $dbi, $argarray, $request, $errorformat) ) return false;
677
678         $expire = $plugin->getExpire($dbi,$argarray,$request);
679
680         if ($content['image']) {
681             $cache->save($id, $content, $expire,'imagecache');
682             WikiPluginCached::writeHeader($content['imagetype']); 
683             print $content['image'];
684             return true;
685         }
686
687         $errortext = "Could not create image file from imagehandle.";
688         WikiPluginCached::printError($errorformat, $errortext);
689         return false; 
690     } // FetchImageFromCache
691
692     // -------------------- error handling ---------------------------- 
693
694     /** 
695      * Resets buffer containing all error messages. This is allways
696      * done before invoking any abstract creation routines like
697      * <code>getImage</code>.
698      *
699      * @access private
700      * @return void
701      */
702     function resetError() {
703         $this->_errortext = '';
704     }
705        
706     /** 
707      * Returns all accumulated error messages. 
708      *
709      * @access protected
710      * @return string error messages printed with <code>complain</code>.
711      */
712     function getError() {
713         return $this->_errortext;
714     }
715
716     /** 
717      * Collects the error messages in a string for later output 
718      * by WikiPluginCached. This should be used for any errors
719      * that occur during data (html,image,map) creation.
720      * 
721      * @access protected
722      * @param  addtext string errormessage to be printed (separate 
723      *                        multiple lines with '\n')
724      * @return void
725      */
726     function complain($addtext) {
727         $this->_errortext .= $addtext;
728     }
729
730     /** 
731      * Outputs the error as image if possible or as html text 
732      * if wished or html header has already been sent.
733      *
734      * @access static protected
735      * @param  imgtype string 'png', 'gif', 'jpeg' or 'html'
736      * @param  errortext string guess what?
737      * @return void
738      */
739     function printError($imgtype, $errortext) {
740        $imgtype = WikiPluginCached::decideImgType($imgtype);
741
742        $talkedallready = ob_get_contents() || headers_sent();
743        if (($imgtype=='html') || $talkedallready) {
744            trigger_error($errortext, E_USER_WARNING);
745        } else {
746            $red = array(255,0,0);
747            $grey = array(221,221,221);
748            $im = WikiPluginCached::text2img($errortext, 2, $red, $grey);
749            if (!$im) { 
750                trigger_error($errortext, E_USER_WARNING);
751                return;
752            }
753            WikiPluginCached::writeHeader($imgtype);
754            WikiPluginCached::writeImage($imgtype, $im); 
755            ImageDestroy($im);
756        }
757     } // printError
758
759
760     /** 
761      * Basic text to image converter for error handling which allows
762      * multiple line output.
763      * It will only output the first 25 lines of 80 characters. Both 
764      * values may be smaller if the chosen font is to big for there
765      * is further restriction to 600 pixel in width and 350 in height.
766      * 
767      * @access static public
768      * @param  txt     string  multi line text to be converted
769      * @param  fontnr  integer number (1-5) telling gd which internal font to use;
770      *                         I recommend font 2 for errors and 4 for help texts.
771      * @param  textcol array   text color as a list of the rgb components; array(red,green,blue)
772      * @param  bgcol   array   background color; array(red,green,blue)
773      * @return string          image handle for gd routines
774      */
775     function text2img($txt,$fontnr,$textcol,$bgcol) {
776         // basic (!) output for error handling
777
778         // check parameters
779         if ($fontnr<1 || $fontnr>5) {
780             $fontnr = 2;
781         }
782         if (!is_array($textcol) || !is_array($bgcol)) {
783                 $textcol = array(0,0,0);
784                 $bgcol = array(255,255,255);
785         }
786         foreach( array_merge($textcol,$bgcol) as $component) {
787             if ($component<0 || $component > 255) {
788                 $textcol = array(0,0,0);
789                 $bgcol = array(255,255,255);
790                 break;
791             }
792         }
793
794         // prepare Parameters 
795         
796         // set maximum values
797         $IMAGESIZE  = array(
798             'cols'   => 80,
799             'rows'   => 25,
800             'width'  => 600,
801             'height' => 350 );
802
803         $charx    = ImageFontWidth($fontnr);
804         $chary    = ImageFontHeight($fontnr);
805         $marginx  = $charx;
806         $marginy  = floor($chary/2);
807
808         $IMAGESIZE['cols'] = min($IMAGESIZE['cols'], floor(($IMAGESIZE['width']  - 2*$marginx )/$charx));
809         $IMAGESIZE['rows'] = min($IMAGESIZE['rows'], floor(($IMAGESIZE['height'] - 2*$marginy )/$chary));
810
811         // split lines
812         $y = 0;
813         $wx = 0;
814         do {
815             $len = strlen($txt);
816             $npos = strpos($txt, "\n");
817
818             if ($npos===false) {
819                 $breaklen = min($IMAGESIZE['cols'],$len);
820             } else {
821                 $breaklen = min($npos+1, $IMAGESIZE['cols']);
822             }
823             $lines[$y] = chop(substr($txt, 0, $breaklen));
824             $wx = max($wx,strlen($lines[$y++]));
825             $txt = substr($txt, $breaklen); 
826         } while ($txt && ($y < $IMAGESIZE['rows']));
827
828         // recalculate image size
829         $IMAGESIZE['rows'] = $y;
830         $IMAGESIZE['cols'] = $wx;
831  
832         $IMAGESIZE['width']  = $IMAGESIZE['cols'] * $charx + 2*$marginx;
833         $IMAGESIZE['height'] = $IMAGESIZE['rows'] * $chary + 2*$marginy;
834
835         // create blank image
836         $im = @ImageCreate($IMAGESIZE['width'],$IMAGESIZE['height']);
837
838         $col = ImageColorAllocate($im, $textcol[0], $textcol[1], $textcol[2]); 
839         $bg  = ImageColorAllocate($im, $bgcol[0], $bgcol[1], $bgcol[2]); 
840
841         ImageFilledRectangle($im, 0, 0, $IMAGESIZE['width']-1, $IMAGESIZE['height']-1, $bg);
842     
843         // write text lines
844         foreach($lines as $nr => $textstr) {
845             ImageString( $im, $fontnr, $marginx, $marginy+$nr*$chary, 
846                          $textstr, $col );
847         }
848         return $im;
849     } // text2img
850
851 } // WikiPluginCached
852
853
854 // For emacs users
855 // Local Variables:
856 // mode: php
857 // tab-width: 4
858 // c-basic-offset: 4
859 // c-hanging-comment-ender-p: nil
860 // indent-tabs-mode: nil
861 // End:
862 ?>