Escaping any data which comes from the server is important to escape, as it prevents XSS amongst other things.
The Zend Framework view component Zend_View let’s you escape template variables with $this->escape($this->variableName), but it doesn’t escape them by default. Wouldn’t it be much nicer if it did that by default, or at least provided you with a variable to turn it on/off?
Let’s find out how to do that!
Start
First, we need to understand how the internals of Zend_View work.
Zend_View_Abstract saves the assigned template variables in the object itself, so we need to get those. This can be done with the PHP function get_object_vars, but luckily Zend has provided us with a method in the Zend_View_Abstract class itself that we can use: getVars().
With getVars, we can get all the template variables assigned to the view.
The best time to escape the variables would probably be before the view script is rendered, so we can override the _run method. There’s something we have to consider, though: If we were to render multiple things with the same view, or if we did something with the view’s variables after rendering, we would be better off with the non-escaped versions of the variables.
Now that we know our stuff, let’s proceed to the coding part
Coding it
So, we will be extending the Zend_View class. I’m calling the new class CU_View_AutoEscape.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <?php require_once 'Zend/View.php'; class CU_View_AutoEscape extends Zend_View { public $autoEscape = false; protected function _run() { $varBackup = null; if($this->autoEscape) { $vars = $this->getVars(); $varBackup = $vars; foreach($vars as $k => $v) $this->$k = $this->escape($v); } parent::_run(func_get_arg(0)); if($varBackup !== null) $this->assign($varBackup); } } |
Not a big block of code. First we define the variable to control the escaping on line 6, then we override the _run method.
The run method then checks if we have enabled automatic escaping, gets the variables and backs them up so that we can return the old, unescaped variables back after rendering, assigns the escaped variables, renders and returns the backup.
It’s a nice little extension, but there’s a small problem…
If we wanted to use a new view class now, perhaps we’re switching to Smarty for views, we would have to re-write the code! This extended view class isn’t very useful with other kinds of views, so what can we do?
Improving the concept
So, rather than making a bulky extension like this, we could make this a view helper!
With a view helper, we won’t get fully automatic escaping, though, but we can still save us from filling our templates with extra clutter. A view helper should also work out of the box with most other kinds of view classes you may have because the view helper isn’t bound on a certain class inheritance chain. It has its disadvantage, but I think the advantages it gives us win.
Converting the above code into a view helper is not difficult. We simply need to make the view helper act like a container for the escaped variables and provide functions for escaping and maybe unescaping too.
The AutoEscape View Helper
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php class Zend_View_Helper_AutoEscape { private $_unescapedVars = null; private $_view; public function setView($view) { $this->_view = $view; } public function autoEscape() { if($this->_unescapedVars === null) { $vars = $this->_view->getVars(); $this->_unescapedVars = $vars; foreach($vars as $k => $v) $this->_view->$k = $this->_view->escape($v); } else { $this->_view->assign($this->_unescapedVars); $this->_unescapedVars = null; } } } |
As you can see, it’s somewhat similar to the earlier class. The view helper works like this: when you call it, it will save the variables from the view, then escape them. Next time you call it, it will return back the original variables.
This way you can easily just escape and unescape things when you want. Note that if you assign variables to the view after escaping, you will need to unescape and re-escape, so that the new variable will show up escaped as well.
Conclusion
So both approaches really have their advantages and disadvantages. The view class method can be made so that the escaping happens automatically and even on new assignments, but it isn’t easily “moved” to a new view class if you ever want to change it. The view helper on the other hand can be easily used with different kinds of view classes, but it doesn’t automatically escape things.
But whichever the method, I still like the fact that I wouldn’t need to write the $this->escape for every variable… and if I ever did forget that, it wouldn’t matter because it would be escaped anyway.