Zend_View View Scripts: Variable Escaping & Custom Template Engines

Once a Zend Framework controller assigns variables and invokes render(), Zend_View includes the requested PHP view script and executes it directly inside the scope of the Zend_View instance. Because execution occurs within the object context, all references to $this inside a view script point to the active Zend_View instance itself.

Controller Variable Assignment & Instance Scope

Variables passed from the action controller to the view are accessed as instance properties on $this. For example, if a controller assigns a variable named something, the view script references it as $this->something. This explicit property boundary cleanly separates controller-assigned data from local temporary variables declared inside the template.

<?php if ($this->books): ?>
    <!-- A table of some books. -->
    <table>
        <tr>
            <th>Author</th>
            <th>Title</th>
        </tr>
        <?php foreach ($this->books as $key => $val): ?>
        <tr>
            <td><?php echo $this->escape($val['author']); ?></td>
            <td><?php echo $this->escape($val['title']); ?></td>
        </tr>
        <?php endforeach; ?>
    </table>
<?php else: ?>
    <p>There are no books to display.</p>
<?php endif; ?>

Output Escaping & Cross-Site Scripting (XSS) Prevention

One of the most critical responsibilities of any view script is ensuring that dynamic variables are properly encoded before being emitted into the HTML DOM. Unless a view helper already performs output encoding internally, you should always wrap dynamic properties in $this->escape() to neutralize Cross-Site Scripting (XSS) payloads.

// Bad view-script practice (vulnerable to reflected/stored XSS):
echo $this->variable;

// Good view-script practice:
echo $this->escape($this->variable);

Customizing Escaping Callbacks with setEscape()

By default, Zend_View::escape() delegates to PHP's native htmlspecialchars() function. Depending on character-set requirements or security policies, you can override the escaping callback at the controller layer using setEscape(). The registered callback must accept the value to be escaped as its first parameter, with all subsequent parameters optional:

// Instantiate Zend_View
$view = new Zend_View();

// 1. Use PHP htmlentities() as the escaping callback
$view->setEscape('htmlentities');

// 2. Or register a static class method as the callback
$view->setEscape(array('SomeClass', 'methodName'));

// 3. Or register an instance method callback
$obj = new SomeClass();
$view->setEscape(array($obj, 'methodName'));

// Render the view output
echo $view->render('booklist.phtml');

Integrating Alternate Template Engines

Although native PHP is itself a fast and expressive template engine, some teams prefer restricted template DSLs for frontend designers. Zend_View supports two integration patterns: instantiating a template object inside a view script, or implementing Zend_View_Interface.

Pattern 1: Manipulating a PHPLIB-Style Template Inside a View Script

A standard Zend_View script can instantiate and orchestrate a separate template object such as PHPLIB's Template class:

include_once 'template.inc';
$tpl = new Template();

if ($this->books) {
    $tpl->setFile(array(
        'booklist' => 'booklist.tpl',
        'eachbook' => 'eachbook.tpl',
    ));

    foreach ($this->books as $key => $val) {
        $tpl->set_var('author', $this->escape($val['author']));
        $tpl->set_var('title', $this->escape($val['title']));
        $tpl->parse('books', 'eachbook', true);
    }

    $tpl->pparse('output', 'booklist');
} else {
    $tpl->setFile('nobooks', 'nobooks.tpl');
    $tpl->pparse('output', 'nobooks');
}

The corresponding PHPLIB template files define placeholders for the parsed blocks:

<!-- booklist.tpl -->
<table>
    <tr>
        <th>Author</th>
        <th>Title</th>
    </tr>
    {books}
</table>

<!-- eachbook.tpl -->
<tr>
    <td>{author}</td>
    <td>{title}</td>
</tr>

<!-- nobooks.tpl -->
<p>There are no books to display.</p>

Pattern 2: Implementing Zend_View_Interface for Smarty

For deep integration with Zend Framework's ViewRenderer action helper, implement Zend_View_Interface directly. The interface defines the minimum contract required for any compatible view engine:

interface Zend_View_Interface
{
    public function getEngine();
    public function setScriptPath($path);
    public function getScriptPaths();
    public function setBasePath($path, $prefix = 'Zend_View');
    public function addBasePath($path, $prefix = 'Zend_View');
    public function __set($key, $value);
    public function __isset($key);
    public function __unset($key);
    public function assign($spec, $value = null);
    public function clearVars();
    public function render($name);
}

Below is a complete Zend_View_Smarty adapter implementation wrapping the Smarty template engine:

class Zend_View_Smarty implements Zend_View_Interface
{
    /**
     * @var Smarty
     */
    protected $_smarty;

    public function __construct($tmplPath = null, $extraParams = array())
    {
        $this->_smarty = new Smarty();

        if (null !== $tmplPath) {
            $this->setScriptPath($tmplPath);
        }

        foreach ($extraParams as $key => $value) {
            $this->_smarty->$key = $value;
        }
    }

    public function getEngine()
    {
        return $this->_smarty;
    }

    public function setScriptPath($path)
    {
        if (is_readable($path)) {
            $this->_smarty->template_dir = $path;
            return;
        }
        throw new Exception('Invalid path provided');
    }

    public function getScriptPaths()
    {
        return array($this->_smarty->template_dir);
    }

    public function setBasePath($path, $prefix = 'Zend_View')
    {
        return $this->setScriptPath($path);
    }

    public function addBasePath($path, $prefix = 'Zend_View')
    {
        return $this->setScriptPath($path);
    }

    public function __set($key, $val)
    {
        $this->_smarty->assign($key, $val);
    }

    public function __isset($key)
    {
        return (null !== $this->_smarty->get_template_vars($key));
    }

    public function __unset($key)
    {
        $this->_smarty->clear_assign($key);
    }

    public function assign($spec, $value = null)
    {
        if (is_array($spec)) {
            $this->_smarty->assign($spec);
            return;
        }
        $this->_smarty->assign($spec, $value);
    }

    public function clearVars()
    {
        $this->_smarty->clear_all_assign();
    }

    public function render($name)
    {
        return $this->_smarty->fetch($name);
    }
}

Registering the Custom Engine with ViewRenderer

Once Zend_View_Smarty is defined, register it in your application bootstrap or controller init() lifecycle hook via the ViewRenderer action helper:

$view = new Zend_View_Smarty('/path/to/templates');
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$viewRenderer->setView($view)
             ->setViewBasePathSpec($view->getEngine()->template_dir)
             ->setViewScriptPathSpec(':controller/:action.:suffix')
             ->setViewScriptPathNoControllerSpec(':action.:suffix')
             ->setViewSuffix('tpl');