diff options
-rw-r--r-- | src/ste/STECore.php | 19 | ||||
-rw-r--r-- | src/ste/STEStandardLibrary.php | 18 | ||||
-rw-r--r-- | src/ste/Transcompiler.php | 10 | ||||
-rw-r--r-- | tests/test_autoescape/.gitignore | 3 | ||||
-rw-r--r-- | tests/test_autoescape/code.php | 14 | ||||
-rw-r--r-- | tests/test_autoescape/test.tpl | 29 | ||||
-rw-r--r-- | tests/test_autoescape/want | 25 |
7 files changed, 113 insertions, 5 deletions
diff --git a/src/ste/STECore.php b/src/ste/STECore.php index 35a92d5..4637aaa 100644 --- a/src/ste/STECore.php +++ b/src/ste/STECore.php @@ -10,9 +10,13 @@ namespace kch42\ste; * The Core of STE */ class STECore { + const ESCAPE_NONE = "none"; + const ESCAPE_HTML = "html"; + private $tags; private $storage_access; private $cur_tpl_dir; + public $escape_method = self::ESCAPE_NONE; public $scope; /* @@ -101,6 +105,21 @@ class STECore { } } + public function autoescape($content) { + if ($this->escape_method == self::ESCAPE_HTML) { + return htmlspecialchars($content); + } + return $content; + } + + public function eval_sub_with_escaping($sub, $method) { + $old_method = $this->escape_method; + $this->escape_method = $method; + $retval = $sub($this); + $this->escape_method = $old_method; + return $retval; + } + public function calc($expression) { return Calc::calc($expression); } diff --git a/src/ste/STEStandardLibrary.php b/src/ste/STEStandardLibrary.php index 915b699..68ba06a 100644 --- a/src/ste/STEStandardLibrary.php +++ b/src/ste/STEStandardLibrary.php @@ -12,13 +12,27 @@ class STEStandardLibrary { } static public function escape($ste, $params, $sub) { + $content = $ste->eval_sub_with_escaping($sub, STECore::ESCAPE_NONE); + if($ste->evalbool(@$params["lines"])) { - return nl2br(htmlspecialchars(str_replace("\r\n", "\n", $sub($ste)))); + return nl2br(htmlspecialchars(str_replace("\r\n", "\n", $content))); } else { - return htmlspecialchars($sub($ste)); + return htmlspecialchars($content); } } + static public function raw($ste, $params, $sub) { + return $ste->eval_sub_with_escaping($sub, STECore::ESCAPE_NONE); + } + + static public function autoescape($ste, $params, $sub) { + if(empty($params["mode"])) { + throw new RuntimeError("Missing mode parameter in <ste:arraylen>."); + } + + return $content = $ste->eval_sub_with_escaping($sub, $params['mode']); + } + static public function strlen($ste, $params, $sub) { return strlen($sub($ste)); } diff --git a/src/ste/Transcompiler.php b/src/ste/Transcompiler.php index 12fc59d..9961b15 100644 --- a/src/ste/Transcompiler.php +++ b/src/ste/Transcompiler.php @@ -401,7 +401,7 @@ class Transcompiler { return "try\n{\n" . self::indent_code($code) . "\n}\ncatch(\\kch42\\ste\\BreakException \$e) { break; }\ncatch(\\kch42\\ste\\ContinueException \$e) { continue; }\n"; } - private static function _transcompile($ast, $avoid_outputstack = false) { /* The real self::transcompile function, does not add boilerplate code. */ + private static function _transcompile($ast, $avoid_outputstack = false, $in_args = false) { /* The real self::transcompile function, does not add boilerplate code. */ $code = ""; $text_and_var_buffer = array(); @@ -410,7 +410,11 @@ class Transcompiler { if($node instanceof TextNode) { $text_and_var_buffer[] = '"' . Misc::escape_text($node->text) . '"'; } else if($node instanceof VariableNode) { - $text_and_var_buffer[] = $node->transcompile(); + if ($in_args) { + $text_and_var_buffer[] = $node->transcompile(); + } else { + $text_and_var_buffer[] = "\$ste->autoescape(".$node->transcompile().")"; + } } else if($node instanceof TagNode) { if(!empty($text_and_var_buffer)) { $code .= "\$outputstack[\$outputstack_i] .= " . implode (" . ", $text_and_var_buffer) . ";\n"; @@ -423,7 +427,7 @@ class Transcompiler { $code .= "\$$paramarray = array();\n"; foreach($node->params as $pname => $pcontent) { - list($pval, $pre) = self::_transcompile($pcontent, true); + list($pval, $pre) = self::_transcompile($pcontent, true, true); $code .= $pre . "\$${paramarray}['" . Misc::escape_text($pname) . "'] = " . $pval . ";\n"; } diff --git a/tests/test_autoescape/.gitignore b/tests/test_autoescape/.gitignore new file mode 100644 index 0000000..de2a41b --- /dev/null +++ b/tests/test_autoescape/.gitignore @@ -0,0 +1,3 @@ +have +*.ast +*.transc.php diff --git a/tests/test_autoescape/code.php b/tests/test_autoescape/code.php new file mode 100644 index 0000000..4f7c998 --- /dev/null +++ b/tests/test_autoescape/code.php @@ -0,0 +1,14 @@ +<?php + +use kch42\ste\STECore; + +function test_func($ste) { + $ste->vars['test'] = 'foo"&<bar>'; + + $ste->register_tag('echoarg', function ($ste, $params, $sub) { + return $params['echo']; + }); + + // Autoescaping enabled by default + $ste->escape_method = STECore::ESCAPE_HTML; +} diff --git a/tests/test_autoescape/test.tpl b/tests/test_autoescape/test.tpl new file mode 100644 index 0000000..9452972 --- /dev/null +++ b/tests/test_autoescape/test.tpl @@ -0,0 +1,29 @@ +outer 1: $test +escaped outer 1: <ste:escape>$test</ste:escape> +double escaped outer 1: <ste:escape><ste:escape>$test</ste:escape></ste:escape> +raw outer 1: <ste:raw>$test</ste:raw> +arg outer 1: <ste:echoarg echo="$test" /> +<ste:autoescape mode="none"> +nested 1: $test +escaped nested 1: <ste:escape>$test</ste:escape> +double escaped nested 1: <ste:escape><ste:escape>$test</ste:escape></ste:escape> +raw nested 1: <ste:raw>$test</ste:raw> +arg nested 1: <ste:echoarg echo="$test" /> +<ste:autoescape mode="html"> +innermost: $test +escaped innermost: <ste:escape>$test</ste:escape> +double escaped innermost: <ste:escape><ste:escape>$test</ste:escape></ste:escape> +raw innermost: <ste:raw>$test</ste:raw> +arg innermost: <ste:echoarg echo="$test" /> +</ste:autoescape> +nested 2: $test +escaped nested 2: <ste:escape>$test</ste:escape> +double escaped nested 2: <ste:escape><ste:escape>$test</ste:escape></ste:escape> +raw nested 2: <ste:raw>$test</ste:raw> +arg nested 2: <ste:echoarg echo="$test" /> +</ste:autoescape> +outer 2: $test +escaped outer 2: <ste:escape>$test</ste:escape> +double escaped outer 2: <ste:escape><ste:escape>$test</ste:escape></ste:escape> +raw outer 2: <ste:raw>$test</ste:raw> +arg outer 2: <ste:echoarg echo="$test" /> diff --git a/tests/test_autoescape/want b/tests/test_autoescape/want new file mode 100644 index 0000000..0d06d44 --- /dev/null +++ b/tests/test_autoescape/want @@ -0,0 +1,25 @@ +outer 1: foo"&<bar> +escaped outer 1: foo"&<bar> +double escaped outer 1: foo&quot;&amp;&lt;bar&gt; +raw outer 1: foo"&<bar> +arg outer 1: foo"&<bar> +nested 1: foo"&<bar> +escaped nested 1: foo"&<bar> +double escaped nested 1: foo&quot;&amp;&lt;bar&gt; +raw nested 1: foo"&<bar> +arg nested 1: foo"&<bar> +innermost: foo"&<bar> +escaped innermost: foo"&<bar> +double escaped innermost: foo&quot;&amp;&lt;bar&gt; +raw innermost: foo"&<bar> +arg innermost: foo"&<bar> +nested 2: foo"&<bar> +escaped nested 2: foo"&<bar> +double escaped nested 2: foo&quot;&amp;&lt;bar&gt; +raw nested 2: foo"&<bar> +arg nested 2: foo"&<bar> +outer 2: foo"&<bar> +escaped outer 2: foo"&<bar> +double escaped outer 2: foo&quot;&amp;&lt;bar&gt; +raw outer 2: foo"&<bar> +arg outer 2: foo"&<bar> |