mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Math
synced 2024-11-24 15:44:33 +00:00
27091b55a0
When $wgMathoidCli is misconfigured the error message was misleading. It was reported that the specified file was not executable, even though other reasons are possible (e.g., nodejs misconfigured). Therefore, we capture STDERR and add it to the error log. Bug: T198564 Change-Id: I7d0ae0f3ab4789124f9ff1533e7712ca31233f9e
196 lines
4.7 KiB
PHP
196 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( array $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 mixed $req request
|
|
* @param int|null &$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 ) {
|
|
$errorMsg = $result->getStderr();
|
|
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( "Failed to execute Mathoid cli '$wgMathoidCli[0]', reason: $errorMsg" );
|
|
}
|
|
$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}";
|
|
}
|
|
}
|