mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Math
synced 2024-11-15 03:34:10 +00:00
195 lines
4.7 KiB
PHP
195 lines
4.7 KiB
PHP
|
<?php
|
||
|
|
||
|
use MediaWiki\Logger\LoggerFactory;
|
||
|
use \MediaWiki\MediaWikiServices;
|
||
|
|
||
|
/**
|
||
|
* Created by PhpStorm.
|
||
|
* User: Moritz
|
||
|
* Date: 15.08.2017
|
||
|
* Time: 09:33
|
||
|
*/
|
||
|
class MathMathMLCli extends MathMathML {
|
||
|
|
||
|
/**
|
||
|
* @param array &$tags math tags
|
||
|
* @return bool
|
||
|
* @throws MWException
|
||
|
*/
|
||
|
public static function batchEvaluate( &$tags ) {
|
||
|
$req = [];
|
||
|
foreach ( $tags as $key => $tag ) {
|
||
|
/** @var MathMathMLCli $renderer */
|
||
|
$renderer = $tag[0];
|
||
|
// checking if the rendering is in the database is no security issue since only the md5
|
||
|
// hash of the user input string will be sent to the database
|
||
|
if ( !$renderer->isInDatabase() ) {
|
||
|
$req[] = $renderer->getMathoidCliQuery();
|
||
|
}
|
||
|
}
|
||
|
if ( count( $req ) === 0 ) {
|
||
|
return true;
|
||
|
}
|
||
|
$exitCode = 1;
|
||
|
$res = self::evaluateWithCli( $req, $exitCode );
|
||
|
foreach ( $tags as $key => $tag ) {
|
||
|
/** @var MathMathMLCli $renderer */
|
||
|
$renderer = $tag[0];
|
||
|
if ( !$renderer->isInDatabase() ) {
|
||
|
$renderer->initializeFromCliResponse( $res );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param Object $res
|
||
|
* @return bool
|
||
|
*/
|
||
|
private function initializeFromCliResponse( $res ) {
|
||
|
global $wgMathoidCli;
|
||
|
if ( !property_exists( $res, $this->getMd5() ) ) {
|
||
|
$this->lastError =
|
||
|
$this->getError( 'math_mathoid_error', 'cli',
|
||
|
var_export( get_object_vars( $res ) ) );
|
||
|
return false;
|
||
|
}
|
||
|
if ( $this->isEmpty() ) {
|
||
|
return false;
|
||
|
}
|
||
|
$response = $res->{$this->getMd5()};
|
||
|
if ( !$response->success ) {
|
||
|
$this->lastError = $this->renderError( $response );
|
||
|
return false;
|
||
|
}
|
||
|
$this->texSecure = true;
|
||
|
$this->tex = $response->sanetex;
|
||
|
// The host name is only relevant for the debugging. So using file:// to indicate that the
|
||
|
// cli interface seems to be OK.
|
||
|
$this->processJsonResult( $response, 'file://' . $wgMathoidCli[0] );
|
||
|
$this->mathStyle = $response->mathoidStyle;
|
||
|
$this->png = implode( array_map( "chr", $response->png->data ) );
|
||
|
$this->changed = true;
|
||
|
}
|
||
|
|
||
|
public function renderError( $response ) {
|
||
|
$msg = $response->error;
|
||
|
try {
|
||
|
switch ( $response->detail->status ) {
|
||
|
case "F":
|
||
|
$msg .= "\n Found {$response->detail->details}" .
|
||
|
$this->appendLocationInfo( $response );
|
||
|
break;
|
||
|
case 'S':
|
||
|
case "C":
|
||
|
$msg .= $this->appendLocationInfo( $response );
|
||
|
break;
|
||
|
case '-':
|
||
|
// we do not know any cases that triggers this error
|
||
|
}
|
||
|
}
|
||
|
catch ( Exception $e ) {
|
||
|
// use default error message
|
||
|
}
|
||
|
|
||
|
return $this->getError( 'math_mathoid_error', 'cli', $msg );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getMathoidCliQuery() {
|
||
|
return [
|
||
|
'query' => [
|
||
|
'q' => $this->getTex(),
|
||
|
'type' => $this->getInputType(),
|
||
|
'hash' => $this->getMd5(),
|
||
|
],
|
||
|
];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param string $req request
|
||
|
* @param int &$exitCode exit code
|
||
|
* @return mixed
|
||
|
* @throws MWException
|
||
|
*/
|
||
|
public static function evaluateWithCli( $req, &$exitCode = null ) {
|
||
|
global $wgMathoidCli;
|
||
|
$json_req = json_encode( $req );
|
||
|
$cmd = MediaWikiServices::getInstance()->getShellCommandFactory()->create();
|
||
|
$cmd->params( $wgMathoidCli );
|
||
|
$cmd->input( $json_req );
|
||
|
$result = $cmd->execute();
|
||
|
if ( $result->getExitCode() != 0 ) {
|
||
|
LoggerFactory::getInstance( 'Math' )->error( 'Can not process {req} with config
|
||
|
{conf} returns {res}', [
|
||
|
'req' => $req,
|
||
|
'conf' => var_export( $wgMathoidCli, true ),
|
||
|
'res' => var_export( $result, true ),
|
||
|
] );
|
||
|
throw new MWException( "Mathoid cli '$wgMathoidCli[0]' is not executable." );
|
||
|
}
|
||
|
$res = json_decode( $result->getStdout() );
|
||
|
if ( !$res ) {
|
||
|
throw new MWException( "Mathoid cli response '$res' is no valid JSON file." );
|
||
|
}
|
||
|
|
||
|
return $res;
|
||
|
}
|
||
|
|
||
|
public function render( $forceReRendering = false ) {
|
||
|
if ( $this->getLastError() ) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
protected function doCheck() {
|
||
|
// avoid that restbase is called if check is set to always
|
||
|
return $this->texSecure;
|
||
|
}
|
||
|
|
||
|
protected function initializeFromDatabaseRow( $rpage ) {
|
||
|
if ( !empty( $rpage->math_svg ) ) {
|
||
|
$this->png = $rpage->math_png;
|
||
|
}
|
||
|
parent::initializeFromDatabaseRow( $rpage ); // TODO: Change the autogenerated stub
|
||
|
}
|
||
|
|
||
|
protected function dbOutArray() {
|
||
|
$out = parent::dbOutArray();
|
||
|
$out['math_png'] = $this->png;
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
protected function dbInArray() {
|
||
|
$out = parent::dbInArray();
|
||
|
$out[] = 'math_png';
|
||
|
|
||
|
return $out;
|
||
|
}
|
||
|
|
||
|
public function getPng() {
|
||
|
if ( !$this->png ) {
|
||
|
$this->initializeFromCliResponse( self::evaluateWithCli( [
|
||
|
$this->getMathoidCliQuery(),
|
||
|
] ) );
|
||
|
|
||
|
}
|
||
|
|
||
|
return parent::getPng();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param $response object from cli
|
||
|
* @return string containing the location information
|
||
|
*/
|
||
|
private function appendLocationInfo( $response ) {
|
||
|
return "in {$response->detail->line}:{$response->detail->column}";
|
||
|
}
|
||
|
}
|