Post 1.9.8 bump
[moodle.git] / filter / tex / texdebug.php
blob356edab4e0131d1e2fd0826f3fab87310bd30dd7
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 require_once("../../config.php");
8 if (empty($CFG->textfilters)) {
9 error ('Filter not enabled!');
10 } else {
11 $filters = explode(',', $CFG->textfilters);
12 if (array_search('filter/tex', $filters) === FALSE) {
13 error ('Filter not enabled!');
17 require_once($CFG->libdir.'/filelib.php');
18 require_once($CFG->dirroot.'/filter/tex/lib.php');
19 require_once($CFG->dirroot.'/filter/tex/latex.php');
21 $action = optional_param('action', '', PARAM_ALPHA);
22 $texexp = optional_param('tex', '', PARAM_RAW);
24 require_login();
25 require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM), $USER->id); /// Required cap to run this. MDL-18552
27 $query = urldecode($_SERVER['QUERY_STRING']);
28 error_reporting(E_ALL);
29 $output = '';
31 // look up in cache if required
32 if ($action=='ShowDB' or $action=='DeleteDB') {
33 $md5 = md5($texexp);
34 $texcache = get_record("cache_filters","filter","tex", "md5key", $md5);
37 // Action: Show DB Entry
38 if ($action=='ShowDB') {
39 if ($texcache) {
40 $output = "DB cache_filters entry for $texexp\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 $texexp not found\n";
52 // Action: Delete DB Entry
53 if ($action=='DeleteDB') {
54 if ($texcache) {
55 $output = "Deleting DB cache_filters entry for $texexp\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 $texexp\nbecause it could not be found.\n";
68 // Action: Show Image
69 if ($action=='ShowImageMimetex') {
70 tex2image($texexp);
73 // Action: Check Slasharguments
74 if ($action=='SlashArguments') {
75 slasharguments($texexp);
78 // Action: Show Tex command line output
79 if ($action=='ShowImageTex') {
80 TexOutput($texexp, true);
81 exit;
84 // Action: Show Tex command line output
85 if ($action=='ShowOutputTex') {
86 if (debugging()) {
87 TexOutput($texexp);
88 } else {
89 echo "Can not output detailed information due to security concerns, please turn on debug mode first.";
91 exit;
94 if (!empty($action)) {
95 outputText($output);
98 // nothing more to do if there was any action
99 if (!empty($action)) {
100 exit;
104 function outputText($texexp) {
105 header("Content-type: text/html");
106 echo "<html><body><pre>\n";
107 if ($texexp) {
108 $texexp = str_replace('<', '&lt;', $texexp);
109 $texexp = str_replace('>', '&gt;', $texexp);
110 $texexp = str_replace('"', '&quot;', $texexp);
111 echo "$texexp\n\n";
112 } else {
113 echo "No text output available\n\n";
115 echo "</pre></body></html>\n";
118 function tex2image($texexp, $return=false) {
119 global $CFG;
121 if (!$texexp) {
122 echo 'No tex expresion specified';
123 return;
126 $image = md5($texexp) . ".gif";
127 $filetype = 'image/gif';
128 if (!file_exists("$CFG->dataroot/filter/tex")) {
129 make_upload_directory("filter/tex");
131 $pathname = "$CFG->dataroot/filter/tex/$image";
132 if (file_exists($pathname)) {
133 unlink($pathname);
136 $texexp = '\Large '.$texexp;
137 $commandpath = tex_filter_get_executable(true);
138 $cmd = tex_filter_get_cmd($pathname, $texexp);
139 system($cmd, $status);
141 if ($return) {
142 return $image;
145 if (file_exists($pathname)) {
146 send_file($pathname, $image);
148 } else if (debugging()) {
149 $ecmd = "$cmd 2>&1";
150 echo `$ecmd` . "<br />\n";
151 echo "The shell command<br />$cmd<br />returned status = $status<br />\n";
152 if ($status == 4) {
153 echo "Status corresponds to illegal instruction<br />\n";
154 } else if ($status == 11) {
155 echo "Status corresponds to bus error<br />\n";
156 } else if ($status == 22) {
157 echo "Status corresponds to abnormal termination<br />\n";
159 if (file_exists($commandpath)) {
160 echo "File size of mimetex executable $commandpath is " . filesize($commandpath) . "<br />";
161 echo "The file permissions are: " . decoct(fileperms($commandpath)) . "<br />";
162 if (function_exists("md5_file")) {
163 echo "The md5 checksum of the file is " . md5_file($commandpath) . "<br />";
164 } else {
165 $handle = fopen($commandpath,"rb");
166 $contents = fread($handle,16384);
167 fclose($handle);
168 echo "The md5 checksum of the first 16384 bytes is " . md5($contents) . "<br />";
170 } else {
171 echo "mimetex executable $commandpath not found!<br />";
173 echo "Image not found!";
174 } else {
175 echo "Can not output detailed information due to security concerns, please turn on debug mode first.";
180 // test Tex/Ghostscript output - command execution only
181 function TexOutput($expression, $graphic=false) {
182 global $CFG;
183 $output = '';
185 $latex = new latex();
187 // first check if it is likely to work at all
188 $output .= "<h3>Checking executables</h3>\n";
189 $executables_exist = true;
190 if (is_file($CFG->filter_tex_pathlatex)) {
191 $output .= "latex executable ($CFG->filter_tex_pathlatex) is readable<br />\n";
193 else {
194 $executables_exist = false;
195 $output .= "<b>Error:</b> latex executable ($CFG->filter_tex_pathlatex) is not readable<br />\n";
197 if (is_file($CFG->filter_tex_pathdvips)) {
198 $output .= "dvips executable ($CFG->filter_tex_pathdvips) is readable<br />\n";
200 else {
201 $executables_exist = false;
202 $output .= "<b>Error:</b> dvips executable ($CFG->filter_tex_pathdvips) is not readable<br />\n";
204 if (is_file($CFG->filter_tex_pathconvert)) {
205 $output .= "convert executable ($CFG->filter_tex_pathconvert) is readable<br />\n";
207 else {
208 $executables_exist = false;
209 $output .= "<b>Error:</b> convert executable ($CFG->filter_tex_pathconvert) is not readable<br />\n";
212 // knowing that it might work..
213 $md5 = md5($expression);
214 $output .= "<p>base filename for expression is '$md5'</p>\n";
216 // temporary paths
217 $tex = "$latex->temp_dir/$md5.tex";
218 $dvi = "$latex->temp_dir/$md5.dvi";
219 $ps = "$latex->temp_dir/$md5.ps";
220 $gif = "$latex->temp_dir/$md5.gif";
222 // put the expression as a file into the temp area
223 $expression = stripslashes($expression);
224 $expression = html_entity_decode($expression);
225 $output .= "<p>Processing TeX expression:</p><pre>$expression</pre>\n";
226 $doc = $latex->construct_latex_document($expression);
227 $fh = fopen($tex, 'w');
228 fputs($fh, $doc);
229 fclose($fh);
231 // cd to temp dir
232 chdir($latex->temp_dir);
234 // step 1: latex command
235 $cmd = "$CFG->filter_tex_pathlatex --interaction=nonstopmode $tex";
236 $output .= execute($cmd);
238 // step 2: dvips command
239 $cmd = "$CFG->filter_tex_pathdvips -E $dvi -o $ps";
240 $output .= execute($cmd);
242 // step 3: convert command
243 $cmd = "$CFG->filter_tex_pathconvert -density 240 -trim $ps $gif ";
244 $output .= execute($cmd);
246 if (!$graphic) {
247 echo($output);
248 } else {
249 send_file($gif, "$md5.gif");
253 function execute($cmd) {
254 exec($cmd, $result, $code);
255 $output = "<pre>$ $cmd\n";
256 $lines = implode("\n", $result);
257 $output .= "OUTPUT: $lines\n";
258 $output .= "RETURN CODE: $code\n</pre>\n";
259 return $output;
262 function slasharguments($texexp) {
263 global $CFG;
264 $admin = $CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=http';
265 $image = tex2image($texexp,true);
266 echo "<p>If the following image displays correctly, set your ";
267 echo "<a href=\"$admin\" target=\"_blank\">Administration->Server->HTTP</a> ";
268 echo "setting for slasharguments to file.php/1/pic.jpg: ";
269 echo "<img src=\"$CFG->wwwroot/filter/tex/pix.php/$image\" align=\"absmiddle\"></p>\n";
270 echo "<p>Otherwise set it to file.php?file=/1/pic.jpg ";
271 echo "It should display correctly as ";
272 echo "<img src=\"$CFG->wwwroot/filter/tex/pix.php?file=$image\" align=\"absmiddle\"></p>\n";
273 echo "<p>If neither equation image displays correctly, please seek ";
274 echo "further help at moodle.org at the ";
275 echo "<a href=\"http://moodle.org/mod/forum/view.php?id=752&loginguest=true\" target=\"_blank\">";
276 echo "Mathematics Tools Forum</a></p>";
281 <html>
282 <head><title>TeX Filter Debugger</title></head>
283 <body>
284 <p>Please enter an algebraic expression <b>without</b> any surrounding $$ into
285 the text box below. (Click <a href="#help">here for help.</a>)
286 <form action="texdebug.php" method="get"
287 target="inlineframe">
288 <center>
289 <input type="text" name="tex" size="50"
290 value="f(x)=\Bigint_{-\infty}^x~e^{-t^2}dt" />
291 </center>
292 <p>The following tests are available:</p>
293 <ol>
294 <li><input type="radio" name="action" value="ShowDB" id="ShowDB" />
295 <label for="ShowDB">See the cache_filters database entry for this expression (if any).</label></li>
296 <li><input type="radio" name="DeleteDB" value="DeleteDB" id="DeleteDB" />
297 <label for="DeleteDB">Delete the cache_filters database entry for this expression (if any).</label></li>
298 <li><input type="radio" name="action" value="ShowImageMimetex" id="ShowImageMimetex" checked="checked" />
299 <label for="ShowImageMimetex">Show a graphic image of the algebraic expression rendered with mimetex.</label></li>
300 <li><input type="radio" name="action" value="ShowImageTex" id="ShowImageTex" />
301 <label for="ShowImageTex">Show a graphic image of the algebraic expression rendered with Tex/Ghostscript.</label></li>
302 <li><input type="radio" name="action" value="ShowOutputTex" id="ShowOutputTex" />
303 <label for="ShowOutputTex">Show command execution output from the algebraic expression rendered with Tex/Ghostscript.</label></li>
304 <li><input type="radio" name="action" value="SlashArguments" id="SlashArguments" />
305 <label for="SlashArguments">Check slasharguments setting.</label></li>
306 </ol>
307 <input type="submit" value="Do it!" />
308 </form> <br /> <br />
309 <center>
310 <iframe name="inlineframe" align="middle" width="80%" height="200">
311 &lt;p&gt;Something is wrong...&lt;/p&gt;
312 </iframe>
313 </center> <br />
314 <hr />
315 <a name="help">
316 <h2>Debugging Help</h2>
317 </a>
318 <p>First a brief overview of how the TeX filter works. The TeX filter first
319 searches the database cache_filters table to see if this TeX expression had been
320 processed before. If not, it adds a DB entry for that expression. It then
321 replaces the TeX expression by an &lt;img src=&quot;.../filter/tex/pix.php...&quot;&gt;
322 tag. The filter/tex/pix.php script then searches the database to find an
323 appropriate gif image file for that expression and to create one if it doesn't exist.
324 It will then use either the LaTex/Ghostscript renderer (using external executables
325 on your system) or the bundled Mimetex executable. The full Latex/Ghostscript
326 renderer produces better results and is tried first.
327 Here are a few common things that can go wrong and some suggestions on how
328 you might try to fix them.</p>
329 <ol>
330 <li>Something had gone wrong on a previous occasion when the filter tried to
331 process this expression. Then the database entry for that expression contains
332 a bad TeX expression in the rawtext field (usually blank). You can fix this
333 by clicking on &quot;Delete DB Entry&quot;</li>
334 <li>The TeX to gif image conversion process does not work.
335 If paths are specified in the filter configuation screen for the three
336 executables these will be tried first. Note that they still must be correctly
337 installed and have the correct permissions. In particular make sure that you
338 have all the packages installed (e.g., on Debian/Ubuntu you need to install
339 the 'tetex-extra' package). Running the 'show command execution' test should
340 give a big clue.
341 If this fails or is not available, the Mimetex executable is tried. If this
342 fails a likely cause is that the mimetex binary you are using is
343 incompatible with your operating system. You can try compiling it from the
344 C sources downloaded from <a href="http://www.forkosh.com/mimetex.zip">
345 http://www.forkosh.com/mimetex.zip</a>, or looking for an appropriate
346 binary at <a href="http://moodle.org/download/mimetex/">
347 http://moodle.org/download/mimetex/</a>. You may then also need to
348 edit your moodle/filter/tex/pix.php file to add
349 <br /><?PHP echo "case &quot;" . PHP_OS . "&quot;:" ;?><br ?> to the list of operating systems
350 in the switch (PHP_OS) statement. Windows users may have a problem properly
351 unzipping mimetex.exe. Make sure that mimetex.exe is is <b>PRECISELY</b>
352 433152 bytes in size. If not, download a fresh copy from
353 <a href="http://moodle.org/download/mimetex/windows/mimetex.exe">
354 http://moodle.org/download/mimetex/windows/mimetex.exe</a>.
355 Another possible problem which may affect
356 both Unix and Windows servers is that the web server doesn't have execute permission
357 on the mimetex binary. In that case change permissions accordingly</li>
358 </ol>
359 </body>
360 </html>