mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-04-02 01:52:10 +09:00
Add more context switches for inline scripts and styles
This commit is contained in:
parent
800eb2f444
commit
62eb6b2aae
3 changed files with 69 additions and 13 deletions
|
|
@ -179,20 +179,45 @@ class TemplateParser_v2
|
||||||
*/
|
*/
|
||||||
protected function _addContextSwitches(string $content): string
|
protected function _addContextSwitches(string $content): string
|
||||||
{
|
{
|
||||||
return preg_replace_callback('#(<script\b([^>]*)|</script)#i', function($match) {
|
// Inline styles.
|
||||||
|
$content = preg_replace_callback('#(?<=\s)(style=")([^"]*?)"#i', function($match) {
|
||||||
|
return $match[1] . '<?php $this->config->context = \'CSS\'; ?>' . $match[2] . '<?php $this->config->context = \'HTML\'; ?>"';
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// Inline scripts.
|
||||||
|
$content = preg_replace_callback('#(?<=\s)(href="javascript:|on[a-z]+=")([^"]*?)"#i', function($match) {
|
||||||
|
return $match[1] . '<?php $this->config->context = \'JS\'; ?>' . $match[2] . '<?php $this->config->context = \'HTML\'; ?>"';
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// <style> tags.
|
||||||
|
$content = preg_replace_callback('#(<style\b([^>]*)|</style)#i', function($match) {
|
||||||
if (substr($match[1], 1, 1) === '/')
|
if (substr($match[1], 1, 1) === '/')
|
||||||
{
|
{
|
||||||
return '<?php $this->config->context = "HTML"; ?>' . $match[1];
|
return '<?php $this->config->context = \'HTML\'; ?>' . $match[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $match[1] . '<?php $this->config->context = \'CSS\'; ?>';
|
||||||
|
}
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// <script> tags that aren't links.
|
||||||
|
$content = preg_replace_callback('#(<script\b([^>]*)|</script)#i', function($match) {
|
||||||
|
if (substr($match[1], 1, 1) === '/')
|
||||||
|
{
|
||||||
|
return '<?php $this->config->context = \'HTML\'; ?>' . $match[1];
|
||||||
}
|
}
|
||||||
elseif (!str_contains($match[2] ?? '', 'src="'))
|
elseif (!str_contains($match[2] ?? '', 'src="'))
|
||||||
{
|
{
|
||||||
return $match[1] . '<?php $this->config->context = "JS"; ?>';
|
return $match[1] . '<?php $this->config->context = \'JS\'; ?>';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return $match[0];
|
return $match[0];
|
||||||
}
|
}
|
||||||
}, $content);
|
}, $content);
|
||||||
|
|
||||||
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -203,7 +228,7 @@ class TemplateParser_v2
|
||||||
*/
|
*/
|
||||||
protected static function _removeContextSwitches(string $content): string
|
protected static function _removeContextSwitches(string $content): string
|
||||||
{
|
{
|
||||||
return preg_replace('#<\?php \$this->config->context = "[A-Z]+"; \?>#', '', $content);
|
return preg_replace('#<\?php \$this->config->context = \'[A-Z]+\'; \?>#', '', $content);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
]); ?>></span>
|
]); ?>></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript"<?php $this->config->context = "JS"; ?>>
|
<script type="text/javascript"<?php $this->config->context = 'JS'; ?>>
|
||||||
const foo = '<?php echo $this->config->context === 'JS' ? escape_js($__Context->foo ?? '') : htmlspecialchars($__Context->foo ?? '', \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_options2) : htmlspecialchars(json_encode($__Context->bar, self::$_json_options), \ENT_QUOTES, 'UTF-8', false); ?>;
|
const bar = <?php echo $this->config->context === 'JS' ? json_encode($__Context->bar, self::$_json_options2) : 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>
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,34 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testContextSwitches()
|
||||||
|
{
|
||||||
|
// <script> tag
|
||||||
|
$source = '<script type="text/javascript"> foobar(); </script>';
|
||||||
|
$target = '<script type="text/javascript"<?php $this->config->context = \'JS\'; ?>> foobar(); <?php $this->config->context = \'HTML\'; ?></script>';
|
||||||
|
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||||
|
|
||||||
|
// Inline script in link href
|
||||||
|
$source = '<a href="javascript:void(0)">Hello</a>';
|
||||||
|
$target = '<a href="javascript:<?php $this->config->context = \'JS\'; ?>void(0)<?php $this->config->context = \'HTML\'; ?>">Hello</a>';
|
||||||
|
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||||
|
|
||||||
|
// Inline script in event handler
|
||||||
|
$source = '<div class="foo" onClick="bar.barr()">Hello</div>';
|
||||||
|
$target = '<div class="foo" onClick="<?php $this->config->context = \'JS\'; ?>bar.barr()<?php $this->config->context = \'HTML\'; ?>">Hello</div>';
|
||||||
|
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||||
|
|
||||||
|
// <style> tag
|
||||||
|
$source = '<style> body { font-size: 16px; } </style>';
|
||||||
|
$target = '<style<?php $this->config->context = \'CSS\'; ?>> body { font-size: 16px; } <?php $this->config->context = \'HTML\'; ?></style>';
|
||||||
|
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||||
|
|
||||||
|
// Inline style
|
||||||
|
$source = '<div style="background-color: #ffffff;" class="foobar"><span></span></div>';
|
||||||
|
$target = '<div style="<?php $this->config->context = \'CSS\'; ?>background-color: #ffffff;<?php $this->config->context = \'HTML\'; ?>" class="foobar"><span></span></div>';
|
||||||
|
$this->assertEquals($target, $this->_parse($source, true, false));
|
||||||
|
}
|
||||||
|
|
||||||
public function testEchoStatements()
|
public function testEchoStatements()
|
||||||
{
|
{
|
||||||
// Basic usage of XE-style single braces
|
// Basic usage of XE-style single braces
|
||||||
|
|
@ -366,11 +394,6 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
$target = "<?php echo escape_js(\$__Context->foo ?? ''); ?>";
|
$target = "<?php echo escape_js(\$__Context->foo ?? ''); ?>";
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Context-aware escape
|
|
||||||
$source = '<script type="text/javascript"> foobar(); </script>';
|
|
||||||
$target = '<script type="text/javascript"<?php $this->config->context = "JS"; ?>> foobar(); <?php $this->config->context = "HTML"; ?></script>';
|
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
|
||||||
|
|
||||||
// JSON using context-aware escape
|
// JSON using context-aware escape
|
||||||
$source = '{{ $foo|json }}';
|
$source = '{{ $foo|json }}';
|
||||||
$target = implode('', [
|
$target = implode('', [
|
||||||
|
|
@ -573,7 +596,7 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
|
|
||||||
// Script tag with external path
|
// Script tag with external path
|
||||||
$source = '<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.0/js/bootstrap.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>';
|
$source = '<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.0/js/bootstrap.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>';
|
||||||
$target = '<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.0/js/bootstrap.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"><?php $this->config->context = "HTML"; ?></script>';
|
$target = '<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.0/js/bootstrap.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>';
|
||||||
$this->assertEquals($target, $this->_parse($source));
|
$this->assertEquals($target, $this->_parse($source));
|
||||||
|
|
||||||
// Absolute URL
|
// Absolute URL
|
||||||
|
|
@ -1295,9 +1318,10 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
*
|
*
|
||||||
* @param string $source
|
* @param string $source
|
||||||
* @param bool $force_v2 Disable version detection
|
* @param bool $force_v2 Disable version detection
|
||||||
|
* @param bool $remove_context_switches Remove context switches that make code difficult to read
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function _parse(string $source, bool $force_v2 = true): string
|
protected function _parse(string $source, bool $force_v2 = true, bool $remove_context_switches = true): string
|
||||||
{
|
{
|
||||||
$tmpl = new \Rhymix\Framework\Template('./tests/_data/template', 'empty.html');
|
$tmpl = new \Rhymix\Framework\Template('./tests/_data/template', 'empty.html');
|
||||||
if ($force_v2)
|
if ($force_v2)
|
||||||
|
|
@ -1309,6 +1333,13 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
|
||||||
{
|
{
|
||||||
$result = substr($result, strlen($this->prefix));
|
$result = substr($result, strlen($this->prefix));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove context switches.
|
||||||
|
if ($remove_context_switches)
|
||||||
|
{
|
||||||
|
$result = preg_replace('#<\?php \$this->config->context = \'[A-Z]+\'; \?>#', '', $result);
|
||||||
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue