MDL-68066 output: Mustache - Add option to disable lambda rendering

This commit is based on an outstanding pull request to the Mustache repo
This commit is contained in:
Lars Bonczek 2022-08-19 14:32:01 +08:00 committed by Jun Pataleta
parent 0393514612
commit fcbb645671
2 changed files with 73 additions and 35 deletions

View File

@ -26,31 +26,34 @@ class Mustache_Compiler
private $entityFlags;
private $charset;
private $strictCallables;
private $disableLambdaRendering;
/**
* Compile a Mustache token parse tree into PHP source code.
*
* @param string $source Mustache Template source code
* @param string $tree Parse tree of Mustache tokens
* @param string $name Mustache Template class name
* @param bool $customEscape (default: false)
* @param string $charset (default: 'UTF-8')
* @param bool $strictCallables (default: false)
* @param int $entityFlags (default: ENT_COMPAT)
* @param string $source Mustache Template source code
* @param array $tree Parse tree of Mustache tokens
* @param string $name Mustache Template class name
* @param bool $customEscape (default: false)
* @param string $charset (default: 'UTF-8')
* @param bool $strictCallables (default: false)
* @param int $entityFlags (default: ENT_COMPAT)
* @param bool $disableLambdaRendering (default: false)
*
* @return string Generated PHP source code
*/
public function compile($source, array $tree, $name, $customEscape = false, $charset = 'UTF-8', $strictCallables = false, $entityFlags = ENT_COMPAT)
public function compile($source, array $tree, $name, $customEscape = false, $charset = 'UTF-8', $strictCallables = false, $entityFlags = ENT_COMPAT, $disableLambdaRendering = false)
{
$this->pragmas = $this->defaultPragmas;
$this->sections = array();
$this->blocks = array();
$this->source = $source;
$this->indentNextLine = true;
$this->customEscape = $customEscape;
$this->entityFlags = $entityFlags;
$this->charset = $charset;
$this->strictCallables = $strictCallables;
$this->pragmas = $this->defaultPragmas;
$this->sections = array();
$this->blocks = array();
$this->source = $source;
$this->indentNextLine = true;
$this->customEscape = $customEscape;
$this->entityFlags = $entityFlags;
$this->charset = $charset;
$this->strictCallables = $strictCallables;
$this->disableLambdaRendering = $disableLambdaRendering;
return $this->writeCode($tree, $name);
}
@ -331,14 +334,8 @@ class Mustache_Compiler
if (%s) {
$source = %s;
$result = (string) call_user_func($value, $source, %s);
if (strpos($result, \'{{\') === false) {
$buffer .= $result;
} else {
$buffer .= $this->mustache
->loadLambda($result%s)
->renderInternal($context);
}
$result = (string) call_user_func($value, $source, %s);%s
$buffer .= $result;
} elseif (!empty($value)) {
$values = $this->isIterable($value) ? $value : array($value);
foreach ($values as $value) {
@ -352,6 +349,36 @@ class Mustache_Compiler
}
';
const SECTION_RENDER_LAMBDA = '
if (strpos($result, \'{{\') !== false) {
$result = $this->mustache
->loadLambda($result%s)
->renderInternal($context);
}
';
/**
* Helper function to compile section with and without lambda rendering.
*
* @param string $key
* @param string $callable
* @param string $source
* @param string $helper
* @param string $delims
* @param string $content
*
* @return string section code
*/
private function getSection($key, $callable, $source, $helper, $delims, $content)
{
$render = '';
if (!$this->disableLambdaRendering) {
$render = sprintf($this->prepare(self::SECTION_RENDER_LAMBDA, 2), $delims);
}
return sprintf($this->prepare(self::SECTION), $key, $callable, $source, $helper, $render, $content);
}
/**
* Generate Mustache Template section PHP source.
*
@ -383,7 +410,7 @@ class Mustache_Compiler
$key = ucfirst(md5($delims . "\n" . $source));
if (!isset($this->sections[$key])) {
$this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $helper, $delims, $this->walk($nodes, 2));
$this->sections[$key] = $this->getSection($key, $callable, $source, $helper, $delims, $this->walk($nodes, 2));
}
$method = $this->getFindMethod($id);

View File

@ -53,6 +53,7 @@ class Mustache_Engine
private $charset = 'UTF-8';
private $logger;
private $strictCallables = false;
private $disableLambdaRendering = false;
private $pragmas = array();
private $delimiters;
@ -130,6 +131,11 @@ class Mustache_Engine
* // This currently defaults to false, but will default to true in v3.0.
* 'strict_callables' => true,
*
* // Do not render the output of lambdas. Use this to prevent repeated rendering if the lambda already
* // takes care of rendering its content. This helps protect against mustache code injection when user
* // input is passed directly into the template. Defaults to false.
* 'disable_lambda_rendering' => true,
*
* // Enable pragmas across all templates, regardless of the presence of pragma tags in the individual
* // templates.
* 'pragmas' => [Mustache_Engine::PRAGMA_FILTERS],
@ -204,6 +210,10 @@ class Mustache_Engine
$this->strictCallables = $options['strict_callables'];
}
if (isset($options['disable_lambda_rendering'])) {
$this->disableLambdaRendering = $options['disable_lambda_rendering'];
}
if (isset($options['delimiters'])) {
$this->delimiters = $options['delimiters'];
}
@ -624,14 +634,15 @@ class Mustache_Engine
//
// Keep this list in alphabetical order :)
$chunks = array(
'charset' => $this->charset,
'delimiters' => $this->delimiters ? $this->delimiters : '{{ }}',
'entityFlags' => $this->entityFlags,
'escape' => isset($this->escape) ? 'custom' : 'default',
'key' => ($source instanceof Mustache_Source) ? $source->getKey() : 'source',
'pragmas' => $this->getPragmas(),
'strictCallables' => $this->strictCallables,
'version' => self::VERSION,
'charset' => $this->charset,
'delimiters' => $this->delimiters ? $this->delimiters : '{{ }}',
'entityFlags' => $this->entityFlags,
'escape' => isset($this->escape) ? 'custom' : 'default',
'key' => ($source instanceof Mustache_Source) ? $source->getKey() : 'source',
'pragmas' => $this->getPragmas(),
'strictCallables' => $this->strictCallables,
'disableLambdaRendering' => $this->disableLambdaRendering,
'version' => self::VERSION,
);
$key = json_encode($chunks);
@ -810,7 +821,7 @@ class Mustache_Engine
$compiler = $this->getCompiler();
$compiler->setPragmas($this->getPragmas());
return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags);
return $compiler->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables, $this->entityFlags, $this->disableLambdaRendering);
}
/**