dokuwiki-latex-plugin – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | <?php |
2 | /** |
||
3 | * Admin for LaTeX plugin. |
||
4 | * |
||
5 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) |
||
6 | * @author Mark Lundeberg <nanite@gmail.com> |
||
7 | */ |
||
8 | |||
9 | if(!defined('DOKU_INC')) die(); |
||
10 | if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); |
||
11 | require_once(DOKU_PLUGIN.'admin.php'); |
||
12 | |||
13 | require_once(dirname(__FILE__).'/latexinc.php'); |
||
14 | |||
15 | /** |
||
16 | * All DokuWiki plugins to extend the admin function |
||
17 | * need to inherit from this class |
||
18 | */ |
||
19 | class admin_plugin_latex extends DokuWiki_Admin_Plugin { |
||
20 | var $output; |
||
21 | /** |
||
22 | * return some info |
||
23 | */ |
||
24 | function getInfo(){ |
||
25 | $a = ''; |
||
26 | if(method_exists(DokuWiki_Admin_Plugin,"getInfo")) { |
||
27 | $a = parent::getInfo(); /// this will grab the data from the plugin.info.txt |
||
28 | $a['name'] = 'LaTeX plugin administration'; |
||
29 | return $a; |
||
30 | } else |
||
31 | // Otherwise return some hardcoded data for old dokuwikis |
||
32 | return array( |
||
33 | 'author' => 'Alexander Kraus, Michael Boyle, and Mark Lundeberg)', |
||
34 | 'email' => '.', |
||
35 | 'date' => '???', |
||
36 | 'name' => 'LaTeX plugin', |
||
37 | 'desc' => 'LaTeX rendering plugin; requires LaTeX, dvips, ImageMagick.', |
||
38 | 'url' => 'http://www.dokuwiki.org/plugin:latex' |
||
39 | ); |
||
40 | } |
||
41 | |||
42 | /** |
||
43 | * return sort order for position in admin menu |
||
44 | */ |
||
45 | function getMenuSort() { |
||
46 | return 999; |
||
47 | } |
||
48 | |||
49 | // Purgers. |
||
50 | function vio_atime($fname) { |
||
51 | if(time() - fileatime($fname) - $this->_timelimit > 0) |
||
52 | { |
||
53 | unlink($fname); |
||
54 | return $this->_timelimit; |
||
55 | } |
||
56 | return false; |
||
57 | } |
||
58 | function vio_mtime($fname) { |
||
59 | if(time() - filemtime($fname) - $this->_timelimit > 0) |
||
60 | { |
||
61 | unlink($fname); |
||
62 | return true; |
||
63 | } |
||
64 | return false; |
||
65 | } |
||
66 | function vio_all($fname) { |
||
67 | unlink($fname); |
||
68 | return true; |
||
69 | } |
||
70 | |||
71 | |||
72 | // purge all files older than $timelimit (in seconds) |
||
73 | // $mode = |
||
74 | // atime: age based on fileatime(). |
||
75 | // mtime: age based on filemtime(). |
||
76 | // all: delete all cached files. |
||
77 | function latexpurge($mode, $timelimit) |
||
78 | { |
||
79 | global $conf, $config_cascade; |
||
80 | $meddir = $conf['mediadir'] . '/' . strtr($this->getConf('latex_namespace'),':','/'); |
||
81 | $images = glob($meddir.'/img*'); |
||
82 | $this->_timelimit = $timelimit; |
||
83 | switch($mode) { |
||
84 | case 'atime': |
||
85 | $vio = array_map(array($this,'vio_atime'),$images); |
||
86 | break; |
||
87 | case 'mtime': |
||
88 | $vio = array_map(array($this,'vio_mtime'),$images); |
||
89 | break; |
||
90 | case 'all': |
||
91 | $vio = array_map(array($this,'vio_all'),$images); |
||
92 | break; |
||
93 | default: |
||
94 | return false; |
||
95 | } |
||
96 | return array_combine($images,$vio); |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * handle user request |
||
101 | */ |
||
102 | function handle() { |
||
103 | global $conf, $config_cascade; |
||
104 | $this->output = ""; |
||
105 | if(isset($_POST['latexpurge'])) |
||
106 | { |
||
107 | $mode = $_POST['purgemode']; |
||
108 | $days = $_POST['purgedays']; |
||
109 | if(is_numeric($days) && $days == 0) |
||
110 | $mode = 'all'; |
||
111 | if($mode == 'all') { |
||
112 | // If the admin wants to delete all of the images, probably it's good to print this reminder |
||
113 | // since they are likely doing it after changing the colour or something. |
||
114 | // (I don't know how many hours I spent trying to fix LaTeX heisenbugs that were just cached... grr.) |
||
115 | $this->output .= '<div class="info">'.$this->getLang('refresh_note').'</div>'; |
||
116 | } |
||
117 | $numdeleted = 0; |
||
118 | $numkept = 0; |
||
119 | $this->output .= "<pre>Purge result ([x] = deleted):\n"; |
||
120 | if($mode == 'all' || (is_numeric($days) && $days >= 0)) { |
||
121 | $res = $this->latexpurge($mode, $days*86400); |
||
122 | foreach($res as $img => $vio){ |
||
123 | if($vio) { |
||
124 | $this->output .= '[x] '.$img . "\n"; |
||
125 | $numdeleted += 1; |
||
126 | } else { |
||
127 | // $this->output .= '[ ] '.$img . "\n"; |
||
128 | $numkept += 1; |
||
129 | } |
||
130 | } |
||
131 | } else { |
||
132 | $this->output = "<div class=\"error\">Purger: Bad form inputs. No action taken.</div>".$this->output; |
||
133 | } |
||
134 | $this->output .= "Totals: $numdeleted deleted, $numkept kept (kept files not shown).\n"; |
||
135 | if ($numdeleted > 0) { |
||
136 | touch($config_cascade['main']['local']); |
||
137 | } |
||
138 | $this->output .= "</pre>"; |
||
139 | } |
||
140 | } |
||
141 | |||
142 | |||
143 | /** |
||
144 | * output appropriate html |
||
145 | */ |
||
146 | function html() { |
||
147 | global $ID,$INFO; |
||
148 | ptln('<p>'.$this->output.'</p>'); |
||
149 | ptln('<h1>LaTeX plugin administrator tasks</h1>'); |
||
150 | ptln('<h2>'.$this->getLang('legend_purge').'</h2>'); |
||
151 | ptln('<div class="level2">'); |
||
152 | |||
153 | ////////////// PURGE FORM |
||
154 | ptln('<form action="'.wl($INFO['id']).'?do=admin&page='.$this->getPluginName().'" method="post">'); |
||
155 | ptln('<table class="inline"><tr>'); |
||
156 | ptln('<td rowspan="2"><input type="submit" class="button" name="latexpurge" value="'.$this->getLang('btn_purge').'" /></td>'); |
||
157 | ptln('<TD>'); |
||
158 | $labtimes = $this->getLang('label_times'); |
||
159 | ptln('(<LABEL><INPUT type="radio" name="purgemode" value="atime" checked />'.$labtimes['atime'].'</LABEL>'); |
||
160 | ptln(' | <LABEL><INPUT type="radio" name="purgemode" value="mtime" />'.$labtimes['mtime'].'</LABEL>)'); |
||
161 | echo $this->getLang('label_olderthan'); |
||
162 | echo '<input type="text" name="purgedays" size="3" value="30">'; |
||
163 | echo $this->getLang('label_days'); |
||
164 | ptln('</TD><TR><TD>'); |
||
165 | echo '<LABEL><INPUT type="radio" name="purgemode" value="all" />'.$this->getLang('label_all').'</LABEL>'; |
||
166 | ptln('</TD></TR></TABLE>'); |
||
167 | ptln('</form>'); |
||
168 | |||
169 | ptln('</div>'); |
||
170 | |||
171 | /////////////// DIAGNOSER |
||
172 | ptln('<h2>LaTeX troubleshooter</h2>'); |
||
173 | ptln('<div class="level2">'); |
||
174 | ptln('<form action="'.wl($INFO['id']).'" method="get">'); |
||
175 | ptln(' <input type="hidden" name="do" value="admin" />'); |
||
176 | ptln(' <input type="hidden" name="page" value="'.$this->getPluginName().'" />'); |
||
177 | ptln('Push this button to diagnose your LaTeX/ImageMagick installation: <input type="submit" class="button" name="dotest" value="Test" /><br/>'); |
||
178 | ptln('<input type="checkbox" name="keep_tmp">Check this button to keep the temporary files used during compilation.</input><br/>'); |
||
179 | ptln('The following latex code will be inserted into the template and compiled:'); |
||
180 | ptln('<br />'); |
||
181 | if(isset($_REQUEST['testformula'])) |
||
182 | $testformula = $_REQUEST['testformula']; |
||
183 | else |
||
184 | $testformula = '$$\underbrace{{\it f}({\rm DokuWiki}) = \overbrace{[a+b=c]}^\textrm{\LaTeX}}_{Success!}$$'; |
||
185 | ptln(' <textarea cols=70 rows=6 type="text" name="testformula">'.htmlspecialchars($testformula).'</textarea>'); |
||
186 | ptln('</form>'); |
||
187 | ptln('</div>'); |
||
188 | if($_REQUEST['dotest']) { |
||
189 | ptln('<h3>Versions</h3>'); |
||
190 | ptln('<div class="level3">'); |
||
191 | ptln('This is a test of the acessibility of your programs and their versions.'); |
||
192 | ptln('<table class="inline">'); |
||
193 | ptln('<tr><th>command</th><th>output</th></tr>'); |
||
194 | foreach(array($this->getConf("latex_path"),$this->getConf("dvips_path"), |
||
195 | $this->getConf("convert_path"),$this->getConf("identify_path")) as $path) { |
||
196 | ptln('<tr><td><pre>'); |
||
197 | $cmd = $path." --version 2>&1"; |
||
198 | echo htmlspecialchars($cmd); |
||
199 | ptln('</pre></td><td>'); |
||
200 | unset($execout); |
||
201 | exec($cmd,$execout,$statuscode); |
||
202 | if($statuscode == 0) |
||
203 | echo '<pre>'; |
||
204 | else |
||
205 | echo '<pre style="background-color:#FCC;">'; //pink for error status |
||
206 | echo htmlspecialchars(implode(PHP_EOL,$execout)); |
||
207 | ptln('</pre></td></tr>'); |
||
208 | } |
||
209 | ptln('</table>'); |
||
210 | ptln('</div>'); |
||
211 | |||
212 | ptln('<h3>Test run</h3>'); |
||
213 | $plug = new syntax_plugin_latex_common(); |
||
214 | |||
215 | /// Directory sanity checks |
||
216 | if(is_writable($plug->_latex->getPicturePath()) && is_dir($plug->_latex->getPicturePath())) |
||
217 | ptln('<div class="success">Media directory is writable: <code>'.$plug->_latex->getPicturePath().'</code></div>'); |
||
218 | else |
||
219 | ptln('<div class="error">Media directory not writable or nonexistant! <code>'.$plug->_latex->getPicturePath().'</code> |
||
220 | <br />Recommendation: This media namespace must be writable on the file system.</div>'); |
||
221 | if(is_writable($plug->_latex->_tmp_dir) && is_dir($plug->_latex->_tmp_dir)) |
||
222 | ptln('<div class="success">Temporary directory is writable: <code>'.$plug->_latex->_tmp_dir.'</code></div>'); |
||
223 | else |
||
224 | ptln('<div class="error">Temporary directory not writable or nonexistant! <code>'.$plug->_latex->_tmp_dir.'</code> |
||
225 | <br />Recommendation: This media namespace must be writable on the file system.</div>'); |
||
226 | |||
227 | // simulate a call to the syntax plugin; force render, keep temp files. |
||
228 | $md5 = md5($testformula); |
||
229 | $outname = $plug->_latex->getPicturePath()."/img".$md5.'.'.$plug->_latex->_image_format; |
||
230 | if(file_exists($outname)) { |
||
231 | if(unlink($outname)) |
||
232 | ptln('<div class="info">Removed cache file for test: <code>'.$outname.'</code><br/> |
||
233 | <b>WARNING: You may need to refresh your browser\'s cache to see changes in the resulting image.</b></div>'); |
||
234 | else |
||
235 | ptln('<div class="error">Could not remove cached file for test! <code>'.$outname.'</code><br /> |
||
236 | the following tests will not work (renderer will just reuse the cached file)</div>'); |
||
237 | } |
||
238 | ptln('<div class="info">Attempting to render to target <code>'.$outname.'</code></div>'); |
||
239 | $plug->_latex->_keep_tmp = true; |
||
240 | $plug->_latex->_cmdoutput = ''; // activate command log. |
||
241 | $data = array($testformula,DOKU_LEXER_UNMATCHED,'class'=>"latex_inline", 'title'=>"Math", NULL); |
||
242 | $this->doc = ''; |
||
243 | $xhtml = new Doku_Renderer_xhtml(); |
||
244 | $plug->render('xhtml', $xhtml, $data); |
||
245 | $tmpw = $this->getConf('latex_namespace').':tmp:'.$plug->_latex->_tmp_filename; |
||
246 | $tmpf = $plug->_latex->_tmp_dir."/".$plug->_latex->_tmp_filename; |
||
247 | $tmpext = array('tex','log','aux','dvi','ps',$plug->_latex->_image_format); |
||
248 | foreach($tmpext as $ext) { |
||
249 | $fname = $tmpf.'.'.$ext; |
||
250 | if(is_file($fname)) { |
||
251 | if(isset($_REQUEST['keep_tmp'])) { |
||
252 | $rendstr = $plug->render('xhtml', $xhtml, '{{'.$tmpw.'.'.$ext.'?linkonly&nocache|'.$fname.'}}'); |
||
253 | $rendstr = preg_replace('/<\\/?p>/','',$rendstr); |
||
254 | } else |
||
255 | $rendstr = $fname; |
||
256 | ptln('<div class="success">File created: <code>'.$rendstr.'</code></div>'); |
||
257 | } else |
||
258 | ptln('<div class="error">File missing! <code>'.$fname.'</code></div>'); |
||
259 | } |
||
260 | if(! isset($_REQUEST['keep_tmp'])) |
||
261 | ptln('<div class="info">These files <code>'.$tmpf.'.*</code> will be deleted at the end of this script.</div>'); |
||
262 | if(is_file($outname)) |
||
263 | ptln('<div class="success">Successfully moved to media: <code>'.$outname.'</code></div>'); |
||
264 | else |
||
265 | ptln('<div class="error">File missing from media! <code>'.$outname.'</code></div>'); |
||
266 | |||
267 | ptln('<div class="level3">'); |
||
268 | ptln('<table class="inline"><tr><th>Input LaTeX file</th><th>Final result</th></tr>'); |
||
269 | ptln('<tr><td><pre>'); |
||
270 | if(is_readable($tmpf.'.tex') && is_file($tmpf.'.tex')) |
||
271 | echo htmlspecialchars(file_get_contents($tmpf.'.tex')); |
||
272 | else |
||
273 | echo 'MISSING'; |
||
274 | ptln('</pre></td><td>'); |
||
275 | // ptln(htmlspecialchars($plug->_url)); |
||
276 | // ptln('<br /><br />'); |
||
277 | ptln('<center>'); |
||
278 | ptln($this->doc); |
||
279 | ptln('</center></td></tr>'); |
||
280 | ptln('</table>'); |
||
281 | |||
282 | ptln('Command log:'); |
||
283 | echo '<pre>'; |
||
284 | echo $plug->_latex->_cmdoutput; |
||
285 | echo '</pre>'; |
||
286 | |||
287 | ptln('Contents of '.$tmpf.'.log:'); |
||
288 | echo '<pre>'; |
||
289 | echo htmlspecialchars(file_get_contents($tmpf.'.log')); |
||
290 | echo '</pre>'; |
||
291 | |||
292 | if(! isset($_REQUEST['keep_tmp'])) |
||
293 | $plug->_latex->cleanTemporaryDirectory(); |
||
294 | ptln('</div>'); |
||
295 | } |
||
296 | } |
||
297 | } |