How to automatically escape template variables in Zend_View

November 10, 2007 – 10:20 am Tags: ,

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);
    }
}

Download the code

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;
        }
    }
}

Download the code

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.

Share this:

RSS feed Subscribe to my RSS feed

About the author

Jani is a 15 year veteran of the software industry. He's currently available for consulting

  1. 8 Responses to “How to automatically escape template variables in Zend_View”

  2. Hi,

    i have two questions:

    1. why are this vars private and not protected?
    private $_unescapedVars = null;
    private $_view;

    2. the escaping should be different regarding where you want to output the vars (escaping in javascript is other then html). How you handle this?

    By harbla on Jan 26, 2008

  3. I tend to make things private rather than protected, unless I’m intending to extend the class. If you want to change it, feel free.

    The point of this was mainly to demonstrate the concept. If you wanted to escape the output (ie. what the users sent or something) you probably would not want to run any JS code either.

    By Jani Hartikainen on Jan 26, 2008

  4. Hello,

    Using the method with extending Zend_View Class is failing.

    I got Warning: htmlspecialchars() expects parameter 1 to be string, array given in /usr/home/………/public_html/library/Zend/View/Abstract.php on line 782

    By Cristian on Feb 8, 2008

  5. You should check with is_string() and is_array().

    /**
    * Escapes strings and recursively iterates over arrays to escape all entries.
    *
    * @param mixed $original
    * @return mixed
    */
    protected function escapeDeep(&$original) {
    if (is_string($original))
    return $this->view->escape($original);
    elseif (is_array($original)) {
    foreach ($original as $k => $v) {
    $original[$k] = $this->escapeDeep($v);
    }
    }
    return $original;
    }

    And then replace your call to $this->_view->escape($v) with $this->escapeDeep($v)

    By Daniel on Feb 11, 2008

  6. Hi, thank you for your answer to my question on stackoverflow.com.
    http://stackoverflow.com/questions/3181425/whats-the-best-way-to-escape-vars-in-zend-view-automatically

    I’ve got my answer by myself.
    http://github.com/chikaram/gnix-view

    Please check it out when you feel like it.

    By chikaram on Oct 29, 2010

  7. Over at the PiKe project we build a custom stream wrapper that automatically escapes all view variables, with a MINIMAL performance hit! You can still get the RAW value with:

     

    Notice the “~” character. Checkout http://code.google.com/p/php-pike/wiki/Pike_View_Stream

    By Pieter Vogelaar on Sep 16, 2011

  8. Pieter, tried fixing the code in your comment to show up but it seems it was entirely filtered out. Not sure why, seems to work usually.

    By Jani Hartikainen on Sep 17, 2011

  9. Hi, I’ve been looking for an escaping tool. Unfortunately I have not found solutions.

    chikarams project looks good but now I’ve been released my own project with context switches for escaping like:
    html
    json
    nofilter (raw)

    see and help on:
    https://github.com/jensklose/ZendX_View_Autoescaping

    By Jens Klose on Feb 1, 2012

Post a Comment

You can use some HTML (a, em, strong, etc.). If you want to post code, use <pre lang="PHP">code here</pre> (you can replace PHP with the language you are posting)