summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Chabowski <kevin@kch42.de>2015-04-13 22:35:27 +0200
committerKevin Chabowski <kevin@kch42.de>2015-04-13 22:35:27 +0200
commitf744b3227b116d4f7ccd7c71f8b8498ebf86d85f (patch)
tree87a2ea0047c7587375986d3b1a2a31c05e8d36ce
parent6d1c13b05d16e89268403860e47743455ea0a2ff (diff)
downloadste-f744b3227b116d4f7ccd7c71f8b8498ebf86d85f.tar.gz
ste-f744b3227b116d4f7ccd7c71f8b8498ebf86d85f.tar.bz2
ste-f744b3227b116d4f7ccd7c71f8b8498ebf86d85f.zip
Implemented autoescaping
Still needs some cleanup and documentation.
-rw-r--r--src/ste/STECore.php19
-rw-r--r--src/ste/STEStandardLibrary.php18
-rw-r--r--src/ste/Transcompiler.php10
-rw-r--r--tests/test_autoescape/.gitignore3
-rw-r--r--tests/test_autoescape/code.php14
-rw-r--r--tests/test_autoescape/test.tpl29
-rw-r--r--tests/test_autoescape/want25
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&quot;&amp;&lt;bar&gt;
+escaped outer 1: foo&quot;&amp;&lt;bar&gt;
+double escaped outer 1: foo&amp;quot;&amp;amp;&amp;lt;bar&amp;gt;
+raw outer 1: foo"&<bar>
+arg outer 1: foo"&<bar>
+nested 1: foo"&<bar>
+escaped nested 1: foo&quot;&amp;&lt;bar&gt;
+double escaped nested 1: foo&amp;quot;&amp;amp;&amp;lt;bar&amp;gt;
+raw nested 1: foo"&<bar>
+arg nested 1: foo"&<bar>
+innermost: foo&quot;&amp;&lt;bar&gt;
+escaped innermost: foo&quot;&amp;&lt;bar&gt;
+double escaped innermost: foo&amp;quot;&amp;amp;&amp;lt;bar&amp;gt;
+raw innermost: foo"&<bar>
+arg innermost: foo"&<bar>
+nested 2: foo"&<bar>
+escaped nested 2: foo&quot;&amp;&lt;bar&gt;
+double escaped nested 2: foo&amp;quot;&amp;amp;&amp;lt;bar&amp;gt;
+raw nested 2: foo"&<bar>
+arg nested 2: foo"&<bar>
+outer 2: foo&quot;&amp;&lt;bar&gt;
+escaped outer 2: foo&quot;&amp;&lt;bar&gt;
+double escaped outer 2: foo&amp;quot;&amp;amp;&amp;lt;bar&amp;gt;
+raw outer 2: foo"&<bar>
+arg outer 2: foo"&<bar>