Re: [SMARTY-DEV] [patch] add $smarty->escape_output feature
[email protected] (Andreas Korthaus) Thu, 04 May 2006 18:19:06 +0200
| Newsgroups | php.smarty.dev |
|---|---|
| Message-ID | <[email protected]> |
Hi!
Monte Ohrt wrote:
> I don't think you should require this in the template:
>
> {if $foo|noescape eq "<bar>"}
I don't require that!
When I apply my patch and try the following code:
xss.php:
<?php
$smarty = new Smarty();
$smarty->escape_output='html';
$smarty->assign('xss', '<xss>');
$smarty->display('xss.tpl');
?>
xss.tpl:
{$xss}
{$xss|noescape}
{if $xss eq "<xss>"}ESCAPE{/if}
{if $xss eq "<xss>"}NOESCAPE{/if}
I get the following output:
<xss>
<xss>
NOESCAPE
That's because I don't apply a (default_)modifier on a variable, but I
change what the compiler does when writing "echo $variable" to the
compiled template. The "heart" of my change is the following in function
_compile_tag() from Smarty_Compiler.class.php (line 435).
Before my change:
if (preg_match(
'~^' .
$this->_num_const_regexp . '|' .
$this->_obj_call_regexp . '|' .
$this->_var_regexp . '$~', $tag_command)) {
$_return = $this->_parse_var_props($tag_command . $tag_modifier);
return "<?php echo $_return; ?>" . $this->_additional_newline;
}
After my change:
if (preg_match(
'~^' .
$this->_num_const_regexp . '|' .
$this->_obj_call_regexp . '|' .
$this->_var_regexp . '$~', $tag_command)) {
$_return = $this->_parse_var_props($tag_command . $tag_modifier);
// THAT'S WHAT'S NEW:
$_return_escaped = $this->_escape_var($_return, $tag_modifier);
return "<?php echo $_return_escaped; " . $this->_additional_newline;
}
So only if the regular expression above is true, the "current tag" gets
escaped.
As far as I understand, block functions like {if} are parsed completely
somewhere else, with all included vars. And I don't need to catch them,
because value of variables INSIDE {if} will never be written to STDOUT
when the PHP interpreter executes the compiled template.
If you do
{if $var eq "<xss>"}{$var}{/if}
you don't have to worry about what you find in {if}. Only {$var} can
reach the users browser, and that's what is catched by my patch. {if}
only creates PHP-Code, which will be away after interpreting the PHP-script.
BUT: I'm not sure if there are more wholes in the smarty core compiler,
where variables like $var still can reach the browser using something
similar like {if}. It must be a function, which get's a variable as
input, and which becomes part of the output. That's what modifiers do,
so I added my escaping _after_ applying all modifiers. Perhaps you can
think about something else here?
Or perhaps you can think about a case, where escaping output from
modifers could be a bad idea?
It's important to realize, that $smarty->escape_output only makes sense,
if assigning HTML-Code from PHP to the template is considered to be
bad practice. Passing HTML _SHOULD_ be more difficult and uncomfortable.
If you excessively want to pass HTML to your templates,
$smarty->escape_output is not the right feature for you. If you want to
make these people happy too, you will end up with something like the
current $default_modifiers, which are not useful for anybody.
Of course there can allways be exceptions, that's what the "noescape"
modifier is for.
If a user doesn't agree with that, he should not use
$smarty->escape_output at all. That's the only way to come to a
clean/complete solution.
People also don't tend to use $default_template_handler_func if they are
happy with the default ;-)
> The engine should determine that $foo is not output (not echo()), so
> it shouldn't get escaped in the first place.
That's exactly what's happening with the patch ;-)
> foo is {$foo}
>
> That should get escaped. The compiled template would be something
> like: echo htmlspecialchars($this->_tpl_vars['foo'],ENT_QUOTES);
exactly! That's what my patch does.
boots thinks[1] about not using escape "modes" like
"html|htmlall|url|user_defined", but a callback-function. I'm not sure
how to add parameters to the callback function (like ENT_QUOTES and
UTF-8 for htmlspecialchars). If you have to add a user-space wrapper
function to pass the parameters, escaping becomes slower than my
solution, which hardcodes htmlspecialchars()... in the compiled templates.
What do you think about that?
[1]: http://www.phpinsider.com/smarty-forum/viewtopic.php?p=30374#30374
Best regards
Andreas