dokuwiki-latex-plugin – Rev 1

Subversion Repositories:
Rev:
<?php
/**
 * Admin for LaTeX plugin.
 * 
 * @license     GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author       Mark Lundeberg <nanite@gmail.com>
 */

if(!defined('DOKU_INC')) die();
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'admin.php');

require_once(dirname(__FILE__).'/latexinc.php');

/**
 * All DokuWiki plugins to extend the admin function
 * need to inherit from this class
 */
class admin_plugin_latex extends DokuWiki_Admin_Plugin {
        var $output;
        /**
         * return some info
         */
         function getInfo(){
                $a = '';
                if(method_exists(DokuWiki_Admin_Plugin,"getInfo")) {
                         $a = parent::getInfo(); /// this will grab the data from the plugin.info.txt
                         $a['name'] = 'LaTeX plugin administration';
                         return $a;
                } else
                        // Otherwise return some hardcoded data for old dokuwikis
                        return array(
                                'author' => 'Alexander Kraus, Michael Boyle, and Mark Lundeberg)',
                                'email'  => '.',
                                'date'   => '???',
                                'name'   => 'LaTeX plugin',
                                'desc'   => 'LaTeX rendering plugin; requires LaTeX, dvips, ImageMagick.',
                                'url'   => 'http://www.dokuwiki.org/plugin:latex'
                        );
        }
 
        /**
         * return sort order for position in admin menu
         */
        function getMenuSort() {
          return 999;
        }

        // Purgers.
        function vio_atime($fname) {
                if(time() - fileatime($fname) - $this->_timelimit > 0)
                {
                        unlink($fname);
                        return $this->_timelimit;
                }
                return false;
        }
        function vio_mtime($fname) {
                if(time() - filemtime($fname) - $this->_timelimit > 0)
                {
                        unlink($fname);
                        return true;
                }
                return false;
        }
        function vio_all($fname) {
                unlink($fname);
                return true;
        }
 
 
        // purge all files older than $timelimit (in seconds)
        // $mode = 
        //        atime: age based on fileatime().
        //        mtime: age based on filemtime().
        //        all: delete all cached files.
        function latexpurge($mode, $timelimit)
        {
                global $conf, $config_cascade;
                $meddir = $conf['mediadir'] . '/' . strtr($this->getConf('latex_namespace'),':','/');
                $images = glob($meddir.'/img*');
                $this->_timelimit = $timelimit;
                switch($mode) {
                        case 'atime':
                                $vio = array_map(array($this,'vio_atime'),$images);
                                break;
                        case 'mtime':
                                $vio = array_map(array($this,'vio_mtime'),$images);
                                break;
                        case 'all':
                                $vio = array_map(array($this,'vio_all'),$images);
                                break;
                        default:
                                return false;
                }
                return array_combine($images,$vio);
        }
 
