mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-05-09 12:02:24 +09:00
Apply context-aware escape more generally; add can/cannot/canany and env directives
This commit is contained in:
parent
7c727c0fcb
commit
c487c13864
6 changed files with 165 additions and 70 deletions
|
|
@ -37,6 +37,7 @@ class Template
|
||||||
*/
|
*/
|
||||||
protected static $_mtime;
|
protected static $_mtime;
|
||||||
protected static $_delay_compile;
|
protected static $_delay_compile;
|
||||||
|
protected static $_json_options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provided for compatibility with old TemplateHandler.
|
* Provided for compatibility with old TemplateHandler.
|
||||||
|
|
@ -76,6 +77,10 @@ class Template
|
||||||
{
|
{
|
||||||
self::$_delay_compile = config('view.delay_compile') ?? 0;
|
self::$_delay_compile = config('view.delay_compile') ?? 0;
|
||||||
}
|
}
|
||||||
|
if (self::$_json_options === null)
|
||||||
|
{
|
||||||
|
self::$_json_options = \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_APOS | \JSON_HEX_QUOT | \JSON_UNESCAPED_UNICODE;
|
||||||
|
}
|
||||||
|
|
||||||
// If paths were provided, initialize immediately.
|
// If paths were provided, initialize immediately.
|
||||||
if ($dirname && $filename)
|
if ($dirname && $filename)
|
||||||
|
|
@ -767,7 +772,42 @@ class Template
|
||||||
case 'admin': return $this->user->isAdmin();
|
case 'admin': return $this->user->isAdmin();
|
||||||
case 'manager': return $grant->manager ?? false;
|
case 'manager': return $grant->manager ?? false;
|
||||||
case 'member': return $this->user->isMember();
|
case 'member': return $this->user->isMember();
|
||||||
default: return $grant->$type ?? false;
|
default: false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capability checker for v2.
|
||||||
|
*
|
||||||
|
* @param int $check_type
|
||||||
|
* @param string|array $capability
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function _v2_checkCapability(int $check_type, $capability): bool
|
||||||
|
{
|
||||||
|
$grant = \Context::get('grant');
|
||||||
|
if ($check_type === 1)
|
||||||
|
{
|
||||||
|
return isset($grant->$capability) ? boolval($grant->$capability) : false;
|
||||||
|
}
|
||||||
|
elseif ($check_type === 2)
|
||||||
|
{
|
||||||
|
return isset($grant->$capability) ? !boolval($grant->$capability) : true;
|
||||||
|
}
|
||||||
|
elseif (is_array($capability))
|
||||||
|
{
|
||||||
|
foreach ($capability as $cap)
|
||||||
|
{
|
||||||
|
if (isset($grant->$cap) && $grant->$cap)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,9 +88,13 @@ class TemplateParser_v2
|
||||||
'empty' => ['if (empty(%s)):', 'endif;'],
|
'empty' => ['if (empty(%s)):', 'endif;'],
|
||||||
'admin' => ['if ($this->user->isAdmin()):', 'endif;'],
|
'admin' => ['if ($this->user->isAdmin()):', 'endif;'],
|
||||||
'auth' => ['if ($this->_v2_checkAuth(%s)):', 'endif;'],
|
'auth' => ['if ($this->_v2_checkAuth(%s)):', 'endif;'],
|
||||||
|
'can' => ['if ($this->_v2_checkCapability(1, %s)):', 'endif;'],
|
||||||
|
'cannot' => ['if ($this->_v2_checkCapability(2, %s)):', 'endif;'],
|
||||||
|
'canany' => ['if ($this->_v2_checkCapability(3, %s)):', 'endif;'],
|
||||||
'guest' => ['if (!$this->user->isMember()):', 'endif;'],
|
'guest' => ['if (!$this->user->isMember()):', 'endif;'],
|
||||||
'desktop' => ['if (!$__Context->m):', 'endif;'],
|
'desktop' => ['if (!$__Context->m):', 'endif;'],
|
||||||
'mobile' => ['if ($__Context->m):', 'endif;'],
|
'mobile' => ['if ($__Context->m):', 'endif;'],
|
||||||
|
'env' => ['if (!empty($_ENV[%s])):', 'endif;'],
|
||||||
'else' => ['else:'],
|
'else' => ['else:'],
|
||||||
'elseif' => ['elseif (%s):'],
|
'elseif' => ['elseif (%s):'],
|
||||||
'case' => ['case %s:'],
|
'case' => ['case %s:'],
|
||||||
|
|
@ -665,8 +669,8 @@ class TemplateParser_v2
|
||||||
if ($match[1] === 'json')
|
if ($match[1] === 'json')
|
||||||
{
|
{
|
||||||
return sprintf('<?php echo $this->config->context === \'JS\' ? ' .
|
return sprintf('<?php echo $this->config->context === \'JS\' ? ' .
|
||||||
'json_encode(%s, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT) : ' .
|
'json_encode(%s, self::$_json_options) : ' .
|
||||||
'htmlspecialchars(json_encode(%s, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT), \ENT_QUOTES, \'UTF-8\', false); ?>', $args, $args);
|
'htmlspecialchars(json_encode(%s, self::$_json_options), \ENT_QUOTES, \'UTF-8\', false); ?>', $args, $args);
|
||||||
}
|
}
|
||||||
elseif ($match[1] === 'lang')
|
elseif ($match[1] === 'lang')
|
||||||
{
|
{
|
||||||
|
|
@ -726,23 +730,30 @@ class TemplateParser_v2
|
||||||
*/
|
*/
|
||||||
protected function _arrangeOutputFilters(array $match): string
|
protected function _arrangeOutputFilters(array $match): string
|
||||||
{
|
{
|
||||||
// Escape is 'autoescape' by default.
|
|
||||||
$escape_option = 'autoescape';
|
|
||||||
|
|
||||||
// Split content into filters.
|
// Split content into filters.
|
||||||
$filters = array_map('trim', preg_split('#(?<![\\\\\|])\|(?![\|\'"])#', $match[1]));
|
$filters = array_map('trim', preg_split('#(?<![\\\\\|])\|(?![\|\'"])#', $match[1]));
|
||||||
$str = strtr(array_shift($filters), ['\\|' => '|']);
|
$str = strtr(array_shift($filters), ['\\|' => '|']);
|
||||||
|
|
||||||
// Convert variable scope before applying filters.
|
// Set default escape option.
|
||||||
$str = $this->_escapeCurly($str);
|
if (preg_match('/^\\$(?:user_)?lang->\\w+$/', $str))
|
||||||
$str = $this->_convertVariableScope($str);
|
{
|
||||||
|
$escape_option = 'autocontext_lang';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$escape_option = 'autocontext';
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent null errors.
|
// Prevent null errors.
|
||||||
if (preg_match('#^\$[\\\\\w\[\]\'":>-]+$#', $str))
|
if (preg_match('#^\$[\\\\\w\[\]\'":>-]+$#', $str) && !str_starts_with($str, '$lang->'))
|
||||||
{
|
{
|
||||||
$str = preg_match('/^\$lang->/', $str) ? $str : "$str ?? ''";
|
$str = "$str ?? ''";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert variable scope and escape any curly braces.
|
||||||
|
$str = $this->_escapeCurly($str);
|
||||||
|
$str = $this->_convertVariableScope($str);
|
||||||
|
|
||||||
// Apply filters.
|
// Apply filters.
|
||||||
foreach ($filters as $filter)
|
foreach ($filters as $filter)
|
||||||
{
|
{
|
||||||
|
|
@ -777,8 +788,8 @@ class TemplateParser_v2
|
||||||
$escape_option = 'noescape';
|
$escape_option = 'noescape';
|
||||||
break;
|
break;
|
||||||
case 'json':
|
case 'json':
|
||||||
$str = "json_encode({$str}, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT)";
|
$str = "json_encode({$str}, self::\$_json_options)";
|
||||||
$escape_option = 'autocontext';
|
$escape_option = 'autocontext_json';
|
||||||
break;
|
break;
|
||||||
case 'strip':
|
case 'strip':
|
||||||
case 'strip_tags':
|
case 'strip_tags':
|
||||||
|
|
@ -797,7 +808,7 @@ class TemplateParser_v2
|
||||||
$str = "strtoupper({$str})";
|
$str = "strtoupper({$str})";
|
||||||
break;
|
break;
|
||||||
case 'nl2br':
|
case 'nl2br':
|
||||||
$str = self::_applyEscapeOption($str, $escape_option);
|
$str = self::_applyEscapeOption($str, $escape_option === 'autocontext' ? 'autoescape' : $escape_option);
|
||||||
$str = "nl2br({$str})";
|
$str = "nl2br({$str})";
|
||||||
$escape_option = 'noescape';
|
$escape_option = 'noescape';
|
||||||
break;
|
break;
|
||||||
|
|
@ -816,10 +827,10 @@ class TemplateParser_v2
|
||||||
$str = $filter_option ? "number_shorten({$str}, {$filter_option})" : "number_shorten({$str})";
|
$str = $filter_option ? "number_shorten({$str}, {$filter_option})" : "number_shorten({$str})";
|
||||||
break;
|
break;
|
||||||
case 'link':
|
case 'link':
|
||||||
$str = self::_applyEscapeOption($str, $escape_option);
|
$str = self::_applyEscapeOption($str, $escape_option === 'autocontext' ? 'autoescape' : $escape_option);
|
||||||
if ($filter_option)
|
if ($filter_option)
|
||||||
{
|
{
|
||||||
$filter_option = self::_applyEscapeOption($filter_option, $escape_option);
|
$filter_option = self::_applyEscapeOption($filter_option, $escape_option === 'autocontext' ? 'autoescape' : $escape_option);
|
||||||
$str = "'<a href=\"' . ($filter_option) . '\">' . ($str) . '</a>'";
|
$str = "'<a href=\"' . ($filter_option) . '\">' . ($str) . '</a>'";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -847,14 +858,19 @@ class TemplateParser_v2
|
||||||
*/
|
*/
|
||||||
protected static function _applyEscapeOption(string $str, string $option): string
|
protected static function _applyEscapeOption(string $str, string $option): string
|
||||||
{
|
{
|
||||||
|
$str2 = strtr($str, ["\n" => ' ']);
|
||||||
switch($option)
|
switch($option)
|
||||||
{
|
{
|
||||||
case 'autocontext':
|
case 'autocontext':
|
||||||
return "\$this->config->context === 'JS' ? ({$str}) : htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false)";
|
return "\$this->config->context === 'JS' ? escape_js({$str2}) : htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false)";
|
||||||
|
case 'autocontext_json':
|
||||||
|
return "\$this->config->context === 'JS' ? {$str2} : htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false)";
|
||||||
|
case 'autocontext_lang':
|
||||||
|
return "\$this->config->context === 'JS' ? escape_js({$str2}) : ({$str})";
|
||||||
case 'autoescape':
|
case 'autoescape':
|
||||||
return "htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false)";
|
return "htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false)";
|
||||||
case 'autolang':
|
case 'autolang':
|
||||||
return "(preg_match('/^\\$(?:user_)?lang->\\w+$/', {$str}) ? ({$str}) : htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false))";
|
return "(preg_match('/^\\\\\$(?:user_)?lang->\\w+$/', {$str2}) ? ({$str}) : htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', false))";
|
||||||
case 'escape':
|
case 'escape':
|
||||||
return "htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', true)";
|
return "htmlspecialchars({$str}, \ENT_QUOTES, 'UTF-8', true)";
|
||||||
case 'noescape':
|
case 'noescape':
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<?php $this->_v2_loadResource('css/style.scss', 'print', '', []); ?>
|
<?php $this->_v2_loadResource('css/style.scss', 'print', '', []); ?>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$__Context->foo = 'FOOFOOFOO';
|
$__Context->foo = 'FOOFOO<"FOO">BAR';
|
||||||
?>
|
?>
|
||||||
<?php
|
<?php
|
||||||
$__Context->bar = ['Rhy', 'miX', 'is', 'da', 'BEST!'];
|
$__Context->bar = ['Rhy', 'miX', 'is', 'da', 'BEST!'];
|
||||||
|
|
@ -15,38 +15,38 @@
|
||||||
{{ $foo }}
|
{{ $foo }}
|
||||||
|
|
||||||
|
|
||||||
<form action="<?php echo htmlspecialchars(\RX_BASEURL, \ENT_QUOTES, 'UTF-8', false); ?>" method="post">
|
<form action="<?php echo $this->config->context === 'JS' ? escape_js(\RX_BASEURL) : htmlspecialchars(\RX_BASEURL, \ENT_QUOTES, 'UTF-8', false); ?>" method="post">
|
||||||
<input type="hidden" name="_rx_csrf_token" value="<?php echo \Rhymix\Framework\Session::getGenericToken(); ?>" />
|
<input type="hidden" name="_rx_csrf_token" value="<?php echo \Rhymix\Framework\Session::getGenericToken(); ?>" />
|
||||||
<input type="text"<?php if (Context::getInstance()->get('foo')): ?> required="required"<?php endif; ?>>
|
<input type="text"<?php if (Context::getInstance()->get('foo')): ?> required="required"<?php endif; ?>>
|
||||||
<input type="text" value="<?php echo htmlspecialchars($__Context->bar[0] ?? '', \ENT_QUOTES, 'UTF-8', false); ?>"<?php if ($__Context->bar[3] === 'da'): ?> required="required"<?php endif; ?> />
|
<input type="text" value="<?php echo $this->config->context === 'JS' ? escape_js($__Context->bar[0] ?? '') : htmlspecialchars($__Context->bar[0] ?? '', \ENT_QUOTES, 'UTF-8', false); ?>"<?php if ($__Context->bar[3] === 'da'): ?> required="required"<?php endif; ?> />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div<?php if (!(isset($__Context->baz))): ?> class="foobar"<?php endif; ?>>
|
<div<?php if (!(isset($__Context->baz))): ?> class="foobar"<?php endif; ?>>
|
||||||
<?php if ($__Context->foo || $__Context->bar): ?>
|
<?php if ($__Context->foo || $__Context->bar): ?>
|
||||||
<p>Hello <?php if ($__Context->bar): ?><?php echo $__Context->foo ?? ''; ?><?php endif; ?></p>
|
<p>Hello <?php if ($__Context->bar): ?><?php echo $__Context->foo ?? ''; ?><?php endif; ?></p>
|
||||||
<p><?php echo htmlspecialchars(implode('|', array_map(function($i) { return strtoupper($i); }, $__Context->bar)), \ENT_QUOTES, 'UTF-8', false); ?></p>
|
<p><?php echo $this->config->context === 'JS' ? escape_js(implode('|', array_map(function($i) { return strtoupper($i); }, $__Context->bar))) : htmlspecialchars(implode('|', array_map(function($i) { return strtoupper($i); }, $__Context->bar)), \ENT_QUOTES, 'UTF-8', false); ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php ob_start(); $__last_fragment_name = 'rhymix'; ?>
|
<?php ob_start(); $__last_fragment_name = 'rhymix'; ?>
|
||||||
<?php $__tmp_RANDOM_LOOP_ID = Context::get('bar') ?? []; if($__tmp_RANDOM_LOOP_ID): $__loop_RANDOM_LOOP_ID = $this->_v2_initLoopVar("RANDOM_LOOP_ID", $__tmp_RANDOM_LOOP_ID); foreach ($__tmp_RANDOM_LOOP_ID as $__Context->k => $__Context->val): ?>
|
<?php $__tmp_64b3371f38fea1 = Context::get('bar') ?? []; if($__tmp_64b3371f38fea1): $__loop_64b3371f38fea1 = $this->_v2_initLoopVar("64b3371f38fea1", $__tmp_64b3371f38fea1); foreach ($__tmp_64b3371f38fea1 as $__Context->k => $__Context->val): ?>
|
||||||
<div>
|
<div>
|
||||||
<?php if (empty($__Context->nosuchvar)): ?>
|
<?php if (empty($__Context->nosuchvar)): ?>
|
||||||
<img src="/rhymix/tests/_data/template/bar/rhymix.svg" alt="unit tests are cool" />
|
<img src="/rhymix/tests/_data/template/bar/rhymix.svg" alt="unit tests are cool" />
|
||||||
<span <?php if ($__Context->k >= 2): ?>class="<?php echo htmlspecialchars($__Context->val ?? '', \ENT_QUOTES, 'UTF-8', false); ?>"<?php endif; ?>></span>
|
<span <?php if ($__Context->k >= 2): ?>class="<?php echo $this->config->context === 'JS' ? escape_js($__Context->val ?? '') : htmlspecialchars($__Context->val ?? '', \ENT_QUOTES, 'UTF-8', false); ?>"<?php endif; ?>></span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php $this->_v2_incrLoopVar($__loop_RANDOM_LOOP_ID); endforeach; $this->_v2_removeLoopVar($__loop_RANDOM_LOOP_ID); unset($__loop_RANDOM_LOOP_ID); else: ?><div>Nothing here...</div><?php endif; ?>
|
<?php $this->_v2_incrLoopVar($__loop_64b3371f38fea1); endforeach; $this->_v2_removeLoopVar($__loop_64b3371f38fea1); unset($__loop_64b3371f38fea1); else: ?><div>Nothing here...</div><?php endif; ?>
|
||||||
<?php $this->_fragments[$__last_fragment_name] = ob_get_flush(); ?>
|
<?php $this->_fragments[$__last_fragment_name] = ob_get_flush(); ?>
|
||||||
|
|
||||||
<?php (function($__filename, $__vars, $__varname, $__empty = null) { if (!$__vars): $__vars = []; if ($__empty): $__filename = $__empty; $__vars[] = ''; endif; endif; foreach ($__vars as $__var): echo $this->_v2_include("include", $__filename, [(string)$__varname => $__var]); endforeach; })('incl/eachtest', $__Context->bar, 'var'); ?>
|
<?php (function($__filename, $__vars, $__varname, $__empty = null) { if (!$__vars): $__vars = []; if ($__empty): $__filename = $__empty; $__vars[] = ''; endif; endif; foreach ($__vars as $__var): echo $this->_v2_include("include", $__filename, [(string)$__varname => $__var]); endforeach; })('incl/eachtest', $__Context->bar, 'var'); ?>
|
||||||
<?php (function($__filename, $__vars, $__varname, $__empty = null) { if (!$__vars): $__vars = []; if ($__empty): $__filename = $__empty; $__vars[] = ''; endif; endif; foreach ($__vars as $__var): echo $this->_v2_include("include", $__filename, [(string)$__varname => $__var]); endforeach; })('incl/eachtest', [], 'anything', 'incl/empty'); ?>
|
<?php (function($__filename, $__vars, $__varname, $__empty = null) { if (!$__vars): $__vars = []; if ($__empty): $__filename = $__empty; $__vars[] = ''; endif; endif; foreach ($__vars as $__var): echo $this->_v2_include("include", $__filename, [(string)$__varname => $__var]); endforeach; })('incl/eachtest', [], 'anything', 'incl/empty'); ?>
|
||||||
|
|
||||||
<?php if (!$__Context->m): ?>
|
<?php if (!$__Context->m): ?>
|
||||||
<p>The full class name is <?php echo htmlspecialchars(get_class(new Rhymix\Framework\Push), \ENT_QUOTES, 'UTF-8', true); ?>, <?php echo htmlspecialchars(Rhymix\Framework\Push::class, \ENT_QUOTES, 'UTF-8', false); ?> really.</p>
|
<p>The full class name is <?php echo htmlspecialchars(get_class(new Rhymix\Framework\Push), \ENT_QUOTES, 'UTF-8', true); ?>, <?php echo $this->config->context === 'JS' ? escape_js(Rhymix\Framework\Push::class) : htmlspecialchars(Rhymix\Framework\Push::class, \ENT_QUOTES, 'UTF-8', false); ?> really.</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<div class="barContainer" data-bar="<?php echo $this->config->context === 'JS' ? (json_encode($__Context->bar ?? '', \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT)) : htmlspecialchars(json_encode($__Context->bar ?? '', \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT), \ENT_QUOTES, 'UTF-8', false); ?>">
|
<div class="barContainer" data-bar="<?php echo $this->config->context === 'JS' ? json_encode($__Context->bar ?? '', self::$_json_options) : htmlspecialchars(json_encode($__Context->bar ?? '', self::$_json_options), \ENT_QUOTES, 'UTF-8', false); ?>">
|
||||||
<span<?php echo $this->_v2_buildAttribute('class', [
|
<span<?php echo $this->_v2_buildAttribute('class', [
|
||||||
'a-1',
|
'a-1',
|
||||||
'font-normal' => $__Context->foo,
|
'font-normal' => $__Context->foo,
|
||||||
|
|
@ -61,5 +61,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript"<?php $this->config->context = "JS"; ?>>
|
<script type="text/javascript"<?php $this->config->context = "JS"; ?>>
|
||||||
const bar = <?php echo $this->config->context === 'JS' ? json_encode($__Context->bar, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT) : htmlspecialchars(json_encode($__Context->bar, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT), \ENT_QUOTES, 'UTF-8', false); ?>;
|
const foo = '<?php echo $this->config->context === 'JS' ? escape_js($__Context->foo ?? '') : htmlspecialchars($__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false); ?>';
|
||||||
|
const bar = <?php echo $this->config->context === 'JS' ? json_encode($__Context->bar, self::$_json_options) : htmlspecialchars(json_encode($__Context->bar, self::$_json_options), \ENT_QUOTES, 'UTF-8', false); ?>;
|
||||||
<?php $this->config->context = "HTML"; ?></script>
|
<?php $this->config->context = "HTML"; ?></script>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="foobar">
|
<div class="foobar">
|
||||||
<p>Hello FOOFOOFOO</p>
|
<p>Hello FOOFOO<"FOO">BAR</p>
|
||||||
<p>RHY|MIX|IS|DA|BEST!</p>
|
<p>RHY|MIX|IS|DA|BEST!</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -57,5 +57,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
const foo = 'FOOFOO\u003C\u0022FOO\u0022\u003EBAR';
|
||||||
const bar = ["Rhy","miX","is","da","BEST!"];
|
const bar = ["Rhy","miX","is","da","BEST!"];
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<load src="css/style.scss" media="print" />
|
<load src="css/style.scss" media="print" />
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$foo = 'FOOFOOFOO';
|
$foo = 'FOOFOO<"FOO">BAR';
|
||||||
?>
|
?>
|
||||||
@php
|
@php
|
||||||
$bar = ['Rhy', 'miX', 'is', 'da', 'BEST!'];
|
$bar = ['Rhy', 'miX', 'is', 'da', 'BEST!'];
|
||||||
|
|
@ -61,5 +61,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
const foo = '{{ $foo }}';
|
||||||
const bar = @json($bar);
|
const bar = @json($bar);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,7 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
{
|
{
|
||||||
// Basic usage of XE-style single braces
|
// Basic usage of XE-style single braces
|
||||||
$source = '{$var}';
|
$source = '{$var}';
|
||||||
$target = "<?php echo htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->var ?? '') : htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Single braces with space at beginning will not be parsed
|
// Single braces with space at beginning will not be parsed
|
||||||
|
|
@ -244,22 +244,22 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
|
|
||||||
// Single braces with space at end are OK
|
// Single braces with space at end are OK
|
||||||
$source = '{$var }';
|
$source = '{$var }';
|
||||||
$target = "<?php echo htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->var ?? '') : htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Correct handling of object property and array access
|
// Correct handling of object property and array access
|
||||||
$source = '{Context::getRequestVars()->$foo[$bar]}';
|
$source = '{Context::getRequestVars()->$foo[$bar]}';
|
||||||
$target = "<?php echo htmlspecialchars(Context::getRequestVars()->{\$__Context->foo}[\$__Context->bar], \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(Context::getRequestVars()->{\$__Context->foo}[\$__Context->bar]) : htmlspecialchars(Context::getRequestVars()->{\$__Context->foo}[\$__Context->bar], \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Basic usage of Blade-style double braces
|
// Basic usage of Blade-style double braces
|
||||||
$source = '{{ $var }}';
|
$source = '{{ $var }}';
|
||||||
$target = "<?php echo htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->var ?? '') : htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Double braces without spaces are OK
|
// Double braces without spaces are OK
|
||||||
$source = '{{$var}}';
|
$source = '{{$var}}';
|
||||||
$target = "<?php echo htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->var ?? '') : htmlspecialchars(\$__Context->var ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Literal double braces
|
// Literal double braces
|
||||||
|
|
@ -273,13 +273,13 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Callback function inside echo statement
|
// Callback function inside echo statement
|
||||||
$source = '{{ implode("|", array_map(function(\$i) { return \$i + 1; }, $list) }}';
|
$source = '{{ implode("|", array_map(function(\$i) { return \$i + 1; }, $list) | noescape }}';
|
||||||
$target = "<?php echo htmlspecialchars(implode(\"|\", array_map(function(\$i) { return \$i + 1; }, \$__Context->list), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo implode(\"|\", array_map(function(\$i) { return \$i + 1; }, \$__Context->list); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Multiline echo statement
|
// Multiline echo statement
|
||||||
$source = '{{ $foo ?' . "\n" . ' date($foo) :' . "\n" . ' toBool($bar) }}';
|
$source = '{{ $foo ?' . "\n" . ' date($foo) :' . "\n" . ' toBool($bar) }}';
|
||||||
$target = "<?php echo htmlspecialchars(\$__Context->foo ?\n date(\$__Context->foo) :\n toBool(\$__Context->bar), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->foo ? date(\$__Context->foo) : toBool(\$__Context->bar)) : htmlspecialchars(\$__Context->foo ?\n date(\$__Context->foo) :\n toBool(\$__Context->bar), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -315,9 +315,17 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
$target = "<?php echo htmlspecialchars(\$__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo htmlspecialchars(\$__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Autolang
|
// Autolang (lang codes are not escaped, but escape_js() is applied in JS context)
|
||||||
$source = '{{ $foo|autolang }}';
|
$source = '{{ $foo|autolang }}';
|
||||||
$target = "<?php echo (preg_match('/^$(?:user_)?lang->\w+$/', \$__Context->foo ?? '') ? (\$__Context->foo ?? '') : htmlspecialchars(\$__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false)); ?>";
|
$target = "<?php echo (preg_match('/^\\\$(?:user_)?lang->\w+$/', \$__Context->foo ?? '') ? (\$__Context->foo ?? '') : htmlspecialchars(\$__Context->foo ?? '', \ENT_QUOTES, 'UTF-8', false)); ?>";
|
||||||
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
|
$source = '{{ $lang->cmd_hello_world }}';
|
||||||
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->lang->cmd_hello_world) : (\$__Context->lang->cmd_hello_world); ?>";
|
||||||
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
|
$source = '{{ $user_lang->user_lang_1234567890 }}';
|
||||||
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->user_lang->user_lang_1234567890 ?? '') : (\$__Context->user_lang->user_lang_1234567890 ?? ''); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Escape
|
// Escape
|
||||||
|
|
@ -344,19 +352,19 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
$source = '{{ $foo|json }}';
|
$source = '{{ $foo|json }}';
|
||||||
$target = implode('', [
|
$target = implode('', [
|
||||||
"<?php echo \$this->config->context === 'JS' ? ",
|
"<?php echo \$this->config->context === 'JS' ? ",
|
||||||
"(json_encode(\$__Context->foo ?? '', \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT)) : ",
|
"json_encode(\$__Context->foo ?? '', self::\$_json_options) : ",
|
||||||
"htmlspecialchars(json_encode(\$__Context->foo ?? '', \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT), \ENT_QUOTES, 'UTF-8', false); ?>",
|
"htmlspecialchars(json_encode(\$__Context->foo ?? '', self::\$_json_options), \ENT_QUOTES, 'UTF-8', false); ?>",
|
||||||
]);
|
]);
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// strip_tags
|
// strip_tags
|
||||||
$source = '{{ $foo|strip }}';
|
$source = '{{ $foo|strip }}';
|
||||||
$target = "<?php echo htmlspecialchars(strip_tags(\$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(strip_tags(\$__Context->foo ?? '')) : htmlspecialchars(strip_tags(\$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// strip_tags (alternate name)
|
// strip_tags (alternate name)
|
||||||
$source = '{{ $foo|upper|strip_tags }}';
|
$source = '{{ $foo|upper|strip_tags }}';
|
||||||
$target = "<?php echo htmlspecialchars(strip_tags(strtoupper(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(strip_tags(strtoupper(\$__Context->foo ?? ''))) : htmlspecialchars(strip_tags(strtoupper(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Trim
|
// Trim
|
||||||
|
|
@ -366,12 +374,12 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
|
|
||||||
// URL encode
|
// URL encode
|
||||||
$source = '{{ $foo|trim|urlencode }}';
|
$source = '{{ $foo|trim|urlencode }}';
|
||||||
$target = "<?php echo htmlspecialchars(rawurlencode(trim(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(rawurlencode(trim(\$__Context->foo ?? ''))) : htmlspecialchars(rawurlencode(trim(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Lowercase
|
// Lowercase
|
||||||
$source = '{{ $foo|trim|lower }}';
|
$source = '{{ $foo|trim|lower }}';
|
||||||
$target = "<?php echo htmlspecialchars(strtolower(trim(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(strtolower(trim(\$__Context->foo ?? ''))) : htmlspecialchars(strtolower(trim(\$__Context->foo ?? '')), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Uppercase
|
// Uppercase
|
||||||
|
|
@ -391,62 +399,62 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
|
|
||||||
// Array join (default joiner is comma)
|
// Array join (default joiner is comma)
|
||||||
$source = '{{ $foo|join }}';
|
$source = '{{ $foo|join }}';
|
||||||
$target = "<?php echo htmlspecialchars(implode(', ', \$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(implode(', ', \$__Context->foo ?? '')) : htmlspecialchars(implode(', ', \$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Array join (custom joiner)
|
// Array join (custom joiner)
|
||||||
$source = '{{ $foo|join:"!@!" }}';
|
$source = '{{ $foo|join:"!@!" }}';
|
||||||
$target = "<?php echo htmlspecialchars(implode(\"!@!\", \$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(implode(\"!@!\", \$__Context->foo ?? '')) : htmlspecialchars(implode(\"!@!\", \$__Context->foo ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Date conversion (default format)
|
// Date conversion (default format)
|
||||||
$source = '{{ $item->regdate | date }}';
|
$source = '{{ $item->regdate | date }}';
|
||||||
$target = "<?php echo htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'Y-m-d H:i:s'), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'Y-m-d H:i:s')) : htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'Y-m-d H:i:s'), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Date conversion (custom format)
|
// Date conversion (custom format)
|
||||||
$source = "{{ \$item->regdate | date:'n/j H:i' }}";
|
$source = "{{ \$item->regdate | date:'n/j H:i' }}";
|
||||||
$target = "<?php echo htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'n/j H:i'), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'n/j H:i')) : htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), 'n/j H:i'), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Date conversion (custom format in variable)
|
// Date conversion (custom format in variable)
|
||||||
$source = "{{ \$item->regdate | date:\$format }}";
|
$source = "{{ \$item->regdate | date:\$format }}";
|
||||||
$target = "<?php echo htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), \$__Context->format), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), \$__Context->format)) : htmlspecialchars(getDisplayDateTime(ztime(\$__Context->item->regdate ?? ''), \$__Context->format), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Number format
|
// Number format
|
||||||
$source = '{{ $num | format }}';
|
$source = '{{ $num | format }}';
|
||||||
$target = "<?php echo htmlspecialchars(number_format(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(number_format(\$__Context->num ?? '')) : htmlspecialchars(number_format(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Number format (alternate name)
|
// Number format (alternate name)
|
||||||
$source = '{{ $num | number_format }}';
|
$source = '{{ $num | number_format }}';
|
||||||
$target = "<?php echo htmlspecialchars(number_format(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo \$this->config->context === 'JS' ? escape_js(number_format(\$__Context->num ?? '')) : htmlspecialchars(number_format(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Number format (custom format)
|
// Number format (custom format)
|
||||||
$source = '{{ $num | number_format:6 }}';
|
$source = '{{ $num | number_format:6 | noescape }}';
|
||||||
$target = "<?php echo htmlspecialchars(number_format(\$__Context->num ?? '', '6'), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo number_format(\$__Context->num ?? '', '6'); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Number format (custom format in variable)
|
// Number format (custom format in variable)
|
||||||
$source = '{{ $num | number_format:$digits }}';
|
$source = '{{ $num | number_format:$digits | noescape }}';
|
||||||
$target = "<?php echo htmlspecialchars(number_format(\$__Context->num ?? '', \$__Context->digits), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo number_format(\$__Context->num ?? '', \$__Context->digits); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Number shorten
|
// Number shorten
|
||||||
$source = '{{ $num | shorten }}';
|
$source = '{{ $num | shorten | noescape }}';
|
||||||
$target = "<?php echo htmlspecialchars(number_shorten(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo number_shorten(\$__Context->num ?? ''); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Number shorten (alternate name)
|
// Number shorten (alternate name)
|
||||||
$source = '{{ $num | number_shorten }}';
|
$source = '{{ $num | number_shorten | noescape }}';
|
||||||
$target = "<?php echo htmlspecialchars(number_shorten(\$__Context->num ?? ''), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo number_shorten(\$__Context->num ?? ''); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Number shorten (custom format)
|
// Number shorten (custom format)
|
||||||
$source = '{{ $num | number_shorten:1 }}';
|
$source = '{{ $num | number_shorten:1 | noescape }}';
|
||||||
$target = "<?php echo htmlspecialchars(number_shorten(\$__Context->num ?? '', '1'), \ENT_QUOTES, 'UTF-8', false); ?>";
|
$target = "<?php echo number_shorten(\$__Context->num ?? '', '1'); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Link
|
// Link
|
||||||
|
|
@ -489,12 +497,12 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
|
|
||||||
// $lang
|
// $lang
|
||||||
$source = "{!! \$lang->cmd_yes !!}";
|
$source = "{!! \$lang->cmd_yes !!}";
|
||||||
$target = "<?php echo \$__Context->lang->cmd_yes ?? ''; ?>";
|
$target = "<?php echo \$__Context->lang->cmd_yes; ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// $loop
|
// $loop
|
||||||
$source = "{!! \$loop->first !!}";
|
$source = "{!! \$loop->first !!}";
|
||||||
$target = "<?php echo end(self::\$_loopvars)->first; ?>";
|
$target = "<?php echo end(self::\$_loopvars)->first ?? ''; ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Escaped dollar sign
|
// Escaped dollar sign
|
||||||
|
|
@ -731,7 +739,7 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
]);
|
]);
|
||||||
$target = implode("\n", [
|
$target = implode("\n", [
|
||||||
"<?php if (\$this->_v2_errorExists('email', 'login')): ?>",
|
"<?php if (\$this->_v2_errorExists('email', 'login')): ?>",
|
||||||
"<?php echo htmlspecialchars(\$__Context->message ?? '', \ENT_QUOTES, 'UTF-8', false); ?>",
|
"<?php echo \$this->config->context === 'JS' ? escape_js(\$__Context->message ?? '') : htmlspecialchars(\$__Context->message ?? '', \ENT_QUOTES, 'UTF-8', false); ?>",
|
||||||
'<?php endif; ?>',
|
'<?php endif; ?>',
|
||||||
]);
|
]);
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
@ -800,6 +808,34 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
'<?php endif; ?>',
|
'<?php endif; ?>',
|
||||||
]);
|
]);
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
|
// @can and @cannot, @canany
|
||||||
|
$source = implode("\n", [
|
||||||
|
"@can('foo')",
|
||||||
|
'Hello World',
|
||||||
|
'@endcan',
|
||||||
|
"<!--@cannot('bar') -->",
|
||||||
|
"@canany(['foo', 'bar'])",
|
||||||
|
'Goodbye World',
|
||||||
|
'<!--@endcanany-->',
|
||||||
|
'<!--@end-->'
|
||||||
|
]);
|
||||||
|
$target = implode("\n", [
|
||||||
|
'<?php if ($this->_v2_checkCapability(1, \'foo\')): ?>',
|
||||||
|
'Hello World',
|
||||||
|
'<?php endif; ?>',
|
||||||
|
'<?php if ($this->_v2_checkCapability(2, \'bar\')): ?>',
|
||||||
|
'<?php if ($this->_v2_checkCapability(3, [\'foo\', \'bar\'])): ?>',
|
||||||
|
'Goodbye World',
|
||||||
|
'<?php endif; ?>',
|
||||||
|
'<?php endif; ?>',
|
||||||
|
]);
|
||||||
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
|
// @env
|
||||||
|
$source = "@env('foo') FOO @endenv";
|
||||||
|
$target = '<?php if (!empty($_ENV[\'foo\'])): ?> FOO <?php endif; ?>';
|
||||||
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInlineConditions()
|
public function testInlineConditions()
|
||||||
|
|
@ -866,8 +902,8 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
$source = '@json($var)';
|
$source = '@json($var)';
|
||||||
$target = implode('', [
|
$target = implode('', [
|
||||||
'<?php echo $this->config->context === \'JS\' ? ',
|
'<?php echo $this->config->context === \'JS\' ? ',
|
||||||
'json_encode($__Context->var, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT) : ',
|
'json_encode($__Context->var, self::$_json_options) : ',
|
||||||
'htmlspecialchars(json_encode($__Context->var, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT), \ENT_QUOTES, \'UTF-8\', false); ?>',
|
'htmlspecialchars(json_encode($__Context->var, self::$_json_options), \ENT_QUOTES, \'UTF-8\', false); ?>',
|
||||||
]);
|
]);
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
|
|
@ -875,8 +911,8 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
$source = '@json(["foo" => 1, "bar" => 2])';
|
$source = '@json(["foo" => 1, "bar" => 2])';
|
||||||
$target = implode('', [
|
$target = implode('', [
|
||||||
'<?php echo $this->config->context === \'JS\' ? ',
|
'<?php echo $this->config->context === \'JS\' ? ',
|
||||||
'json_encode(["foo" => 1, "bar" => 2], \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT) : ',
|
'json_encode(["foo" => 1, "bar" => 2], self::$_json_options) : ',
|
||||||
'htmlspecialchars(json_encode(["foo" => 1, "bar" => 2], \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES | \JSON_HEX_TAG | \JSON_HEX_QUOT), \ENT_QUOTES, \'UTF-8\', false); ?>',
|
'htmlspecialchars(json_encode(["foo" => 1, "bar" => 2], self::$_json_options), \ENT_QUOTES, \'UTF-8\', false); ?>',
|
||||||
]);
|
]);
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue