View previous topic :: View next topic |
Author |
Message |
stayclose Smarty Rookie
Joined: 16 Feb 2010 Posts: 9
|
Posted: Wed Jul 21, 2010 1:23 pm Post subject: variableFilter and bbcode parsing |
|
|
Hello Monte,
I am switching one of our sites over to Smarty3 RC3 and as such I've ran into some small problems. I am using the variable filter htmlspecialchars which works great except when you want to parse bbcode.
As is the case now, modifiers are applied first and after that the variable filter is applied. So, my bbcode modifier generates HMTL from [b] etc tags. Which are then escaped by the variable filter.
There are some solutions (in my opinion):
1) use nofilter and apply your own modifier to escape first, then apply smiley and bbcode modifiers. In my opinion this is not the best solution. Especially in this case where you already allow users to influence the output forgetting to apply to escape modifier can have some serious impact. Also it pretty much negates the usefulnes of autoescaping.
2) apply the variable filter before the modifiers. I think this is one of the safest options because you know the data your are working with is safe for displaying.
3) bypass the variable filter all together and auto escape when assigning. This is what I use with Smarty 2:
function assign($tpl_var_unsafe, $value_unsafe = null, $output_filter = TRUE)
{
$tpl_var = $tpl_var_unsafe;
$value = $value_unsafe;
if ($output_filter === TRUE) {
if (is_array($tpl_var_unsafe)) {
$tpl_var = $this->_output_filter($tpl_var_unsafe);
} else {
$value = $this->_output_filter($value_unsafe);
}
}
function _output_filter($in) {
if (is_array($in)) {
$out = array();
foreach ($in as $key => $value) {
if ($value != "") {
$out[$key] = $this->_output_filter($value);
}
}
} else {
$out = htmlspecialchars(iconv("UTF-8", "UTF-8//IGNORE", $in), ENT_QUOTES, "UTF-8", FALSE);
}
return $out;
}
NOTE: this also isn't the best solution since i'm missing the other methods by only doing this for assign()!
What would be the best solution in your opinion? Perhaps I am overlooking something in the docs and there's an even better solution. I also couldn't find anything related on the forum.
Thanks, |
|
Back to top |
|
U.Tews Administrator
Joined: 22 Nov 2006 Posts: 5068 Location: Hamburg / Germany
|
Posted: Wed Jul 21, 2010 6:10 pm Post subject: |
|
|
Well I never thought about this possible problem.
To your ideas:
1.) Currently this is the best workaround.
2.) This is the betst solution. However it requires some major changes in the parser for the modifier handling. I will try to implement this ASAP, but could take a few days until it's done.
3.) Even if this worked for you in Smarty2 but personally don't like this solution. In my opinion the filter should work on the output string and not on variables as they are assigned. You may want to use the variables for other purpose as output. When you run the filter also on these variables you may not gat the expected results. |
|
Back to top |
|
stayclose Smarty Rookie
Joined: 16 Feb 2010 Posts: 9
|
Posted: Thu Jul 22, 2010 9:36 am Post subject: |
|
|
Well, I agree with you on point 2. The filter should only be used on variables that are actually displayed.
Until the changes are visible in SVN I have implemented a simple method in class Smarty_Variable to get me going for now:
$this->value = $this->_variableFilter($value);
private function _variableFilter ($in)
{
if (is_array($in)) {
$out = array();
foreach ($in as $key => $value) {
if ($value != "") {
$out[$key] = $this->_variableFilter($value);
} else {
//print "[empty] key: $key, value: $value\n";
$out[$key] = $value;
}
}
} else {
if (is_string($in)) {
//print "[string] value: $in\n";
$out = htmlspecialchars(iconv("UTF-8", "UTF-8//IGNORE", $in), ENT_QUOTES, "UTF-8", FALSE);
} else {
//print "[non-string] value: $in\n";
$out = $in;
}
}
return $out;
}
The only thing to remember I see with option 2 is that when you want (for instance, ofcourse it depends on what your variable filter does!) HTML outputted you will have to add a modifier to negate the variable filter to that specific variable in your template. |
|
Back to top |
|
stayclose Smarty Rookie
Joined: 16 Feb 2010 Posts: 9
|
Posted: Thu Jul 22, 2010 11:16 am Post subject: |
|
|
After some testing I noticed a case where I would need a whole array not to be ran through a filter.
Ofcourse I could have added a modifier for each variable (there are a lot) but instead I temporarily implemented the following:
In smarty_internal_data.php:
public function assign($tpl_var, $value = null, $nocache = false, $scope = SMARTY_LOCAL_SCOPE, $variableFilter = true)
{
public function __construct ($value = null, $nocache = false, $scope = SMARTY_LOCAL_SCOPE, $variableFilter = true)
{
if ($variableFilter === true) {
$this->value = $this->_variableFilter($value);
} else {
$this->value = $value;
}
Where private function _variableFilter is the one from an earlier post.
Variable assignment should be like this:
$smarty->assign("myvar", $myvar, false, SMARTY_LOCAL_SCOPE, false);
Note that this is only useful in my specific case. |
|
Back to top |
|
U.Tews Administrator
Joined: 22 Nov 2006 Posts: 5068 Location: Hamburg / Germany
|
Posted: Fri Jul 23, 2010 1:12 pm Post subject: |
|
|
The execution order has now been changed. The variable filter does now run on output before the modifier.
Note that the execution of the variable filter is automatically context sensitive. It does run only when output is gererated.
Example with variable filter htmlspecialchars
Code: | {if $foo == '>'}{$foo}{/if} |
Assume that foo has '>' assigned. The filter does not run on $foo inside the if tag. So the compare will work. But it does run on {$foo} so the generated output is '?gt;'
The same does apply to default modifers. In contrast Smarty2 did run default modifers always which did create in many cases problems.
The change is in the SVN now. |
|
Back to top |
|
stayclose Smarty Rookie
Joined: 16 Feb 2010 Posts: 9
|
Posted: Fri Jul 23, 2010 3:44 pm Post subject: |
|
|
Hello Uwe,
After some initial testing everything seems to be working as I expected. I have applied the latest SVN code and thus removed my initial workaround. I think this is the most elegant way to go, in combination with 'nofilter' it is also very flexible. In my case it gives me the freedom needed and also gives me some extra speed by only running the variable filter on variables that are actually outputted.
Thanks
U.Tews wrote: | The execution order has now been changed. The variable filter does now run on output before the modifier.
Note that the execution of the variable filter is automatically context sensitive. It does run only when output is gererated.
Example with variable filter htmlspecialchars
Code: | {if $foo == '>'}{$foo}{/if} |
Assume that foo has '>' assigned. The filter does not run on $foo inside the if tag. So the compare will work. But it does run on {$foo} so the generated output is '?gt;'
The same does apply to default modifers. In contrast Smarty2 did run default modifers always which did create in many cases problems.
The change is in the SVN now. |
|
|
Back to top |
|
U.Tews Administrator
Joined: 22 Nov 2006 Posts: 5068 Location: Hamburg / Germany
|
Posted: Sat Jul 24, 2010 11:51 pm Post subject: |
|
|
I had introduced another bug which is fixed in the SVN now. |
|
Back to top |
|
thunberg Smarty Rookie
Joined: 08 Mar 2011 Posts: 6
|
Posted: Tue Mar 08, 2011 9:37 pm Post subject: |
|
|
I could be mistaken, but I believe version 3.0.7 once again incorrectly applies variable filters (or the mapped default_modifiers) after in-template modifiers as opposed to before.
The example I'm currently referring to applies an htmlentities-like variable filter and when outputting in a template using "|nl2br" the <br> tags are escaped.
Any suggestions? |
|
Back to top |
|
U.Tews Administrator
Joined: 22 Nov 2006 Posts: 5068 Location: Hamburg / Germany
|
Posted: Wed Mar 09, 2011 1:35 pm Post subject: |
|
|
The change got somehow lost.
This is now fixed in the SVN trunk version. |
|
Back to top |
|
thunberg Smarty Rookie
Joined: 08 Mar 2011 Posts: 6
|
Posted: Wed Mar 09, 2011 4:14 pm Post subject: |
|
|
Works perfectly now, thank you for fixing it. |
|
Back to top |
|
stayclose Smarty Rookie
Joined: 16 Feb 2010 Posts: 9
|
Posted: Tue Mar 22, 2011 8:44 am Post subject: |
|
|
I was having the exact same thing, I applied 3.0.7 but I only noticed it when I went on recompiling some templates.
I'm happy it is fixed in SVN
Thanks Uwe |
|
Back to top |
|
thunberg Smarty Rookie
Joined: 08 Mar 2011 Posts: 6
|
Posted: Mon Aug 20, 2012 10:49 pm Post subject: |
|
|
I think this has once again reverted. I recently upgraded from Smarty 3 SVN revision 3286 to 3.1, and my default modifiers are being run after the in-template modifiers. Here's an example of my setup (note that I have a page class that extends Smarty):
$this->default_modifiers = array('escape:"htmlall":"UTF-8"');
in the template:
{$event.details|truncate:190|nl2br}
Prior versions worked as expected, current version outputs a bunch of visibly escaped <br />.
Thank you in advance for the help. |
|
Back to top |
|
U.Tews Administrator
Joined: 22 Nov 2006 Posts: 5068 Location: Hamburg / Germany
|
Posted: Wed Aug 22, 2012 7:44 pm Post subject: |
|
|
When we introduced the $smarty->escape_html option flag we decided on the execution order documented here http://www.smarty.net/docs/en/variable.escape.html.tpl
Either way we go is wrong.
{$foo|strlen} is an argument pro “escapeHTML goes last”,
{$foo|nl2br} is an argument pro individual goes last”.
We think that modifier adding html tags are used less frequently that something like {$foo|escape|nl2br nofilter} is in order for such cases. |
|
Back to top |
|
thunberg Smarty Rookie
Joined: 08 Mar 2011 Posts: 6
|
Posted: Thu Aug 23, 2012 4:55 am Post subject: |
|
|
I appreciate both the reply and your continued work on Smarty, but unfortunately that does not help in my situation since the "escape_html" option uses "htmlspecialchars" and not the more complete "htmlentities".
Additionally, in your documentation it states that:
"Modifiers and Filters are run in the following order: modifier, default_modifier, $escape_html, registered variable filters, autoloaded variable filters, template instance's variable filters. Everything after default_modifier can be disabled with the nofilter flag."
Unless I'm ready that incorrectly, it would imply that "nofilter", unlike in the past, has no impact on whether or not default modifiers are applied. In practice though, in 3.1, "nofilter" does in fact prevent default modifiers from being applied (as I expected based on previous version behavior).
So I can plan for the above, is this a documentation or implementation error? |
|
Back to top |
|
thunberg Smarty Rookie
Joined: 08 Mar 2011 Posts: 6
|
Posted: Thu Aug 23, 2012 5:15 am Post subject: |
|
|
Additionally, since you've specifically added a separate method to escape HTML via "escape_html", wouldn't that nullify the argument against having "default_modifiers" run first? |
|
Back to top |
|
|