* Original Author: Benjamin Zeiss * * @license GPL 2 */ class LatexRender { protected $_picture_path = ""; protected $_picture_path_httpd = ""; protected $_tmp_dir = ""; public $_keep_tmp = false; public $_latex_path = "latex"; public $_dvips_path = "dvips"; public $_convert_path = "convert"; public $_identify_path = "identify"; public $_xsize_limit = 1000; public $_ysize_limit = 500; public $_string_length_limit = 2000; public $_image_format = "png"; public $_font_size = 10; public $_latexclass = "article"; public $_tmp_filename; public $_latex_tags_blacklist = []; public $_errorcode = 0; public $_errorextra = ""; public $_filename; public $_cmdoutput = ""; public $_preamble = ""; public $_postamble = ""; public function __construct($picture_path, $picture_path_httpd, $tmp_dir) { $this->_picture_path = $picture_path; $this->_picture_path_httpd = $picture_path_httpd; $this->_tmp_dir = $tmp_dir; } public function getPicturePath() { return $this->_picture_path; } public function getPicturePathHTTPD() { return $this->_picture_path_httpd; } public function getFormulaURL($latex_formula) { $latex_formula = str_ireplace(['>', '<'], ['>', '<'], $latex_formula); $this->latex_document = $this->_preamble . "\n" . trim($latex_formula) . "\n" . $this->_postamble; $formula_hash = md5($latex_formula); $filename = "img" . $formula_hash . '.' . $this->_image_format; $full_path_filename = $this->getPicturePath() . "/" . $filename; $this->_filename = $full_path_filename; if (is_readable($full_path_filename)) { return $this->getPicturePathHTTPD() . "/" . $filename; } if (strlen($latex_formula) > $this->_string_length_limit) { $this->_errorcode = 1; $this->_errorextra = ': ' . strlen($latex_formula); return false; } foreach ($this->_latex_tags_blacklist as $tag) { if (stristr($latex_formula, $tag)) { $this->_errorcode = 2; return false; } } if ($this->renderLatex($this->latex_document, $full_path_filename)) { return $this->getPicturePathHTTPD() . $filename; } return false; } protected function getDimensions($filename) { $output = $this->myexec($this->_identify_path . " " . escapeshellarg($filename), $status); $result = explode(" ", $output); if (!isset($result[2])) return ["x" => 0, "y" => 0]; $dim = explode("x", $result[2]); return ["x" => (int)$dim[0], "y" => (int)$dim[1]]; } public function renderLatex($latex_document, $destination) { $current_dir = getcwd(); if (!is_dir($this->_tmp_dir)) return false; chdir($this->_tmp_dir); $this->_tmp_filename = md5(uniqid(rand(), true)); file_put_contents($this->_tmp_filename . ".tex", $latex_document); $this->myexec($this->_latex_path . " --interaction=nonstopmode " . $this->_tmp_filename . ".tex", $status_latex); if (!file_exists($this->_tmp_filename . ".dvi")) { if (!$this->_keep_tmp) $this->cleanTemporaryDirectory(); chdir($current_dir); $this->_errorcode = 4; return false; } $this->myexec($this->_dvips_path . " " . $this->_tmp_filename . ".dvi -o " . $this->_tmp_filename . ".ps", $status_dvips); $this->myexec($this->_convert_path . " " . $this->_tmp_filename . ".ps " . $this->_tmp_filename . "." . $this->_image_format, $status_convert); if ($status_dvips || $status_convert) { if (!$this->_keep_tmp) $this->cleanTemporaryDirectory(); chdir($current_dir); $this->_errorcode = 6; return false; } $dim = $this->getDimensions($this->_tmp_filename . "." . $this->_image_format); if ($dim["x"] > $this->_xsize_limit || $dim["y"] > $this->_ysize_limit) { if (!$this->_keep_tmp) $this->cleanTemporaryDirectory(); chdir($current_dir); $this->_errorcode = 5; $this->_errorextra = ": " . $dim["x"] . "x" . $dim["y"]; return false; } $status_code = copy($this->_tmp_filename . "." . $this->_image_format, $destination); chdir($current_dir); if (!$this->_keep_tmp) $this->cleanTemporaryDirectory(); if (!$status_code) { $this->_errorcode = 7; return false; } return true; } protected function myexec($cmd, &$status) { $cmd = "$cmd 2>&1"; $lastline = exec($cmd, $output, $status); $this->_cmdoutput .= "\n>>>>> $cmd\n" . trim(implode(PHP_EOL, $output)) . PHP_EOL . " --- exit status " . $status; return $lastline; } public function cleanTemporaryDirectory() { foreach (['tex', 'aux', 'log', 'dvi', 'ps', $this->_image_format] as $ext) { @unlink($this->_tmp_dir . "/" . $this->_tmp_filename . "." . $ext); } } }