Merge branch 'MDL-33122-master' of git://github.com/ankitagarwal/moodle
[moodle.git] / filter / tex / texdebug.php
blob35f1afb4642f516aedc41a249f488e3215d2d71b
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * This function fetches math. images from the data directory
19 * If not, it obtains the corresponding TeX expression from the cache_tex db table
20 * and uses mimeTeX to create the image file
22 * @package filter
23 * @subpackage tex
24 * @copyright 2004 Zbigniew Fiedorowicz fiedorow@math.ohio-state.edu
25 * Originally based on code provided by Bruno Vernier bruno@vsbeducation.ca
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 require_once("../../config.php");
31 if (!filter_is_enabled('filter/tex')) {
32 print_error('filternotenabled');
35 require_once($CFG->libdir.'/filelib.php');
36 require_once($CFG->dirroot.'/filter/tex/lib.php');
37 require_once($CFG->dirroot.'/filter/tex/latex.php');
39 $action = optional_param('action', '', PARAM_ALPHA);
40 $texexp = optional_param('tex', '', PARAM_RAW);
42 require_login();
43 require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM), $USER->id); /// Required cap to run this. MDL-18552
45 $output = '';
47 // look up in cache if required
48 if ($action=='ShowDB' or $action=='DeleteDB') {
49 $md5 = md5($texexp);
50 $texcache = $DB->get_record("cache_filters", array("filter"=>"tex", "md5key"=>$md5));
53 // Action: Show DB Entry
54 if ($action=='ShowDB') {
55 if ($texcache) {
56 $output = "DB cache_filters entry for $texexp\n";
57 $output .= "id = $texcache->id\n";
58 $output .= "filter = $texcache->filter\n";
59 $output .= "version = $texcache->version\n";
60 $output .= "md5key = $texcache->md5key\n";
61 $output .= "rawtext = $texcache->rawtext\n";
62 $output .= "timemodified = $texcache->timemodified\n";
63 } else {
64 $output = "DB cache_filters entry for $texexp not found\n";
68 // Action: Delete DB Entry
69 if ($action=='DeleteDB') {
70 if ($texcache) {
71 $output = "Deleting DB cache_filters entry for $texexp\n";
72 $result = $DB->delete_records("cache_filters", array("id"=>$texcache->id));
73 if ($result) {
74 $result = 1;
75 } else {
76 $result = 0;
78 $output .= "Number of records deleted = $result\n";
79 } else {
80 $output = "Could not delete DB cache_filters entry for $texexp\nbecause it could not be found.\n";
84 // Action: Show Image
85 if ($action=='ShowImageMimetex') {
86 tex2image($texexp);
89 // Action: Check Slasharguments
90 if ($action=='SlashArguments') {
91 slasharguments($texexp);
94 // Action: Show Tex command line output
95 if ($action=='ShowImageTex') {
96 TexOutput($texexp, true);
97 exit;
100 // Action: Show Tex command line output
101 if ($action=='ShowOutputTex') {
102 if (debugging()) {
103 TexOutput($texexp);
104 } else {
105 echo "Can not output detailed information due to security concerns, please turn on debug mode first.";
107 exit;
110 if (!empty($action)) {
111 outputText($output);
114 // nothing more to do if there was any action
115 if (!empty($action)) {
116 exit;
120 function outputText($texexp) {
121 header("Content-type: text/html; charset=utf-8");
122 echo "<html><body><pre>\n";
123 if ($texexp) {
124 echo s($texexp)."\n\n";
125 } else {
126 echo "No text output available\n\n";
128 echo "</pre></body></html>\n";
131 function tex2image($texexp, $return=false) {
132 global $CFG;
134 if (!$texexp) {
135 echo 'No tex expresion specified';
136 return;
139 $image = md5($texexp) . ".gif";
140 $filetype = 'image/gif';
141 if (!file_exists("$CFG->dataroot/filter/tex")) {
142 make_upload_directory("filter/tex");
144 $pathname = "$CFG->dataroot/filter/tex/$image";
145 if (file_exists($pathname)) {
146 unlink($pathname);
149 $texexp = '\Large '.$texexp;
150 $commandpath = filter_tex_get_executable(true);
151 $cmd = filter_tex_get_cmd($pathname, $texexp);
152 system($cmd, $status);
154 if ($return) {
155 return $image;
158 if (file_exists($pathname)) {
159 send_file($pathname, $image);
161 } else if (debugging()) {
162 $ecmd = "$cmd 2>&1";
163 echo `$ecmd` . "<br />\n";
164 echo "The shell command<br />$cmd<br />returned status = $status<br />\n";
165 if ($status == 4) {
166 echo "Status corresponds to illegal instruction<br />\n";
167 } else if ($status == 11) {
168 echo "Status corresponds to bus error<br />\n";
169 } else if ($status == 22) {
170 echo "Status corresponds to abnormal termination<br />\n";
172 if (file_exists($commandpath)) {
173 echo "File size of mimetex executable $commandpath is " . filesize($commandpath) . "<br />";
174 echo "The file permissions are: " . decoct(fileperms($commandpath)) . "<br />";
175 if (function_exists("md5_file")) {
176 echo "The md5 checksum of the file is " . md5_file($commandpath) . "<br />";
177 } else {
178 $handle = fopen($commandpath,"rb");
179 $contents = fread($handle,16384);
180 fclose($handle);
181 echo "The md5 checksum of the first 16384 bytes is " . md5($contents) . "<br />";
183 } else {
184 echo "mimetex executable $commandpath not found!<br />";
186 echo "Image not found!";
187 } else {
188 echo "Can not output detailed information due to security concerns, please turn on debug mode first.";
193 // test Tex/Ghostscript output - command execution only
194 function TexOutput($expression, $graphic=false) {
195 global $CFG;
196 $output = '';
198 $latex = new latex();
200 // first check if it is likely to work at all
201 $output .= "<h3>Checking executables</h3>\n";
202 $executables_exist = true;
203 if (is_file($CFG->filter_tex_pathlatex)) {
204 $output .= "latex executable ($CFG->filter_tex_pathlatex) is readable<br />\n";
206 else {
207 $executables_exist = false;
208 $output .= "<b>Error:</b> latex executable ($CFG->filter_tex_pathlatex) is not readable<br />\n";
210 if (is_file($CFG->filter_tex_pathdvips)) {
211 $output .= "dvips executable ($CFG->filter_tex_pathdvips) is readable<br />\n";
213 else {
214 $executables_exist = false;
215 $output .= "<b>Error:</b> dvips executable ($CFG->filter_tex_pathdvips) is not readable<br />\n";
217 if (is_file($CFG->filter_tex_pathconvert)) {
218 $output .= "convert executable ($CFG->filter_tex_pathconvert) is readable<br />\n";
220 else {
221 $executables_exist = false;
222 $output .= "<b>Error:</b> convert executable ($CFG->filter_tex_pathconvert) is not readable<br />\n";
225 // knowing that it might work..
226 $md5 = md5($expression);
227 $output .= "<p>base filename for expression is '$md5'</p>\n";
229 // temporary paths
230 $tex = "$latex->temp_dir/$md5.tex";
231 $dvi = "$latex->temp_dir/$md5.dvi";
232 $ps = "$latex->temp_dir/$md5.ps";
233 $img = "$latex->temp_dir/$md5.{$CFG->filter_tex_convertformat}";
235 // put the expression as a file into the temp area
236 $expression = html_entity_decode($expression);
237 $output .= "<p>Processing TeX expression:</p><pre>$expression</pre>\n";
238 $doc = $latex->construct_latex_document($expression);
239 $fh = fopen($tex, 'w');
240 fputs($fh, $doc);
241 fclose($fh);
243 // cd to temp dir
244 chdir($latex->temp_dir);
246 // step 1: latex command
247 $cmd = "$CFG->filter_tex_pathlatex --interaction=nonstopmode $tex";
248 $output .= execute($cmd);
250 // step 2: dvips command
251 $cmd = "$CFG->filter_tex_pathdvips -E $dvi -o $ps";
252 $output .= execute($cmd);
254 // step 3: convert command
255 $cmd = "$CFG->filter_tex_pathconvert -density 240 -trim $ps $img ";
256 $output .= execute($cmd);
258 if (!$graphic) {
259 echo $output;
260 } else if (file_exists($img)){
261 send_file($img, "$md5.{$CFG->filter_tex_convertformat}");
262 } else {
263 echo "Error creating image, see command execution output for more details.";
267 function execute($cmd) {
268 exec($cmd, $result, $code);
269 $output = "<pre>$ $cmd\n";
270 $lines = implode("\n", $result);
271 $output .= "OUTPUT: $lines\n";
272 $output .= "RETURN CODE: $code\n</pre>\n";
273 return $output;
276 function slasharguments($texexp) {
277 global $CFG;
278 $admin = $CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=http';
279 $image = tex2image($texexp,true);
280 echo "<p>If the following image displays correctly, set your ";
281 echo "<a href=\"$admin\" target=\"_blank\">Administration->Server->HTTP</a> ";
282 echo "setting for slasharguments to file.php/1/pic.jpg: ";
283 echo "<img src=\"$CFG->wwwroot/filter/tex/pix.php/$image\" align=\"absmiddle\"></p>\n";
284 echo "<p>Otherwise set it to file.php?file=/1/pic.jpg ";
285 echo "It should display correctly as ";
286 echo "<img src=\"$CFG->wwwroot/filter/tex/pix.php?file=$image\" align=\"absmiddle\"></p>\n";
287 echo "<p>If neither equation image displays correctly, please seek ";
288 echo "further help at moodle.org at the ";
289 echo "<a href=\"http://moodle.org/mod/forum/view.php?id=752&loginguest=true\" target=\"_blank\">";
290 echo "Mathematics Tools Forum</a></p>";
295 <html>
296 <head><title>TeX Filter Debugger</title></head>
297 <body>
298 <p>Please enter an algebraic expression <b>without</b> any surrounding $$ into
299 the text box below. (Click <a href="#help">here for help.</a>)
300 <form action="texdebug.php" method="get"
301 target="inlineframe">
302 <center>
303 <input type="text" name="tex" size="50"
304 value="f(x)=\int_{-\infty}^x~e^{-t^2}dt" />
305 </center>
306 <p>The following tests are available:</p>
307 <ol>
308 <li><input type="radio" name="action" value="ShowDB" id="ShowDB" />
309 <label for="ShowDB">See the cache_filters database entry for this expression (if any).</label></li>
310 <li><input type="radio" name="action" value="DeleteDB" id="DeleteDB" />
311 <label for="DeleteDB">Delete the cache_filters database entry for this expression (if any).</label></li>
312 <li><input type="radio" name="action" value="ShowImageMimetex" id="ShowImageMimetex" checked="checked" />
313 <label for="ShowImageMimetex">Show a graphic image of the algebraic expression rendered with mimetex.</label></li>
314 <li><input type="radio" name="action" value="ShowImageTex" id="ShowImageTex" />
315 <label for="ShowImageTex">Show a graphic image of the algebraic expression rendered with Tex/Ghostscript.</label></li>
316 <li><input type="radio" name="action" value="ShowOutputTex" id="ShowOutputTex" />
317 <label for="ShowOutputTex">Show command execution output from the algebraic expression rendered with Tex/Ghostscript.</label></li>
318 <li><input type="radio" name="action" value="SlashArguments" id="SlashArguments" />
319 <label for="SlashArguments">Check slasharguments setting.</label></li>
320 </ol>
321 <input type="submit" value="Do it!" />
322 </form> <br /> <br />
323 <center>
324 <iframe name="inlineframe" align="middle" width="80%" height="200">
325 &lt;p&gt;Something is wrong...&lt;/p&gt;
326 </iframe>
327 </center> <br />
328 <hr />
329 <a name="help">
330 <h2>Debugging Help</h2>
331 </a>
332 <p>First a brief overview of how the TeX filter works. The TeX filter first
333 searches the database cache_filters table to see if this TeX expression had been
334 processed before. If not, it adds a DB entry for that expression. It then
335 replaces the TeX expression by an &lt;img src=&quot;.../filter/tex/pix.php...&quot;&gt;
336 tag. The filter/tex/pix.php script then searches the database to find an
337 appropriate gif/png image file for that expression and to create one if it doesn't exist.
338 It will then use either the LaTex/Ghostscript renderer (using external executables
339 on your system) or the bundled Mimetex executable. The full Latex/Ghostscript
340 renderer produces better results and is tried first.
341 Here are a few common things that can go wrong and some suggestions on how
342 you might try to fix them.</p>
343 <ol>
344 <li>Something had gone wrong on a previous occasion when the filter tried to
345 process this expression. Then the database entry for that expression contains
346 a bad TeX expression in the rawtext field (usually blank). You can fix this
347 by clicking on &quot;Delete DB Entry&quot;</li>
348 <li>The TeX to gif/png image conversion process does not work.
349 If paths are specified in the filter configuation screen for the three
350 executables these will be tried first. Note that they still must be correctly
351 installed and have the correct permissions. In particular make sure that you
352 have all the packages installed (e.g., on Debian/Ubuntu you need to install
353 the 'tetex-extra' package). Running the 'show command execution' test should
354 give a big clue.
355 If this fails or is not available, the Mimetex executable is tried. If this
356 fails a likely cause is that the mimetex binary you are using is
357 incompatible with your operating system. You can try compiling it from the
358 C sources downloaded from <a href="http://www.forkosh.com/mimetex.zip">
359 http://www.forkosh.com/mimetex.zip</a>, or looking for an appropriate
360 binary at <a href="http://moodle.org/download/mimetex/">
361 http://moodle.org/download/mimetex/</a>. You may then also need to
362 edit your moodle/filter/tex/pix.php file to add
363 <br /><?PHP echo "case &quot;" . PHP_OS . "&quot;:" ;?><br ?> to the list of operating systems
364 in the switch (PHP_OS) statement. Windows users may have a problem properly
365 unzipping mimetex.exe. Make sure that mimetex.exe is is <b>PRECISELY</b>
366 433152 bytes in size. If not, download a fresh copy from
367 <a href="http://moodle.org/download/mimetex/windows/mimetex.exe">
368 http://moodle.org/download/mimetex/windows/mimetex.exe</a>.
369 Another possible problem which may affect
370 both Unix and Windows servers is that the web server doesn't have execute permission
371 on the mimetex binary. In that case change permissions accordingly</li>
372 </ol>
373 </body>
374 </html>