Done tag option :raw and :escape

This commit is contained in:
bzick 2014-05-06 00:45:37 +04:00
parent ac4ccd0fca
commit 783bf10b39
8 changed files with 153 additions and 73 deletions

View File

@ -1,5 +1,7 @@
{var:escape $a}
asdasd
{/var}
{Ts\Math::multi x=34 y=44}
{$a + Ts\Math::multi(34, 44)}
{34|Ts\Math::multi:44}
{*{Ts\Math::multi x=34 y=44}*}
{*{$a + Ts\Math::multi(34, 44)}*}
{*{34|Ts\Math::multi:44}*}

View File

@ -36,7 +36,7 @@ class Fenom
const FORCE_VERIFY = 0x800;
const AUTO_TRIM = 0x1000; // reserved
const DENY_STATICS = 0x2000;
const AUTO_STRIP = 0x4000; // reserved
const AUTO_STRIP = 0x4000;
/* @deprecated */
const DENY_INLINE_FUNCS = 0x20;

View File

@ -628,7 +628,7 @@ class Compiler
*/
public static function stdFuncParser(Tokenizer $tokens, Tag $tag)
{
return $tag->escape($tag->callback . "(" . self::toArray($tag->tpl->parseParams($tokens)) . ', $tpl)');
return $tag->out($tag->callback . "(" . self::toArray($tag->tpl->parseParams($tokens)) . ', $tpl)');
}
/**
@ -658,7 +658,7 @@ class Compiler
$args[] = var_export($param->getDefaultValue(), true);
}
}
return $tag->escape($tag->callback . "(" . implode(", ", $args) . ')');
return $tag->out($tag->callback . "(" . implode(", ", $args) . ')');
}
/**
@ -672,6 +672,7 @@ class Compiler
public static function stdFuncOpen(Tokenizer $tokens, Tag $tag)
{
$tag["params"] = self::toArray($tag->tpl->parseParams($tokens));
$tag->setOption(\Fenom::AUTO_ESCAPE, false);
return 'ob_start();';
}
@ -685,7 +686,8 @@ class Compiler
*/
public static function stdFuncClose($tokens, Tag $tag)
{
return $tag->escape($tag->callback . '(' . $tag["params"] . ', ob_get_clean(), $tpl)');
$tag->restore(\Fenom::AUTO_ESCAPE);
return $tag->out($tag->callback . '(' . $tag["params"] . ', ob_get_clean(), $tpl)');
}
/**
@ -944,23 +946,19 @@ class Compiler
/**
* @param Tokenizer $tokens
* @param Tag $scope
* @param Tag $tag
*/
public static function autoescapeOpen(Tokenizer $tokens, Tag $scope)
public static function autoescapeOpen(Tokenizer $tokens, Tag $tag)
{
$boolean = ($tokens->get(T_STRING) == "true" ? true : false);
$scope["escape"] = $scope->tpl->escape;
$scope->tpl->escape = $boolean;
$expected = ($tokens->get(T_STRING) == "true" ? true : false);
$tokens->next();
$tag->setOption(\Fenom::AUTO_ESCAPE, $expected);
}
/**
* @param Tokenizer $tokens
* @param Tag $scope
* @param Tag $tag
*/
public static function autoescapeClose(Tokenizer $tokens, Tag $scope)
{
$scope->tpl->escape = $scope["escape"];
}
public static function autoescapeClose(Tokenizer $tokens, Tag $tag) { }
}

View File

