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!');
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";
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
);
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') {
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";
48 $output = "DB cache_filters entry for $param->tex not found\n";
52 // Action: Delete DB Entry
53 if ($param->action
=='DeleteDB') {
55 $output = "Deleting DB cache_filters entry for $param->tex\n";
56 $result = delete_records("cache_filters","id",$texcache->id
);
62 $output .= "Number of records deleted = $result\n";
64 $output = "Could not delete DB cache_filters entry for $param->tex\nbecause it could not be found.\n";
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);
84 // Action: Show Tex command line output
85 if ($param->action
=='ShowOutputTex') {
86 TexOutput($param->tex
);
90 if (!empty($param->action
)) {
94 // nothing more to do if there was any action
95 if (!empty($param->action
)) {
100 function outputText($texexp) {
101 header("Content-type: text/html");
102 echo "<html><body><pre>\n";
104 $texexp = str_replace('<','<',$texexp);
105 $texexp = str_replace('>','>',$texexp);
106 $texexp = str_replace('"','"',$texexp);
109 echo "No text output available\n\n";
111 echo "</pre></body></html>\n";
114 function tex2image($texexp, $return=false) {
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.";
130 $texexp = '\Large ' . $texexp;
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)) {
143 $texexp = escapeshellarg($texexp);
146 $commandpath="$CFG->dirroot/$CFG->texfilterdir/mimetex.linux";
147 $cmd = "\"$CFG->dirroot/$CFG->texfilterdir/mimetex.linux\" -e \"$pathname\" $texexp";
152 $commandpath="$CFG->dirroot/$CFG->texfilterdir/mimetex.exe";
153 $cmd = str_replace(' ','^ ',$commandpath);
154 $cmd .= " ++ -e \"$pathname\" $texexp";
157 $commandpath="$CFG->dirroot/$CFG->texfilterdir/mimetex.darwin";
158 $cmd = "\"$CFG->dirroot/$CFG->texfilterdir/mimetex.darwin\" -e \"$pathname\" $texexp";
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";
166 error($error_message1);
169 system($cmd, $status);
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
180 header("Content-disposition: inline; filename=$image");
181 header("Content-length: ".filesize($pathname));
182 header("Content-type: $filetype");
183 readfile("$pathname");
186 echo `
$ecmd`
. "<br />\n";
187 echo "The shell command<br />$cmd<br />returned status = $status<br />\n";
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 />";
201 $handle = fopen($commandpath,"rb");
202 $contents = fread($handle,16384);
204 echo "The md5 checksum of the first 16384 bytes is " . md5($contents) . "<br />";
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 ) {
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";
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";
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";
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";
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 $expression = html_entity_decode( $expression );
258 $output .= "<p>Processing TeX expression:</p><pre>$expression</pre>\n";
259 $doc = $latex->construct_latex_document( $expression );
260 $fh = fopen( $tex, 'w' );
265 chdir( $latex->temp_dir
);
267 // step 1: latex command
268 $cmd = "$CFG->filter_tex_pathlatex --interaction=nonstopmode $tex";
269 $output .= execute( $cmd );
271 // step 2: dvips command
272 $cmd = "$CFG->filter_tex_pathdvips -E $dvi -o $ps";
273 $output .= execute( $cmd );
275 // step 3: convert command
276 $cmd = "$CFG->filter_tex_pathconvert -density 240 -trim $ps $gif ";
277 $output .= execute( $cmd );
282 $lastmodified = filemtime($gif);
284 $filetype = 'image/gif';
286 header("Last-Modified: " . gmdate("D, d M Y H:i:s", $lastmodified) . " GMT");
287 header("Expires: " . gmdate("D, d M Y H:i:s", time() +
$lifetime) . " GMT");
288 header("Cache-control: max_age = $lifetime"); // a day
290 header("Content-disposition: inline; filename=$image");
291 header("Content-length: ".filesize($gif));
292 header("Content-type: $filetype");
297 function execute( $cmd ) {
298 exec( $cmd, $result, $code );
299 $output = "<pre>$ $cmd\n";
300 $lines = implode( "\n", $result );
301 $output .= "OUTPUT: $lines\n";
302 $output .= "RETURN CODE: $code\n</pre>\n";
306 function slasharguments($texexp) {
308 $admin = $CFG->wwwroot
. '/' . $CFG->admin
. '/config.php';
309 $image = tex2image($texexp,true);
310 echo "<p>If the following image displays correctly, set your ";
311 echo "<a href=\"$admin\" target=\"_blank\">Administration->Configuration->Variables</a> ";
312 echo "setting for slasharguments to file.php/1/pic.jpg: ";
313 echo "<img src=\"pix.php/$image\" align=\"absmiddle\"></p>\n";
314 echo "<p>Otherwise set it to file.php?file=/1/pic.jpg ";
315 echo "It should display correctly as ";
316 echo "<img src=\"pix.php?file=$image\" align=\"absmiddle\"></p>\n";
317 echo "<p>If neither equation image displays correctly, please seek ";
318 echo "further help at moodle.org at the ";
319 echo "<a href=\"http://moodle.org/mod/forum/view.php?id=752&username=guest\" target=\"_blank\">";
320 echo "Mathematics Tools Forum</a></p>";
326 <head
><title
>TeX Filter Debugger
</title
></head
>
328 <p
>Please enter an algebraic expression
<b
>without
</b
> any surrounding $$ into
329 the text box below
. (Click
<a href
="#help">here
for help
.</a
>)
330 <form action
="texdebug.php" method
="get"
331 target
="inlineframe">
333 <input type
="text" name
="tex" size
="50"
334 value
="f(x)=\Bigint_{-\infty}^x~e^{-t^2}dt" />
336 <p
>The following tests are available
:</p
>
338 <li
><input type
="radio" name
="action" value
="ShowDB" />
339 See the cache_filters database entry
for this
expression (if any
).</li
>
340 <li
><input type
="radio" name
="DeleteDB" value
="DeleteDB" />
341 Delete the cache_filters database entry
for this
expression (if any
).</li
>
342 <li
><input type
="radio" name
="action" value
="ShowImageMimetex" />
343 Show a graphic image of the algebraic expression rendered with mimetex
.</li
>
344 <li
><input type
="radio" name
="action" value
="ShowImageTex" />
345 Show a graphic image of the algebraic expression rendered with Tex
/Ghostscript
.</li
>
346 <li
><input type
="radio" name
="action" value
="ShowOutputTex" />
347 Show command execution output from the algebraic expression rendered with Tex
/Ghostscript
.</li
>
348 <li
><input type
="radio" name
="action" value
="SlashArguments" />
349 Check slasharguments setting
.</li
>
351 <input type
="submit" value
="Do it!" />
352 </form
> <br
/> <br
/>
354 <iframe name
="inlineframe" align
="middle" width
="80%" height
="200">
355 <
;p
>
;Something is wrong
...<
;/p
>
;
360 <h2
>Debugging Help
</h2
>
362 <p
>First a brief overview of how the TeX filter works
. The TeX filter first
363 searches the database cache_filters table to see
if this TeX expression had been
364 processed before
. If not
, it adds a DB entry
for that expression
. It then
365 replaces the TeX expression by an
<
;img src
="
;.../filter
/tex
/pix
.php
..."
;>
;
366 tag
. The filter
/tex
/pix
.php script then searches the database to find an
367 appropriate gif image file
for that expression
and to create one
if it doesn
't exist.
368 It will then use either the LaTex/Ghostscript renderer (using external executables
369 on your system) or the bundled Mimetex executable. The full Latex/Ghostscript
370 renderer produces better results and is tried first.
371 Here are a few common things that can go wrong and some suggestions on how
372 you might try to fix them.</p>
374 <li>Something had gone wrong on a previous occasion when the filter tried to
375 process this expression. Then the database entry for that expression contains
376 a bad TeX expression in the rawtext field (usually blank). You can fix this
377 by clicking on "Delete DB Entry"</li>
378 <li>The TeX to gif image conversion process does not work.
379 If paths are specified in the filter configuation screen for the three
380 executables these will be tried first. Note that they still must be correctly
381 installed and have the correct permissions. In particular make sure that you
382 have all the packages installed (e.g., on Debian/Ubuntu you need to install
383 the 'tetex
-extra
' package). Running the 'show command execution
' test should
385 If this fails or is not available, the Mimetex executable is tried. If this
386 fails a likely cause is that the mimetex binary you are using is
387 incompatible with your operating system. You can try compiling it from the
388 C sources downloaded from <a href="http://www.forkosh.com/mimetex.zip">
389 http://www.forkosh.com/mimetex.zip</a>, or looking for an appropriate
390 binary at <a href="http://moodle.org/download/mimetex/">
391 http://moodle.org/download/mimetex/</a>. You may then also need to
392 edit your moodle/filter/tex/pix.php file to add
393 <br /><?PHP echo "case "" . PHP_OS . "":" ;?><br ?> to the list of operating systems
394 in the switch (PHP_OS) statement. Windows users may have a problem properly
395 unzipping mimetex.exe. Make sure that mimetex.exe is is <b>PRECISELY</b>
396 433152 bytes in size. If not, download a fresh copy from
397 <a href="http://moodle.org/download/mimetex/windows/mimetex.exe">
398 http://moodle.org/download/mimetex/windows/mimetex.exe</a>.
399 Another possible problem which may affect
400 both Unix and Windows servers is that the web server doesn't have execute permission
401 on the mimetex binary
. In that
case change permissions accordingly
</li
>