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