@ -16,15 +16,20 @@ class Tag extends \ArrayObject
const FUNC = 2;
const BLOCK = 4;
const LTRIM = 1;
const RTRIM = 2;
/**
* @var Template
*/
public $tpl;
public $name;
public $options;
public $options = array();
public $line = 0;
public $level = 0;
public $callback;
public $escape;
private $_offset = 0;
private $_closed = true;
@ -34,6 +39,7 @@ class Tag extends \ArrayObject
private $_close;
private $_tags = array();
private $_floats = array();
private $_changed = array();
/**
* Create tag entity
@ -51,6 +57,7 @@ class Tag extends \ArrayObject
$this->_body = & $body;
$this->_offset = strlen($body);
$this->_type = $info["type"];
$this->escape = $tpl->getOptions() & \Fenom::AUTO_ESCAPE;
if ($this->_type & self::BLOCK) {
$this->_open = $info["open"];
@ -70,10 +77,48 @@ class Tag extends \ArrayObject
/**
* Set tag option
* @param string $option
* @throws \RuntimeException
*/
public function setOption($option)
public function tagOption($option)
{
if(method_exists($this, 'opt'.$option)) {
$this->options[] = $option;
} else {
throw new \RuntimeException("Unknown tag option $option");
}
}
/**
* Rewrite template option for tag. When tag will be closed option will be reverted.
* @param int $option option constant
* @param bool $value true add option, false remove option
*/
public function setOption($option, $value) {
$actual = (bool)($this->tpl->getOptions() & $option);
if($actual != $value) {
$this->_changed[$option] = $actual;
$this->tpl->setOption(\Fenom::AUTO_ESCAPE, $value);
}
}
/**
* Restore the option
* @param int $option
*/
public function restore($option)
{
if(isset($this->_changed[$option])) {
$this->tpl->setOption($option, $this->_changed[$option]);
unset($this->_changed[$option]);
}
}
public function restoreAll()
{
foreach($this->_changed as $option => $value) {
$this->tpl->setOption($option, $this->_changed[$option]);
unset($this->_changed[$option]);
}
}
/**
@ -93,6 +138,10 @@ class Tag extends \ArrayObject
*/
public function start($tokenizer)
{
foreach($this->options as $option) {
$option = 'opt'.$option;
$this->$option();
}
return call_user_func($this->_open, $tokenizer, $this);
}
@ -146,7 +195,15 @@ class Tag extends \ArrayObject
throw new \LogicException("Tag {$this->name} already closed");
}
if ($this->_close) {
return call_user_func($this->_close, $tokenizer, $this);
foreach($this->options as $option) {
$option = 'opt'.$option.'end';
if(method_exists($this, $option)) {
$this->$option();
}
}
$code = call_user_func($this->_close, $tokenizer, $this);
$this->restoreAll();
return $code;
} else {
throw new \LogicException("Can not use a inline tag {$this->name} as a block");
}
@ -195,33 +252,23 @@ class Tag extends \ArrayObject
$this->_body .= $new_content;
}
public function escape($code)
/**
* Generate output code
* @param string $code
* @return string
*/
public function out($code)
{
return $this->tpl->out($code);
}
public function optLtrim()
{
}
public function optRtrim()
{
}
public function optTrim()
{
}
public function optRaw()
{
return $this->tpl->out($code, $this->escape);
}
public function optEscape()
{
$this->escape = true;
}
public function optRaw()
{
$this->escape = false;
}
}

View File

