/[drupal]/contributions/modules/drutex/drutex_remote.inc
ViewVC logotype

Contents of /contributions/modules/drutex/drutex_remote.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.4 - (show annotations) (download) (as text)
Wed Jan 9 12:33:53 2008 UTC (22 months, 2 weeks ago) by darthsteven
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5--2, DRUPAL-5, DRUPAL-6--1
Changes since 1.3: +6 -6 lines
File MIME type: text/x-php
#190613, bug, reported by: mennonot
Call-time pass-by-reference, not need so removed.
1 <?php
2 // $Id: drutex_remote.inc,v 1.3 2007/09/09 18:57:38 darthsteven Exp $
3
4 /**
5 * @file
6 * Provide environments to remotely render maths and/or arbitrary TeX.
7 */
8
9 /**
10 * Implementation of subhook_info().
11 */
12 function drutex_remote_info($format = -1) {
13 return (object) array(
14 'title' => t('Remote LaTeX Renderer'),
15 'description' => t('Provides different environments to create rendered (remotely) images (especially maths).'),
16 'toggle' => true,
17 'weight' => 2
18 );
19 }
20
21 /**
22 * Implementation of subhook_defaults().
23 */
24 function drutex_remote_defaults() {
25 $D['drutex_remote_active'] = false;
26 return $D;
27 }
28
29 /**
30 * Implementation of subhook_node2html().
31 */
32 function drutex_remote_node2html() {
33 $E = array();
34
35 /* Plain TeX environment */
36 $E[] = (object) array(
37 'pattern' => '@<tex( [^>]*)?>(.+?)</tex>@se',
38 'replacement' => "drutex_remote('$2', '<var>format</var>', '$1', 'tag=\"span\" class=\"plaintex\"')",
39 'weight' => -10
40 );
41
42 /* <equation> environment */
43 $E[] = (object) array(
44 'pattern' => '@<equation( [^>]*)?>(.+?)</equation>@se',
45 'replacement' => "drutex_remote('\[ $2 \]', '<var>format</var>', '$1', 'tag=\"table\" class=\"displaymath\"')",
46 'weight' => -7
47 );
48
49 /* <equations> environment */
50 $E[] = (object) array(
51 'pattern' => '@<equations( [^>]*)?>(.+?)</equations>@se',
52 'replacement' => "drutex_remote('\begin{align*} $2 \end{align*}', '<var>format</var>', '$1', 'tag=\"table\" class=\"displaymath\"')",
53 'weight' => -6
54 );
55
56 /* Paragraph math between $$ and $$ */
57 $E[] = (object) array(
58 'pattern' => '@(^|[^\\\\])(\$\$.*?[^\\\\]\$\$)@se',
59 'replacement' => "'$1' . drutex_remote('$2', '<var>format</var>', '', 'tag=\"table\" class=\"displaymath\"')",
60 'weight' => -5
61 );
62
63 /* Paragraph math between \[ and \] */
64 $E[] = (object) array(
65 'pattern' => '@\\\\\\[(.+?)\\\\\\]@se',
66 'replacement' => "drutex_remote('$0', '<var>format</var>', '', 'tag=\"table\" class=\"displaymath\"')",
67 'weight' => -5
68 );
69
70 /* Inline math (display style) between $! and $ */
71 $E[] = (object) array(
72 'pattern' => '@(^|[^\\\\])\$!(.*?[^\\\\])\$@se',
73 'replacement' => "'$1' . drutex_remote('$\displaystyle $2 $', '<var>format</var>')",
74 'weight' => -4
75 );
76
77 /* Inline math between $ and $ */
78 $E[] = (object) array(
79 'pattern' => '@(^|[^\\\\])\$(.*?[^\\\\])\$@se',
80 'replacement' => "'$1' . drutex_remote('$ $2 $', '<var>format</var>')",
81 'weight' => -3
82 );
83
84 /* unescape escaped dollar signs */
85 $E[] = (object) array(
86 'pattern' => '@\\\\\\$@s',
87 'replacement' => '$',
88 'weight' => 1000 /* very late */
89 );
90
91 return $E;
92 }
93
94 /**
95 * Implementation of subhook_filter_settings().
96 */
97 function drutex_remote_filter_settings($format = -1) {
98 $form = array();
99
100 $form["drutex_server_remote_$format"] = array(
101 '#type' => 'textfield',
102 '#title' => t('Remote server path'),
103 '#description' => t('The address of the remote server that will do the rendering. Should include the path to the script that will complete the rendering, i.e. end in drutex/render'),
104 '#default_value' => drutex_var_get("drutex_server_remote_$format"),
105 );
106
107 $form["drutex_dpi_remote_$format"] = array(
108 '#type' => 'textfield',
109 '#title' => t('Resolution (DPI)'),
110 '#size' => 15,
111 '#maxlength' => 3,
112 '#default_value' => drutex_var_get("drutex_dpi_remote_$format"),
113 '#description' => t('100 is small, 107 is default, 115 is big')
114 );
115
116 return $form;
117 }
118
119 /**
120 * Renders $text in LaTeX.
121 */
122 function drutex_remote($text, $format = -1, $attributes = '', $default_attributes = '') {
123
124 $text = _drutex_unescape($text);
125
126 if (drutex_submodule_is_active('security', $format)) {
127 if (drutex_security($text, $format) == false) {
128 return '<em class="error">Unallowed command detected!</em>';
129 }
130 }
131
132 $attributes = drutex_parse_attributes(_drutex_unescape($attributes));
133 $default_attributes = drutex_parse_attributes($default_attributes);
134 $attributes = array_merge($default_attributes, $attributes);
135
136
137 $image_dir = drutex_var_get("drutex_dir_images_$format");
138
139 $dpi = drutex_var_get("drutex_dpi_remote_$format");
140
141 if (!empty($attributes['dpi']) AND is_numeric($attributes['dpi']) AND $attributes['dpi'] > 0) {
142 $dpi = $attributes['dpi'];
143 }
144
145 $image_type = drutex_var_get("drutex_imagetype_$format");
146
147 $hash = sha1($text . $displaystyle . $dpi);
148 $image_file = "$image_dir/$hash.$image_type";
149
150
151 $success = TRUE;
152
153 if (!is_file($image_file)) {
154
155 // Need to curl to the remote url, sending the variables $text, $dpi, $displaystyle
156 $data = array(
157 'text' => $text,
158 'dpi' => $dpi,
159 'displaystyle' => $displaystyle,
160 );
161 $response = drupal_http_request(
162 drutex_var_get("drutex_server_remote_$format"),
163 array('Content-Type' => 'application/x-www-form-urlencoded'),
164 'POST',
165 http_build_query($data,'','&'));
166 if ($response->code == 200) {
167 // We get the image back from the server.
168 $errorcode = file_save_data($response->data, $image_file, FILE_EXISTS_REPLACE);
169 }
170 elseif ($response->code == 403) {
171 watchdog('DruTeX', 'The remote server denied the request to render LaTeX', WATCHDOG_WARNING);
172 }
173 elseif ($response->code == 404) {
174 watchdog('DruTeX', 'The remote server doesn\'t appear to have the renderer installed.', WATCHDOG_WARNING);
175 }
176 else {
177 watchdog('DruTeX', 'Unknown response ('. $response->code .') from the remote server when rendering LaTeX', WATCHDOG_WARNING);
178 }
179 }
180 $success = is_file($image_file);
181 if (drutex_var_get("drutex_debug")) {
182 if ($success) {
183 watchdog('DruTeX', "$image_file was created remotely and saved locally.", WATCHDOG_NOTICE);
184 }
185 else {
186 watchdog('DruTeX', "$image_file couldn\'t be created remotely.", WATCHDOG_WARNING);
187 }
188 }
189
190 $img_url = drutex_get_image_url($format) . "/$hash.$image_type";
191
192 if ($success) {
193 $img_alt = _drutex_hide('set', check_plain($text));
194 $res = "<img class=\"teximage\" src=\"$img_url\" alt=\"$img_alt\" />";
195 }
196 else {
197 $res = '<em class="error">TeX Embedding failed!</em>';
198 }
199
200 if (!empty($attributes['tag'])) {
201 $class_attr = empty($attributes['class']) ? '' : " class=\"{$attributes['class']}\"";
202
203 if (!empty($attributes['id'])) {
204 $id = $attributes['id'];
205 $anchor = "<a name=\"$id\" id=\"$id\"></a>";
206 }
207 else {
208 $anchor = '';
209 }
210
211 if ($attributes['tag'] == 'table') {
212 $name = _drutex_references('get name by id', $attributes['id']);
213 $name = empty($name) ? '' : "($name)";
214 $res = "<table{$class_attr}><tr><td class=\"dspleft\">{$anchor}{$res}</td><td class=\"dspright\">{$name}</td></tr></table>";
215 }
216 else {
217 $tag = $attributes['tag'];
218 $res = "<{$tag}{$class_attr}>{$res}</{$tag}>";
219 }
220 }
221
222
223 return $res;
224 }
225
226 if(!function_exists('http_build_query')) {
227 function http_build_query($data,$prefix=null,$sep='',$key='') {
228 $ret = array();
229 foreach($data as $k => $v) {
230 $k = urlencode($k);
231 if(is_int($k) && $prefix != null) {
232 $k = $prefix.$k;
233 };
234 if(!empty($key)) {
235 $k = $key."[".$k."]";
236 };
237 if(is_array($v) || is_object($v)) {
238 array_push($ret,http_build_query($v,"",$sep,$k));
239 }
240 else {
241 array_push($ret,$k."=".urlencode($v));
242 };
243 };
244 if(empty($sep)) {
245 $sep = ini_get("arg_separator.output");
246 };
247 return implode($sep, $ret);
248 };
249 };
250
251 function drutex_remote_do_render() {
252
253 if (variable_get('drutex_remote_rendering_enabled',0) == 1) {
254 // Check the incoming ip:
255 //Wilcard character is an asterix, *
256 $ip_allow = explode("\n",variable_get('drutex_remote_allowed_ips',''));
257
258 function ip_first($ips) {
259 if (($pos = strpos($ips, ',')) != false) {
260 return substr($ips, 0, $pos);
261 }
262 else {
263 return $ips;
264 }
265 }
266
267 function ip_valid($ips) {
268 if (isset($ips)) {
269 $ip = ip_first($ips);
270 $ipnum = ip2long($ip);
271 if ($ipnum !== -1 && $ipnum !== false && (long2ip($ipnum) === $ip)) { // PHP 4 and PHP 5
272 if (($ipnum < 167772160 || $ipnum > 184549375) && // Not in 10.0.0.0/8
273 ($ipnum < -1408237568 || $ipnum > -1407188993) && // Not in 172.16.0.0/12
274 ($ipnum < -1062731776 || $ipnum > -1062666241)) { // Not in 192.168.0.0/16
275 return true;
276 }
277 }
278 }
279 return false;
280 }
281
282 function ip() {
283 $check = array('HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED',
284 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED',
285 'HTTP_VIA', 'HTTP_X_COMING_FROM', 'HTTP_COMING_FROM'
286 );
287 foreach ($check as $c) {
288 if (ip_valid($_SERVER[$c])) {
289 return ip_first($_SERVER[$c]);
290 }
291 }
292 return $_SERVER['REMOTE_ADDR'];
293 }
294
295 $ip = ip();
296
297 $allowed_to_run = FALSE;
298
299 if(in_array($ip, $ip_allow)) {
300 $allowed_to_run = TRUE;
301 }
302 else {
303 foreach($ip_allow as $allow) {
304 if (trim($allow) != '') {
305 if(eregi($allow, $ip)) {
306 $allowed_to_run = TRUE;
307 }
308 }
309 }
310 }
311
312
313 if ($allowed_to_run) {
314 // Get the variable and do the render:
315 $text = $_REQUEST['text'];
316 $dpi = $_REQUEST['dpi'];
317 $template_dir = drutex_var_get('drutex_dir') . '/templates/render';
318 $template_file = variable_get('drutex_remote_render_template', 'default.tex');
319 $template = $template_dir . '/' . $template_file;
320 $hash = sha1('latex_image'. $text . $dpi);
321 $temporary_dir = _drutex_create_temporary_dir();
322 $image_file = $temporary_dir .'/'. $hash .'.png';
323
324 /* conversion method */
325 $conversion = variable_get('drutex_remote_render_conversion', 'dvipng');
326
327 /* command patterns */
328 $pattern_convert = variable_get('drutex_remote_render_custom_pattern', '');
329
330 /* replacement arrays */
331 $map = array('[TMP_DIR]' => $temporary_dir, '[IMG_FILE]' => $image_file,
332 '[DPI]' => $dpi, '[HASH]' => $hash,
333 '[DRUTEX_DIR]' => drutex_var_get('drutex_dir')
334 );
335
336 /* conversion commands (seperated by \n) */
337 $cmd_convert = str_replace(array_keys($map), $map, $pattern_convert);
338
339 /* load the appropriate template ... */
340 $handle = fopen($template, 'r');
341 $content = fread($handle, filesize($template));
342 fclose($handle);
343
344 /* ... and put the $text in there */
345 $content = str_replace('DRUTEX_REPLACE', $text, $content);
346
347 /* write $content to file, for LaTeX to read an render it */
348 file_save_data($content, "$temporary_dir/$hash.tex", FILE_EXISTS_REPLACE);
349
350 /* invoke all conversion commands */
351 $commands = explode("\n", $cmd_convert);
352
353 foreach ($commands as $cmd) {
354 $cmd = trim($cmd);
355 if ($cmd) {
356 exec($cmd, $cmd_output, $cmd_retval);
357 }
358 }
359
360 $success = is_file($image_file);
361
362 if ($success) {
363 // Transfer file in 1024 byte chunks to save memory usage.
364 if ($fd = fopen($image_file, 'rb')) {
365 while (!feof($fd)) {
366 print fread($fd, 1024);
367 }
368 fclose($fd);
369 }
370 else {
371 drupal_not_found();
372 }
373 }
374 /* remove temporary dir */
375 if (!drutex_var_get("drutex_debug")) {
376 _drutex_delete_dir($temporary_dir);
377 }
378 else {
379 if ($success) {
380 watchdog('DruTeX', "$image_file was created. Temporary directory was $temporary_dir.", WATCHDOG_NOTICE);
381 }
382 else {
383 watchdog('DruTeX', "$image_file couldn't be created. Temporary directory was $temporary_dir.", WATCHDOG_WARNING);
384 }
385 }
386
387 }
388 else {
389 // Not an allowed ip:
390 drupal_access_denied();
391 }
392
393 }
394 else {
395 // Rendering disabled:
396 drupal_access_denied();
397 }
398
399 exit();
400
401 }
402
403 function drutex_remote_settings() {
404 /* conversion methods */
405 $conversions = array('dvipng' => 'dvipng',
406 'imagemagick' => 'ImageMagick (convert)',
407 'custom' => 'custom');
408 $form = array();
409
410 $form['remote_fieldset'] = array(
411 '#type' => 'fieldset',
412 '#title' => t('Remote rendering settings'),
413 '#collapsible' => true,
414 );
415
416 $form['remote_fieldset']['drutex_remote_rendering_enabled'] = array(
417 '#type' => 'checkbox',
418 '#title' => t('Allow remote LaTeX rendering on THIS server'),
419 '#default_value' => variable_get('drutex_remote_rendering_enabled',0),
420 );
421
422 $form['remote_fieldset']['drutex_remote_allowed_ips'] = array(
423 '#type' => 'textarea',
424 '#title' => t('Allowed remote IPs'),
425 '#description' => t('Put the address of each remote IP that is allowed to render LaTeX on this server.'."<br />".'Put each address on a new line.'."<br />".'You may use * as a wildcard character.'."<br />".'e.g. 10.0.0.5, or 192.168.*.*'),
426 '#default_value' => variable_get('drutex_remote_allowed_ips',''),
427 );
428
429
430 /* determine whether temporary dir is writeable */
431 $is_writable = is_writable(drutex_var_get('drutex_dir_temporary'));
432
433 $form['remote_fieldset']['drutex_dir_temporary'] = array(
434 '#type' => 'textfield',
435 '#title' => t('Temporary directory'),
436 '#size' => 80,
437 '#maxlength' => 100,
438 '#default_value' => drutex_var_get('drutex_dir_temporary'),
439 '#description' => t('Directory for temporaray actions. Has to be writable by apache.'),
440 '#attributes' => $is_writable ? array() : array('style' => 'border-color:red')
441 );
442
443
444
445 $form['remote_fieldset']['drutex_remote_render_template'] = array(
446 '#type' => 'select',
447 '#title' => t('Template'),
448 '#options' => _drutex_get_templates(),
449 '#default_value' => variable_get('drutex_remote_render_template', 'default.tex')
450 );
451
452 $form['remote_fieldset']['drutex_remote_render_conversion'] = array(
453 '#type' => 'select',
454 '#title' => t('Conversion Method'),
455 '#options' => $conversions,
456 '#default_value' => variable_get('drutex_remote_render_conversion', 'dvipng')
457 );
458
459 /* Custom Conversion Method */
460
461 /* determine default value for <custom conversion method> */
462 $default_value = variable_get('drutex_remote_render_custom_pattern', 'cd [TMP_DIR]; TEXINPUTS="[DRUTEX_DIR]//:" latex -interaction=batchmode [HASH].tex'."\n".
463 'dvipng -o [IMG_FILE] -D [DPI] -T tight [TMP_DIR]/[HASH].dvi');
464
465 /* description for <custom conversion method> */
466 $description = t('* Leave blank and select dvipng or ImageMagick, to display a template for one of these commands in this box.') . '<br />'
467 . t('* Every line is executed in sequence, but in its own shell (so path changes aren\'t inherited).') . '<br />'
468 . t('Placeholders available:<br />
469 [HASH] - hash (name) for the image<br />
470 [TMP_DIR] - temporary dir (automatically cleaned)<br />
471 [DPI] - dots per inch (see above)<br />
472 [IMG_FILE] - abbreviation for [TMP_DIR]/[HASH].png<br />
473 [DRUTEX_DIR] - full path to DruTeX base dir');
474
475
476 $form['remote_fieldset']['drutex_remote_render_custom_pattern'] = array(
477 '#type' => 'textarea',
478 '#title' => t('Conversion Method (Custom)'),
479 '#rows' => 3,
480 '#cols' => 50,
481 '#default_value' => $default_value,
482 '#description' => $description
483 );
484
485 return system_settings_form($form);
486
487 }

  ViewVC Help
Powered by ViewVC 1.1.2