        /**
         * handle user request
         */
        function handle() {
          global $conf, $config_cascade;
          $this->output = "";
          if(isset($_POST['latexpurge']))
          {
                        $mode = $_POST['purgemode'];
                        $days = $_POST['purgedays'];
                        if(is_numeric($days) && $days == 0)
                                $mode = 'all';
                        if($mode == 'all') {
                                // If the admin wants to delete all of the images, probably it's good to print this reminder
                                //   since they are likely doing it after changing the colour or something.
                                // (I don't know how many hours I spent trying to fix LaTeX heisenbugs that were just cached... grr.)
                                $this->output .= '<div class="info">'.$this->getLang('refresh_note').'</div>';
                        }
                        $numdeleted = 0;
                        $numkept = 0;
                        $this->output .= "<pre>Purge result ([x] = deleted):\n";
                        if($mode == 'all' || (is_numeric($days) && $days >= 0)) {
                                $res = $this->latexpurge($mode, $days*86400);                           
                                foreach($res as $img => $vio){
                                        if($vio) {
                                                $this->output .= '[x] '.$img . "\n";
                                                $numdeleted += 1;
                                        } else {
                                                // $this->output .= '[ ] '.$img . "\n";
                                                $numkept += 1;
                                        }
                                }
                        } else {
                                $this->output = "<div class=\"error\">Purger: Bad form inputs. No action taken.</div>".$this->output;
                        }
                        $this->output .= "Totals: $numdeleted deleted, $numkept kept (kept files not shown).\n";
                        if ($numdeleted > 0) {
                                touch($config_cascade['main']['local']);
                        }
                        $this->output .= "</pre>";
          }
        }

        
        /**
         * output appropriate html
         */
        function html() {
                global $ID,$INFO;
                ptln('<p>'.$this->output.'</p>');
                ptln('<h1>LaTeX plugin administrator tasks</h1>');
                ptln('<h2>'.$this->getLang('legend_purge').'</h2>');
                ptln('<div class="level2">');

                ////////////// PURGE FORM
                ptln('<form action="'.wl($INFO['id']).'?do=admin&page='.$this->getPluginName().'" method="post">');
                ptln('<table class="inline"><tr>');
                ptln('<td rowspan="2"><input type="submit" class="button" name="latexpurge"  value="'.$this->getLang('btn_purge').'" /></td>');
                ptln('<TD>');
                $labtimes = $this->getLang('label_times');
                ptln('(<LABEL><INPUT type="radio" name="purgemode" value="atime" checked />'.$labtimes['atime'].'</LABEL>');
                ptln(' | <LABEL><INPUT type="radio" name="purgemode" value="mtime" />'.$labtimes['mtime'].'</LABEL>)');
                echo $this->getLang('label_olderthan');
                echo '<input type="text" name="purgedays" size="3" value="30">';
                echo $this->getLang('label_days');
                ptln('</TD><TR><TD>');
                echo '<LABEL><INPUT type="radio" name="purgemode" value="all" />'.$this->getLang('label_all').'</LABEL>';
                ptln('</TD></TR></TABLE>');
                ptln('</form>');
                
                ptln('</div>');

                /////////////// DIAGNOSER
                ptln('<h2>LaTeX troubleshooter</h2>');
                ptln('<div class="level2">');
                ptln('<form action="'.wl($INFO['id']).'" method="get">');
                ptln('  <input type="hidden" name="do"   value="admin" />');
                ptln('  <input type="hidden" name="page" value="'.$this->getPluginName().'" />');
                ptln('Push this button to diagnose your LaTeX/ImageMagick installation: <input type="submit" class="button" name="dotest"  value="Test" /><br/>');
                ptln('<input type="checkbox" name="keep_tmp">Check this button to keep the temporary files used during compilation.</input><br/>');
                ptln('The following latex code will be inserted into the template and compiled:');
                ptln('<br />');
                if(isset($_REQUEST['testformula']))
                        $testformula = $_REQUEST['testformula'];
                else
                        $testformula = '$$\underbrace{{\it f}({\rm DokuWiki}) = \overbrace{[a+b=c]}^\textrm{\LaTeX}}_{Success!}$$';
                ptln('  <textarea cols=70 rows=6 type="text" name="testformula">'.htmlspecialchars($testformula).'</textarea>');
                ptln('</form>');
                ptln('</div>');
                if($_REQUEST['dotest']) {
                        ptln('<h3>Versions</h3>');
                        ptln('<div class="level3">');
                        ptln('This is a test of the acessibility of your programs and their versions.');
                        ptln('<table class="inline">');
                        ptln('<tr><th>command</th><th>output</th></tr>');
                        foreach(array($this->getConf("latex_path"),$this->getConf("dvips_path"),
                                        $this->getConf("convert_path"),$this->getConf("identify_path")) as $path) {
                                ptln('<tr><td><pre>');
                                $cmd = $path." --version 2>&1";
                                echo htmlspecialchars($cmd);
                                ptln('</pre></td><td>');
                                unset($execout);
                                exec($cmd,$execout,$statuscode);
                                if($statuscode == 0)
                                        echo '<pre>';
                                else
                                        echo '<pre style="background-color:#FCC;">'; //pink for error status
                                echo htmlspecialchars(implode(PHP_EOL,$execout));
                                ptln('</pre></td></tr>');
                        }
                        ptln('</table>');
                        ptln('</div>');
                        
                        ptln('<h3>Test run</h3>');
                        $plug = new syntax_plugin_latex_common();
                        
                        /// Directory sanity checks
                        if(is_writable($plug->_latex->getPicturePath()) && is_dir($plug->_latex->getPicturePath()))
                                ptln('<div class="success">Media directory is writable: <code>'.$plug->_latex->getPicturePath().'</code></div>');
                        else
                                ptln('<div class="error">Media directory not writable or nonexistant! <code>'.$plug->_latex->getPicturePath().'</code>
                                                <br />Recommendation: This media namespace must be writable on the file system.</div>');
                        if(is_writable($plug->_latex->_tmp_dir) && is_dir($plug->_latex->_tmp_dir))
                                ptln('<div class="success">Temporary directory is writable: <code>'.$plug->_latex->_tmp_dir.'</code></div>');
                        else
                                ptln('<div class="error">Temporary directory not writable or nonexistant! <code>'.$plug->_latex->_tmp_dir.'</code>
                                                <br />Recommendation: This media namespace must be writable on the file system.</div>');

                        // simulate a call to the syntax plugin; force render, keep temp files.
                        $md5 = md5($testformula);
                        $outname = $plug->_latex->getPicturePath()."/img".$md5.'.'.$plug->_latex->_image_format;
                        if(file_exists($outname)) {
                                if(unlink($outname))
                                        ptln('<div class="info">Removed cache file for test: <code>'.$outname.'</code><br/>
                                        <b>WARNING: You may need to refresh your browser\'s cache to see changes in the resulting image.</b></div>');
                                else
                                        ptln('<div class="error">Could not remove cached file for test! <code>'.$outname.'</code><br />
                                                                        the following tests will not work (renderer will just reuse the cached file)</div>');
                        }
                        ptln('<div class="info">Attempting to render to target <code>'.$outname.'</code></div>');
                        $plug->_latex->_keep_tmp = true;
                        $plug->_latex->_cmdoutput = ''; // activate command log.
                        $data = array($testformula,DOKU_LEXER_UNMATCHED,'class'=>"latex_inline", 'title'=>"Math", NULL);
                        $this->doc = '';
                        $xhtml  = new Doku_Renderer_xhtml();
                        $plug->render('xhtml', $xhtml, $data);
                        $tmpw = $this->getConf('latex_namespace').':tmp:'.$plug->_latex->_tmp_filename;
                        $tmpf = $plug->_latex->_tmp_dir."/".$plug->_latex->_tmp_filename;
                        $tmpext = array('tex','log','aux','dvi','ps',$plug->_latex->_image_format);
                        foreach($tmpext as $ext) {
                                $fname = $tmpf.'.'.$ext;
                                if(is_file($fname)) {
                                        if(isset($_REQUEST['keep_tmp'])) {
                                                $rendstr = $plug->render('xhtml', $xhtml, '{{'.$tmpw.'.'.$ext.'?linkonly&nocache|'.$fname.'}}');
                                                $rendstr = preg_replace('/<\\/?p>/','',$rendstr);
                                        } else
                                                $rendstr = $fname;
                                        ptln('<div class="success">File created: <code>'.$rendstr.'</code></div>');
                                } else
                                        ptln('<div class="error">File missing! <code>'.$fname.'</code></div>');
                        }
                        if(! isset($_REQUEST['keep_tmp']))
                                ptln('<div class="info">These files <code>'.$tmpf.'.*</code> will be deleted at the end of this script.</div>');
                        if(is_file($outname))
                                ptln('<div class="success">Successfully moved to media: <code>'.$outname.'</code></div>');
                        else
                                ptln('<div class="error">File missing from media! <code>'.$outname.'</code></div>');
                                
                        ptln('<div class="level3">');
                        ptln('<table class="inline"><tr><th>Input LaTeX file</th><th>Final result</th></tr>');
                        ptln('<tr><td><pre>');
                        if(is_readable($tmpf.'.tex') && is_file($tmpf.'.tex'))
                                echo htmlspecialchars(file_get_contents($tmpf.'.tex'));
                        else
                                echo 'MISSING';
                        ptln('</pre></td><td>');
//                      ptln(htmlspecialchars($plug->_url));
//                      ptln('<br /><br />');
                        ptln('<center>');
                        ptln($this->doc);
                        ptln('</center></td></tr>');
                        ptln('</table>');
                        
                        ptln('Command log:');
                        echo '<pre>';
                        echo $plug->_latex->_cmdoutput;
                        echo '</pre>';
                        
                        ptln('Contents of '.$tmpf.'.log:');
                        echo '<pre>';
                        echo htmlspecialchars(file_get_contents($tmpf.'.log'));
                        echo '</pre>';
                        
                        if(! isset($_REQUEST['keep_tmp']))
                                $plug->_latex->cleanTemporaryDirectory();
                        ptln('</div>');
                }
        }
}

Generated by GNU Enscript 1.6.5.90.