@ -26,6 +26,7 @@ class Template extends Render
{
const VAR_NAME = '$var';
const TPL_NAME = '$tpl';
/**
* Disable array parser.
*/
@ -287,6 +288,19 @@ class Template extends Render
}
}
/**
* Set or unset the option
* @param int $option
* @param bool $value
*/
public function setOption($option, $value) {
if($value) {
$this->_options |= $option;
} else {
$this->_options &= ~$option;
}
}
/**
* Execute some code at loading cache
* @param $code
@ -452,12 +466,16 @@ class Template extends Render
/**
* Output the value
*
* @param $data
* @param string $data
* @param null|bool $escape
* @return string
*/
public function out($data)
public function out($data, $escape = null)
{
if ($this->escape) {
if($escape === null) {
$escape = $this->_options & Fenom::AUTO_ESCAPE;
}
if ($escape) {
return "echo htmlspecialchars($data, ENT_COMPAT, 'UTF-8');";
} else {
return "echo $data;";
@ -590,11 +608,13 @@ class Template extends Render
$tag = new Tag($action, $this, $info, $this->_body);
if ($tokens->is(':')) { // parse tag options
do {
$tag->setOption($tokens->next()->need(T_STRING)->getAndNext());
$tag->tagOption($tokens->next()->need(T_STRING)->getAndNext());
} while ($tokens->is(':'));
}
$code = $tag->start($tokens);
if (!$tag->isClosed()) {
if ($tag->isClosed()) {
$tag->restoreAll();
} else {
array_push($this->_stack, $tag);
}
return $code;

View File

@ -6,6 +6,7 @@ namespace Fenom;
class AutoEscapeTest extends TestCase
{
public static function providerHTML()
{
$html = "<script>alert('injection');</script>";
@ -30,32 +31,32 @@ class AutoEscapeTest extends TestCase
array('{autoescape false}{raw $html}{/autoescape}, {$html}', "$html, $html", $vars, 0),
// inline function
// array('{test_function text=$html}, {$html}', "$html, $html", $vars, 0),
// array('{test_function text=$html}, {$html}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{test_function:raw text=$html}, {$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{test_function:raw text="{$html|up}"}, {$html}', strtoupper($html) . ", $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape true}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$escaped, $html", $vars, 0),
// array('{autoescape false}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape true}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape false}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
// array('{autoescape true}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
// array('{autoescape false}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape true}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape false}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
array('{test_function text=$html}, {$html}', "$html, $html", $vars, 0),
array('{test_function text=$html}, {$html}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{test_function:raw text=$html}, {$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{test_function:raw text="{$html|up}"}, {$html}', strtoupper($html) . ", $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$escaped, $html", $vars, 0),
array('{autoescape false}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape false}{test_function text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
array('{autoescape true}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
array('{autoescape false}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape false}{test_function:raw text=$html}{/autoescape}, {test_function text=$html}', "$html, $html", $vars, 0),
// block function
// array('{test_block_function}{$html}{/test_block_function}', $html, $vars, 0),
// array('{test_block_function}{$html}{/test_block_function}', $escaped, $vars, \Fenom::AUTO_ESCAPE),
// array('{test_block_function:raw}{$html}{/test_block_function}', $html, $vars, \Fenom::AUTO_ESCAPE),
// array('{test_block_function:raw}{"{$html|up}"}{/test_block_function}', strtoupper($html), $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape true}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $html", $vars, 0),
// array('{autoescape false}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape true}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape false}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $html", $vars, 0),
// array('{autoescape true}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $html", $vars, 0),
// array('{autoescape false}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape true}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
// array('{autoescape false}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $html", $vars, 0),
array('{test_block_function}{$html}{/test_block_function}', $html, $vars, 0),
array('{test_block_function}{$html}{/test_block_function}', $escaped, $vars, \Fenom::AUTO_ESCAPE),
array('{test_block_function:raw}{$html}{/test_block_function}', $html, $vars, \Fenom::AUTO_ESCAPE),
array('{test_block_function:raw}{"{$html|up}"}{/test_block_function}', strtoupper($html), $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $html", $vars, 0),
array('{autoescape false}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$escaped, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape false}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $html", $vars, 0),
array('{autoescape true}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $html", $vars, 0),
array('{autoescape false}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function}{$html}{/test_block_function}', "$html, $escaped", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_block_function}{$html}{/test_block_function}{/autoescape}, {test_block_function:raw}{$html}{/test_block_function}', "$escaped, $html", $vars, \Fenom::AUTO_ESCAPE),
array('{autoescape true}{test_block_function:raw}{$html}{/test_block_function}{/autoescape}, {test_block_function:raw}{$html}{/test_block_function}', "$html, $html", $vars, 0),
);
}

View File

@ -0,0 +1,12 @@
<?php
namespace Fenom;
class TagOptionTest extends TestCase {
public function testTrim() {
}
}

View File

@ -848,7 +848,7 @@ class TemplateTest extends TestCase
public function _testSandbox()
{
try {
var_dump($this->fenom->compileCode('{$a}')->getBody());
var_dump($this->fenom->setOptions(0)->compileCode("{autoescape true}{test_block_function:raw}{\$html}{/test_block_function}{/autoescape}")->getBody());
} catch (\Exception $e) {
print_r($e->getMessage() . "\n" . $e->getTraceAsString());
while ($e->getPrevious()) {