MDL-11147:
[moodle-linuxchix.git] / filter / tex / texdebug.php
blobe4224ecd31e7a4432874c11b6962c302b5c263b8
1 <?PHP // $Id$
2 // This function fetches math. images from the data directory
3 // If not, it obtains the corresponding TeX expression from the cache_tex db table
4 // and uses mimeTeX to create the image file
6 $nomoodlecookie = true; // Because it interferes with caching
8 require_once("../../config.php");
9 require( 'latex.php' );
11 if (empty($CFG->textfilters)) {
12 error ('Filter not enabled!');
13 } else {
14 $filters = explode(',', $CFG->textfilters);
15 if (array_search('filter/tex', $filters) === FALSE) {
16 error ('Filter not enabled!');
20 $CFG->texfilterdir = "filter/tex";
21 $CFG->teximagedir = "filter/tex";
23 $param = null;
24 $param->action = optional_param( 'action','',PARAM_ALPHA );
25 $param->tex = optional_param( 'tex','' );
27 $query = urldecode($_SERVER['QUERY_STRING']);
28 error_reporting(E_ALL);
29 $output = '';
31 // look up in cache if required
32 if ($param->action=='ShowDB' or $param->action=='DeleteDB') {
33 $md5 = md5($param->tex);
34 $texcache = get_record("cache_filters","filter","tex", "md5key", $md5);
37 // Action: Show DB Entry
38 if ($param->action=='ShowDB') {
39 if ($texcache) {
40 $output = "DB cache_filters entry for $param->tex\n";
41 $output .= "id = $texcache->id\n";
42 $output .= "filter = $texcache->filter\n";
43 $output .= "version = $texcache->version\n";
44 $output .= "md5key = $texcache->md5key\n";
45 $output .= "rawtext = $texcache->rawtext\n";
46 $output .= "timemodified = $texcache->timemodified\n";
47 } else {
48 $output = "DB cache_filters entry for $param->tex not found\n";
52 // Action: Delete DB Entry
53 if ($param->action=='DeleteDB') {
54 if ($texcache) {
55 $output = "Deleting DB cache_filters entry for $param->tex\n";
56 $result = delete_records("cache_filters","id",$texcache->id);
57 if ($result) {
58 $result = 1;
59 } else {
60 $result = 0;
62 $output .= "Number of records deleted = $result\n";
63 } else {
64 $output = "Could not delete DB cache_filters entry for $param->tex\nbecause it could not be found.\n";
68 // Action: Show Image
69 if ($param->action=='ShowImageMimetex') {
70 tex2image($param->tex);
73 // Action: Check Slasharguments
74 if ($param->action=='SlashArguments') {
75 slasharguments($param->tex);
78 // Action: Show Tex command line output
79 if ($param->action=='ShowImageTex') {
80 TexOutput($param->tex, true);
81 exit;
84 // Action: Show Tex command line output
85 if ($param->action=='ShowOutputTex') {
86 TexOutput($param->tex);
87 exit;
90 if (!empty($param->action)) {
91 outputText($output);
94 // nothing more to do if there was any action
95 if (!empty($param->action)) {
96 exit;
100 function outputText($texexp) {
101 header("Content-type: text/html");
102 echo "<html><body><pre>\n";
103 if ($texexp) {
104 $texexp = str_replace('<','&lt;',$texexp);
105 $texexp = str_replace('>','&gt;',$texexp);
106 $texexp = str_replace('"','&quot;',$texexp);
107 echo "$texexp\n\n";
108 } else {
109 echo "No text output available\n\n";
111 echo "</pre></body></html>\n";
114 function tex2image($texexp, $return=false) {
115 global $CFG;
116 $error_message1 = "Your system is not configured to run mimeTeX. ";
117 $error_message1 .= "You need to download the appropriate<br /> executable ";
118 $error_message1 .= "from <a href=\"http://moodle.org/download/mimetex/\">";
119 $error_message1 .= "http://moodle.org/download/mimetex/</a>, or obtain the ";
120 $error_message1 .= "C source<br /> from <a href=\"http://www.forkosh.com/mimetex.zip\">";
121 $error_message1 .= "http://www.forkosh.com/mimetex.zip</a>, compile it and ";
122 $error_message1 .= "put the executable into your<br /> moodle/filter/tex/ directory. ";
123 $error_message1 .= "You also need to edit your moodle/filter/tex/pix.php file<br />";
124 $error_message1 .= ' by adding the line<br /><pre> case "' . PHP_OS . "\":\n";
125 $error_message1 .= " \$cmd = \"\\\\\"\$CFG->dirroot/\$CFG->texfilterdir/";
126 $error_message1 .= 'mimetex.' . strtolower(PHP_OS) . "\\\\\" -e \\\\\"\$pathname\\\\\" \". escapeshellarg(\$texexp);";
127 $error_message1 .= "</pre>You also need to add this to your texdebug.php file.";
129 if ($texexp) {
130 $texexp = '\Large ' . $texexp;
131 $lifetime = 86400;
132 $image = md5($texexp) . ".gif";
133 $filetype = 'image/gif';
134 if (!file_exists("$CFG->dataroot/$CFG->teximagedir")) {
135 make_upload_directory($CFG->teximagedir);
137 $pathname = "$CFG->dataroot/$CFG->teximagedir/$image";
138 if (file_exists($pathname)) {
139 unlink($pathname);
141 $commandpath = "";
142 $cmd = "";
143 $texexp = escapeshellarg($texexp);
144 switch (PHP_OS) {
145 case "Linux":
146 $commandpath="$CFG->dirroot/$CFG->texfilterdir/mimetex.linux";
147 $cmd = "\"$CFG->dirroot/$CFG->texfilterdir/mimetex.linux\" -e \"$pathname\" $texexp";
148 break;
149 case "WINNT":
150 case "WIN32":
151 case "Windows":
152 $commandpath="$CFG->dirroot/$CFG->texfilterdir/mimetex.exe";
153 $cmd = str_replace(' ','^ ',$commandpath);
154 $cmd .= " ++ -e \"$pathname\" $texexp";
155 break;
156 case "Darwin":
157 $commandpath="$CFG->dirroot/$CFG->texfilterdir/mimetex.darwin";
158 $cmd = "\"$CFG->dirroot/$CFG->texfilterdir/mimetex.darwin\" -e \"$pathname\" $texexp";
159 break;
161 if (!$cmd) {
162 if (is_executable("$CFG->dirroot/$CFG->texfilterdir/mimetex")) { /// Use the custom binary
163 $commandpath="$CFG->dirroot/$CFG->texfilterdir/mimetex";
164 $cmd = "$CFG->dirroot/$CFG->texfilterdir/mimetex -e $pathname $texexp";
165 } else {
166 error($error_message1);
169 system($cmd, $status);
171 if ($return) {
172 return $image;
174 if ($texexp && file_exists($pathname)) {
175 $lastmodified = filemtime($pathname);
176 header("Last-Modified: " . gmdate("D, d M Y H:i:s", $lastmodified) . " GMT");
177 header("Expires: " . gmdate("D, d M Y H:i:s", time() + $lifetime) . " GMT");
178 header("Cache-control: max_age = $lifetime"); // a day
179 header("Pragma: ");
180 header("Content-disposition: inline; filename=$image");
181 header("Content-length: ".filesize($pathname));
182 header("Content-type: $filetype");
183 readfile("$pathname");
184 } else {
185 $ecmd = "$cmd 2>&1";
186 echo `$ecmd` . "<br />\n";
187 echo "The shell command<br />$cmd<br />returned status = $status<br />\n";
188 if ($status == 4) {
189 echo "Status corresponds to illegal instruction<br />\n";
190 } else if ($status == 11) {
191 echo "Status corresponds to bus error<br />\n";
192 } else if ($status == 22) {
193 echo "Status corresponds to abnormal termination<br />\n";
195 if (file_exists($commandpath)) {
196 echo "File size of mimetex executable $commandpath is " . filesize($commandpath) . "<br />";
197 echo "The file permissions are: " . decoct(fileperms($commandpath)) . "<br />";
198 if (function_exists("md5_file")) {
199 echo "The md5 checksum of the file is " . md5_file($commandpath) . "<br />";
200 } else {
201 $handle = fopen($commandpath,"rb");
202 $contents = fread($handle,16384);
203 fclose($handle);
204 echo "The md5 checksum of the first 16384 bytes is " . md5($contents) . "<br />";
206 } else {
207 echo "mimetex executable $commandpath not found!<br />";
209 echo "Image not found!";
214 // test Tex/Ghostscript output - command execution only
215 function TexOutput( $expression, $graphic=false ) {
216 global $CFG;
217 $output = '';
219 $latex = new latex();
221 // first check if it is likely to work at all
222 $output .= "<h3>Checking executables</h3>\n";
223 $executables_exist = true;
224 if (is_file($CFG->filter_tex_pathlatex)) {
225 $output .= "latex executable ($CFG->filter_tex_pathlatex) is readable<br />\n";
227 else {
228 $executables_exist = false;
229 $output .= "<b>Error:</b> latex executable ($CFG->filter_tex_pathlatex) is not readable<br />\n";
231 if (is_file($CFG->filter_tex_pathdvips)) {
232 $output .= "dvips executable ($CFG->filter_tex_pathdvips) is readable<br />\n";
234 else {
235 $executables_exist = false;
236 $output .= "<b>Error:</b> dvips executable ($CFG->filter_tex_pathdvips) is not readable<br />\n";
238 if (is_file($CFG->filter_tex_pathconvert)) {
239 $output .= "convert executable ($CFG->filter_tex_pathconvert) is readable<br />\n";
241 else {
242 $executables_exist = false;
243 $output .= "<b>Error:</b> convert executable ($CFG->filter_tex_pathconvert) is not readable<br />\n";
246 // knowing that it might work..
247 $md5 = md5( $expression );
248 $output .= "<p>base filename for expression is '$md5'</p>\n";
250 // temporary paths
251 $tex = "$latex->temp_dir/$md5.tex";
252 $dvi = "$latex->temp_dir/$md5.dvi";
253 $ps = "$latex->temp_dir/$md5.ps";
254 $gif = "$latex->temp_dir/$md5.gif";
256 // put the expression as a file into the temp area
257 $doc = $latex->construct_latex_document( $expression );
258 $fh = fopen( $tex, 'w' );
259 fputs( $fh, $doc );
260 fclose( $fh );
262 // cd to temp dir
263 chdir( $latex->temp_dir );
265 // step 1: latex command
266 $cmd = "$CFG->filter_tex_pathlatex --interaction=nonstopmode $tex";
267 $output .= execute( $cmd );
269 // step 2: dvips command
270 $cmd = "$CFG->filter_tex_pathdvips -E $dvi -o $ps";
271 $output .= execute( $cmd );
273 // step 3: convert command
274 $cmd = "$CFG->filter_tex_pathconvert -density 240 -trim $ps $gif ";
275 $output .= execute( $cmd );
277 if (!$graphic) {
278 echo( $output );
279 } else {
280 $lastmodified = filemtime($gif);
281 $lifetime = 86400;
282 $filetype = 'image/gif';
283 $image = "$md5.gif";
284 header("Last-Modified: " . gmdate("D, d M Y H:i:s", $lastmodified) . " GMT");
285 header("Expires: " . gmdate("D, d M Y H:i:s", time() + $lifetime) . " GMT");
286 header("Cache-control: max_age = $lifetime"); // a day
287 header("Pragma: ");
288 header("Content-disposition: inline; filename=$image");
289 header("Content-length: ".filesize($gif));
290 header("Content-type: $filetype");
291 readfile("$gif");
295 function execute( $cmd ) {
296 exec( $cmd, $result, $code );
297 $output = "<pre>$ $cmd\n";
298 $lines = implode( "\n", $result );
299 $output .= "OUTPUT: $lines\n";
300 $output .= "RETURN CODE: $code\n</pre>\n";
301 return $output;
304 function slasharguments($texexp) {
305 global $CFG;
306 $admin = $CFG->wwwroot . '/' . $CFG->admin . '/config.php';
307 $image = tex2image($texexp,true);
308 echo "<p>If the following image displays correctly, set your ";
309 echo "<a href=\"$admin\" target=\"_blank\">Administration->Configuration->Variables</a> ";
310 echo "setting for slasharguments to file.php/1/pic.jpg: ";
311 echo "<img src=\"pix.php/$image\" align=\"absmiddle\"></p>\n";
312 echo "<p>Otherwise set it to file.php?file=/1/pic.jpg ";
313 echo "It should display correctly as ";
314 echo "<img src=\"pix.php?file=$image\" align=\"absmiddle\"></p>\n";
315 echo "<p>If neither equation image displays correctly, please seek ";
316 echo "further help at moodle.org at the ";
317 echo "<a href=\"http://moodle.org/mod/forum/view.php?id=752&username=guest\" target=\"_blank\">";
318 echo "Mathematics Tools Forum</a></p>";
323 <html>
324 <head><title>TeX Filter Debugger</title></head>
325 <body>
326 <p>Please enter an algebraic expression <b>without</b> any surrounding $$ into
327 the text box below. (Click <a href="#help">here for help.</a>)
328 <form action="texdebug.php" method="get"
329 target="inlineframe">
330 <center>
331 <input type="text" name="tex" size="50"
332 value="f(x)=\Bigint_{-\infty}^x~e^{-t^2}dt" />
333 </center>
334 <p>The following tests are available:</p>
335 <ol>
336 <li><input type="radio" name="action" value="ShowDB" />
337 See the cache_filters database entry for this expression (if any).</li>
338 <li><input type="radio" name="DeleteDB" value="DeleteDB" />
339 Delete the cache_filters database entry for this expression (if any).</li>
340 <li><input type="radio" name="action" value="ShowImageMimetex" />
341 Show a graphic image of the algebraic expression rendered with mimetex.</li>
342 <li><input type="radio" name="action" value="ShowImageTex" />
343 Show a graphic image of the algebraic expression rendered with Tex/Ghostscript.</li>
344 <li><input type="radio" name="action" value="ShowOutputTex" />
345 Show command execution output from the algebraic expression rendered with Tex/Ghostscript.</li>
346 <li><input type="radio" name="action" value="SlashArguments" />
347 Check slasharguments setting.</li>
348 </ol>
349 <input type="submit" value="Do it!" />
350 </form> <br /> <br />
351 <center>
352 <iframe name="inlineframe" align="middle" width="80%" height="200">
353 &lt;p&gt;Something is wrong...&lt;/p&gt;
354 </iframe>
355 </center> <br />
356 <hr />
357 <a name="help">
358 <h2>Debugging Help</h2>
359 </a>
360 <p>First a brief overview of how the TeX filter works. The TeX filter first
361 searches the database cache_filters table to see if this TeX expression had been
362 processed before. If not, it adds a DB entry for that expression. It then
363 replaces the TeX expression by an &lt;img src=&quot;.../filter/tex/pix.php...&quot;&gt;
364 tag. The filter/tex/pix.php script then searches the database to find an
365 appropriate gif image file for that expression and to create one if it doesn't exist.
366 It will then use either the LaTex/Ghostscript renderer (using external executables
367 on your system) or the bundled Mimetex executable. The full Latex/Ghostscript
368 renderer produces better results and is tried first.
369 Here are a few common things that can go wrong and some suggestions on how
370 you might try to fix them.</p>
371 <ol>
372 <li>Something had gone wrong on a previous occasion when the filter tried to
373 process this expression. Then the database entry for that expression contains
374 a bad TeX expression in the rawtext field (usually blank). You can fix this
375 by clicking on &quot;Delete DB Entry&quot;</li>
376 <li>The TeX to gif image conversion process does not work.
377 If paths are specified in the filter configuation screen for the three
378 executables these will be tried first. Note that they still must be correctly
379 installed and have the correct permissions. In particular make sure that you
380 have all the packages installed (e.g., on Debian/Ubuntu you need to install
381 the 'tetex-extra' package). Running the 'show command execution' test should
382 give a big clue.
383 If this fails or is not available, the Mimetex executable is tried. If this
384 fails a likely cause is that the mimetex binary you are using is
385 incompatible with your operating system. You can try compiling it from the
386 C sources downloaded from <a href="http://www.forkosh.com/mimetex.zip">
387 http://www.forkosh.com/mimetex.zip</a>, or looking for an appropriate
388 binary at <a href="http://moodle.org/download/mimetex/">
389 http://moodle.org/download/mimetex/</a>. You may then also need to
390 edit your moodle/filter/tex/pix.php file to add
391 <br /><?PHP echo "case &quot;" . PHP_OS . "&quot;:" ;?><br ?> to the list of operating systems
392 in the switch (PHP_OS) statement. Windows users may have a problem properly
393 unzipping mimetex.exe. Make sure that mimetex.exe is is <b>PRECISELY</b>
394 433152 bytes in size. If not, download a fresh copy from
395 <a href="http://moodle.org/download/mimetex/windows/mimetex.exe">
396 http://moodle.org/download/mimetex/windows/mimetex.exe</a>.
397 Another possible problem which may affect
398 both Unix and Windows servers is that the web server doesn't have execute permission
399 on the mimetex binary. In that case change permissions accordingly</li>
400 </ol>
401 </body>
402 </html>