2017-08-16 05:50:44 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
use MediaWiki\Logger\LoggerFactory;
|
|
|
|
use \MediaWiki\MediaWikiServices;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Created by PhpStorm.
|
|
|
|
* User: Moritz
|
|
|
|
* Date: 15.08.2017
|
|
|
|
* Time: 09:33
|
|
|
|
*/
|
|
|
|
class MathMathMLCli extends MathMathML {
|
|
|
|
|
|
|
|
/**
|
2018-05-15 15:50:08 +00:00
|
|
|
* @param array[] $tags math tags
|
2017-08-16 05:50:44 +00:00
|
|
|
* @return bool
|
|
|
|
* @throws MWException
|
|
|
|
*/
|
2018-05-15 15:50:08 +00:00
|
|
|
public static function batchEvaluate( array $tags ) {
|
2017-08-16 05:50:44 +00:00
|
|
|
$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(),
|
|
|
|
],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-04-07 19:03:56 +00:00
|
|
|
* @param mixed $req request
|
2017-08-16 05:50:44 +00:00
|
|
|
* @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}";
|
|
|
|
}
|
|
|
|
}
|