Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members | Related Pages

Math.php

Go to the documentation of this file.
00001 <?php 00002 # 00003 # Takes LaTeX fragments, sends them to a helper program (texvc) for rendering 00004 # to rasterized PNG and HTML and MathML approximations. An appropriate 00005 # rendering form is picked and returned. 00006 # 00007 # by Tomasz Wegrzanowski, with additions by Brion Vibber (2003, 2004) 00008 # 00009 00010 class MathRenderer { 00011 var $mode = MW_MATH_MODERN; 00012 var $tex = ""; 00013 var $inputhash = ""; 00014 var $hash = ""; 00015 var $html = ""; 00016 var $mathml = ""; 00017 var $conservativeness = 0; 00018 00019 function MathRenderer( $tex ) { 00020 $this->tex = $tex; 00021 } 00022 00023 function setOutputMode( $mode ) { 00024 $this->mode = $mode; 00025 } 00026 00027 function render() { 00028 global $wgMathDirectory, $wgTmpDirectory, $wgInputEncoding; 00029 global $wgTexvc; 00030 00031 if( $this->mode == MW_MATH_SOURCE ) { 00032 # No need to render or parse anything more! 00033 return ('$ '.htmlspecialchars( $this->tex ).' $'); 00034 } 00035 00036 if( !$this->_recall() ) { 00037 # Ensure that the temp and output directories are available before continuing... 00038 if( !file_exists( $wgMathDirectory ) ) { 00039 if( !@mkdir( $wgMathDirectory ) ) { 00040 return $this->_error( "math_bad_output" ); 00041 } 00042 } elseif( !is_dir( $wgMathDirectory ) || !is_writable( $wgMathDirectory ) ) { 00043 return $this->_error( "math_bad_output" ); 00044 } 00045 if( !file_exists( $wgTmpDirectory ) ) { 00046 if( !@mkdir( $wgTmpDirectory ) ) { 00047 return $this->_error( "math_bad_tmpdir" ); 00048 } 00049 } elseif( !is_dir( $wgTmpDirectory ) || !is_writable( $wgTmpDirectory ) ) { 00050 return $this->_error( "math_bad_tmpdir" ); 00051 } 00052 00053 if( !is_executable( $wgTexvc ) ) { 00054 return $this->_error( "math_notexvc" ); 00055 } 00056 $cmd = $wgTexvc." ". 00057 escapeshellarg($wgTmpDirectory)." ". 00058 escapeshellarg($wgMathDirectory)." ". 00059 escapeshellarg($this->tex)." ". 00060 escapeshellarg($wgInputEncoding); 00061 wfDebug( "TeX: $cmd" ); 00062 $contents = `$cmd`; 00063 00064 if (strlen($contents) == 0) { 00065 return $this->_error( "math_unknown_error" ); 00066 } 00067 00068 $retval = substr ($contents, 0, 1); 00069 if (($retval == "C") || ($retval == "M") || ($retval == "L")) { 00070 if ($retval == "C") 00071 $this->conservativeness = 2; 00072 else if ($retval == "M") 00073 $this->conservativeness = 1; 00074 else 00075 $this->conservativeness = 0; 00076 $outdata = substr ($contents, 33); 00077 00078 $i = strpos($outdata, "\000"); 00079 00080 $this->html = substr($outdata, 0, $i); 00081 $this->mathml = substr($outdata, $i+1); 00082 00083 $sql_html = "'".wfStrencode($this->html)."'"; 00084 $sql_mathml = "'".wfStrencode($this->mathml)."'"; 00085 } else if (($retval == "c") || ($retval == "m") || ($retval == "l")) { 00086 $this->html = substr ($contents, 33); 00087 if ($retval == "c") 00088 $this->conservativeness = 2; 00089 else if ($retval == "m") 00090 $this->conservativeness = 1; 00091 else 00092 $this->conservativeness = 0; 00093 $sql_html = "'".wfStrencode($this->html)."'"; 00094 $this->mathml = ''; 00095 $sql_mathml = 'NULL'; 00096 } else if ($retval == "X") { 00097 $outhtml = ''; 00098 $this->mathml = substr ($contents, 33); 00099 $sql_html = 'NULL'; 00100 $sql_mathml = "'".wfStrencode($this->mathml)."'"; 00101 $this->conservativeness = 0; 00102 } else if ($retval == "+") { 00103 $this->outhtml = ''; 00104 $this->mathml = ''; 00105 $sql_html = 'NULL'; 00106 $sql_mathml = 'NULL'; 00107 $this->conservativeness = 0; 00108 } else { 00109 $errbit = htmlspecialchars( substr($contents, 1) ); 00110 switch( $retval ) { 00111 case "E": return $this->_error( "math_lexing_error", $errbit ); 00112 case "S": return $this->_error( "math_syntax_error", $errbit ); 00113 case "F": return $this->_error( "math_unknown_function", $errbit ); 00114 default: return $this->_error( "math_unknown_error", $errbit ); 00115 } 00116 } 00117 00118 $this->hash = substr ($contents, 1, 32); 00119 if (!preg_match("/^[a-f0-9]{32}$/", $this->hash)) { 00120 return $this->_error( "math_unknown_error" ); 00121 } 00122 00123 if( !file_exists( "$wgMathDirectory/{$this->hash}.png" ) ) { 00124 return $this->_error( "math_image_error" ); 00125 } 00126 00127 # Now save it back to the DB: 00128 $outmd5_sql = wfStrencode(pack("H32", $this->hash)); 00129 00130 $md5_sql = wfStrencode( pack("H32", $this->md5) ); # Binary packed, not hex 00131 $sql = "REPLACE INTO math VALUES ('".$md5_sql."', '".$outmd5_sql."', ".$this->conservativeness.", ".$sql_html.", ".$sql_mathml.")"; 00132 00133 $res = wfQuery( $sql, DB_WRITE, "MathRenderer::render" ); 00134 # we don't really care if it fails 00135 } 00136 00137 return $this->_doRender(); 00138 } 00139 00140 function _error( $msg, $append = "" ) { 00141 $mf = htmlspecialchars( wfMsg( "math_failure" ) ); 00142 $munk = htmlspecialchars( wfMsg( "math_unknown_error" ) ); 00143 $errmsg = htmlspecialchars( wfMsg( $msg ) ); 00144 $source = htmlspecialchars($this->tex); 00145 return "<strong class='error'>$mf ($errmsg$append): $source</strong>\n"; 00146 } 00147 00148 function _recall() { 00149 global $wgMathDirectory; 00150 00151 $this->md5 = md5( $this->tex ); 00152 00153 $md5_sql = wfStrencode( pack("H32", $this->md5) ); # Binary packed, not hex 00154 $sql = "SELECT math_outputhash,math_html_conservativeness,math_html,math_mathml FROM math WHERE math_inputhash = '$md5_sql'"; 00155 $res = wfQuery( $sql, DB_READ, "MathRenderer::_recall" ); 00156 00157 if( $rpage = wfFetchObject ( $res ) ) { 00158 # Tailing 0x20s can get dropped by the database, add it back on if necessary: 00159 $xhash = unpack( "H32md5", $rpage->math_outputhash . " " ); 00160 $this->hash = $xhash ['md5']; 00161 00162 $this->conservativeness = $rpage->math_html_conservativeness; 00163 $this->html = $rpage->math_html; 00164 $this->mathml = $rpage->math_mathml; 00165 00166 if( file_exists( "$wgMathDirectory/{$this->hash}.png" ) ) { 00167 return true; 00168 } 00169 } 00170 00171 # Missing from the database and/or the render cache 00172 return false; 00173 } 00174 00175 # Select among PNG, HTML, or MathML output depending on 00176 function _doRender() { 00177 if( $this->mode == MW_MATH_MATHML && $this->mathml != '' ) { 00178 return "<math xmlns='http://www.w3.org/1998/Math/MathML'>{$this->mathml}</math>"; 00179 } 00180 if (($this->mode == MW_MATH_PNG) || ($this->html == '') || 00181 (($this->mode == MW_MATH_SIMPLE) && ($this->conservativeness != 2)) || 00182 (($this->mode == MW_MATH_MODERN || $this->mode == MW_MATH_MATHML) && ($this->conservativeness == 0))) { 00183 return $this->_linkToMathImage(); 00184 } else { 00185 return '<span class="texhtml">'.$this->html.'</span>'; 00186 } 00187 } 00188 00189 function _linkToMathImage() { 00190 global $wgMathPath; 00191 $url = htmlspecialchars( "$wgMathPath/{$this->hash}.png" ); 00192 $alt = trim(str_replace("\n", ' ', htmlspecialchars( $this->tex ))); 00193 return "<img class='tex' src=\"$url\" alt=\"$alt\" />"; 00194 } 00195 00196 } 00197 00198 function renderMath( $tex ) { 00199 global $wgUser; 00200 $math = new MathRenderer( $tex ); 00201 $math->setOutputMode( $wgUser->getOption("math")); 00202 return $math->render(); 00203 } 00204 00205 ?>

Generated on Tue Jun 29 23:40:05 2004 for Mediawiki by doxygen 1.3.7