1<?php 2/** 3 * LaTeX Rendering Class 4 * 5 * Primary Author: Wizardry and Steamworks <wizardry.steamworks@outlook.com> 6 * Original Author: Benjamin Zeiss <zeiss@math.uni-goettingen.de> 7 * 8 * @license GPL 2 9 */ 10 11class LatexRender { 12 protected $_picture_path = ""; 13 protected $_picture_path_httpd = ""; 14 protected $_tmp_dir = ""; 15 16 public $_keep_tmp = false; 17 public $_latex_path = "latex"; 18 public $_dvips_path = "dvips"; 19 public $_convert_path = "convert"; 20 public $_identify_path = "identify"; 21 public $_xsize_limit = 1000; 22 public $_ysize_limit = 500; 23 public $_string_length_limit = 2000; 24 public $_image_format = "png"; 25 public $_font_size = 10; 26 public $_latexclass = "article"; 27 public $_tmp_filename; 28 public $_latex_tags_blacklist = []; 29 public $_errorcode = 0; 30 public $_errorextra = ""; 31 public $_filename; 32 public $_cmdoutput = ""; 33 public $_preamble = ""; 34 public $_postamble = ""; 35 36 public function __construct($picture_path, $picture_path_httpd, $tmp_dir) { 37 $this->_picture_path = $picture_path; 38 $this->_picture_path_httpd = $picture_path_httpd; 39 $this->_tmp_dir = $tmp_dir; 40 } 41 42 public function getPicturePath() { return $this->_picture_path; } 43 public function getPicturePathHTTPD() { return $this->_picture_path_httpd; } 44 45 public function getFormulaURL($latex_formula) { 46 $latex_formula = str_ireplace(['>', '<'], ['>', '<'], $latex_formula); 47 $this->latex_document = $this->_preamble . "\n" . trim($latex_formula) . "\n" . $this->_postamble; 48 49 $formula_hash = md5($latex_formula); 50 $filename = "img" . $formula_hash . '.' . $this->_image_format; 51 $full_path_filename = $this->getPicturePath() . "/" . $filename; 52 $this->_filename = $full_path_filename; 53 54 if (is_readable($full_path_filename)) { 55 return $this->getPicturePathHTTPD() . "/" . $filename; 56 } 57 58 if (strlen($latex_formula) > $this->_string_length_limit) { 59 $this->_errorcode = 1; 60 $this->_errorextra = ': ' . strlen($latex_formula); 61 return false; 62 } 63 64 foreach ($this->_latex_tags_blacklist as $tag) { 65 if (stristr($latex_formula, $tag)) { 66 $this->_errorcode = 2; 67 return false; 68 } 69 } 70 71 if ($this->renderLatex($this->latex_document, $full_path_filename)) { 72 return $this->getPicturePathHTTPD() . $filename; 73 } 74 75 return false; 76 } 77 78 protected function getDimensions($filename) { 79 $output = $this->myexec($this->_identify_path . " " . escapeshellarg($filename), $status); 80 $result = explode(" ", $output); 81 if (!isset($result[2])) return ["x" => 0, "y" => 0]; 82 $dim = explode("x", $result[2]); 83 return ["x" => (int)$dim[0], "y" => (int)$dim[1]]; 84 } 85 86 public function renderLatex($latex_document, $destination) { 87 $current_dir = getcwd(); 88 if (!is_dir($this->_tmp_dir)) return false; 89 chdir($this->_tmp_dir); 90 91 $this->_tmp_filename = md5(uniqid(rand(), true)); 92 file_put_contents($this->_tmp_filename . ".tex", $latex_document); 93 94 $this->myexec($this->_latex_path . " --interaction=nonstopmode " . $this->_tmp_filename . ".tex", $status_latex); 95 96 if (!file_exists($this->_tmp_filename . ".dvi")) { 97 if (!$this->_keep_tmp) $this->cleanTemporaryDirectory(); 98 chdir($current_dir); 99 $this->_errorcode = 4; 100 return false; 101 } 102 103 $this->myexec($this->_dvips_path . " " . $this->_tmp_filename . ".dvi -o " . $this->_tmp_filename . ".ps", $status_dvips); 104 $this->myexec($this->_convert_path . " " . $this->_tmp_filename . ".ps " . $this->_tmp_filename . "." . $this->_image_format, $status_convert); 105 106 if ($status_dvips || $status_convert) { 107 if (!$this->_keep_tmp) $this->cleanTemporaryDirectory(); 108 chdir($current_dir); 109 $this->_errorcode = 6; 110 return false; 111 } 112 113 $dim = $this->getDimensions($this->_tmp_filename . "." . $this->_image_format); 114 if ($dim["x"] > $this->_xsize_limit || $dim["y"] > $this->_ysize_limit) { 115 if (!$this->_keep_tmp) $this->cleanTemporaryDirectory(); 116 chdir($current_dir); 117 $this->_errorcode = 5; 118 $this->_errorextra = ": " . $dim["x"] . "x" . $dim["y"]; 119 return false; 120 } 121 122 $status_code = copy($this->_tmp_filename . "." . $this->_image_format, $destination); 123 chdir($current_dir); 124 125 if (!$this->_keep_tmp) $this->cleanTemporaryDirectory(); 126 if (!$status_code) { $this->_errorcode = 7; return false; } 127 128 return true; 129 } 130 131 protected function myexec($cmd, &$status) { 132 $cmd = "$cmd 2>&1"; 133 $lastline = exec($cmd, $output, $status); 134 $this->_cmdoutput .= "\n>>>>> $cmd\n" . trim(implode(PHP_EOL, $output)) . PHP_EOL . " --- exit status " . $status; 135 return $lastline; 136 } 137 138 public function cleanTemporaryDirectory() { 139 foreach (['tex', 'aux', 'log', 'dvi', 'ps', $this->_image_format] as $ext) { 140 @unlink($this->_tmp_dir . "/" . $this->_tmp_filename . "." . $ext); 141 } 142 } 143} 144