Writing templates can be a pain. Securing it against cross-site scripting attacks can be even worse. Sick of writing htmlspecialchars($output, ENT_QUOTES)
again and again? And using htmlentities()
instead when escaping input for a JavaScript snippet? Why bother when there is a templating engine that can take care of all this dirty business?
Latte is a templating engine that comes shipped as a part of Nette framework, an open-source PHP framework of Czech origin. It is dual-licensed under New BSD and GNU GPL licenses. Latte automatically secures your templates against XSS exploits using context-aware escaping. And it makes writing templates a pleasure.
So, how do you output a variable in a secure way? Simply:
{$variable}
That's it. It gets automatically escaped, aware of its context, as seen in the example in the documentation:
// $movie = 'Amarcord & 8 1/2';
<p onclick="alert({$movie})">{$movie}</p>
<script>var movie = {$movie};</script>
renders as:
<p onclick="alert("Amarcord & 8 1\/2")">Amarcord & 8 1/2</p>
<script>var movie = “Amarcord & 8 1\/2";</script>
If you don't want to escape the output, e.g. if it is a pre-prepared HTML code, just prepend an exclamation mark before the expression:
{!$variable}
But wait! There is more to Latte than just escaping.
Latte is, of course, far more powerful. It's a full-featured and extensible templating engine. It provides a set of built-in macros and helpers and an easy way of adding your own macros and helpers.
Here goes an example of two macros, if
and foreach
, and two helpers, bytes
and date
. As you can see, macros contain PHP code and also are compiled into it. Helpers are used to format the output and can take arguments.
{if count($files) > 0}
<ul>
{foreach $files as $file}
<li>
{$file->filename} ({$file->site|bytes}), uploaded {$file->uploaded|date:'m/d/Y'}
</li>
{/foreach}
</ul>
{/if}
The code above might output something like this:
<ul>
<li>file1.jpg (2.35 kB), uploaded 04/03/2013</li>
<li>file2.pdf (12.47 MB), uploaded 04/01/2013</li>
</ul>
Macros also allow a different, attribute-like syntax with an n:
prefix. The example above could be rewritten like this:
<ul n:if="count($files) > 0">
<li n:foreach="$files as $file">
{$file->filename} ({$file->size|bytes}), uploaded {$file->uploaded|date:'m/d/Y'}
</li>
</ul>
You can find a list of all built-in macros and helpers in the documentation, as well as the information on how to write your own macros and helpers.
First, you need Nette framework. You can either require nette/nette
in version 2.0.x
using Composer, or download an archive from the official site. In the latter way, all you need from the archive is Nette-minified/nette.min.php
file, which is a minifed version of Nette framework.
(Note that this procedure may change in the future, as Latte is planned to be released as a stand-alone package.)
All you have to do then is to create a template file, encapsulate it with a FileTemplate
object, register Latte as a filter and register the predefined set of helpers:
$template = new Nette\Templating\FileTemplate('/path/to/template.latte');
$template->registerFilter(new Nette\Latte\Engine);
$template->registerHelperLoader('Nette\\Templating\\Helpers::loader');
Then you can simply pass variables to the template:
$template->foo = 'bar';
And finally render it:
$template->render();
You can take your templates one step further by enabling caching. If you provide the template with a cache storage (an object implementing Nette\Caching\IStorage
), it will compile into native PHP code that gets cached, so that the next time you render the template, it will be as fast as PHP itself. In development environment, the template automatically recompiles every time you change its source code.
In this example, the filesystem-based cache provided by Nette is used:
$tempDir = '/path/to/your/projects/temp/dir';
$template->setCacheStorage(new Nette\Caching\Storages\FileStorage($tempDir));
On UNIX-based systems, make sure that the user running your web server can write into the temp directory.
Nette also comes with a brilliant debugging tool, nicknamed Tracy. You can use it not only to find typos in your templates. It also catches all errors and uncaught exceptions and displays them in a fancy, structured way. In production environment, however, Tracy logs all errors instead, thus not disclosing your configuration, database passwords, etc.
You can enable it like this:
Nette\Diagnostics\Debugger::enable();
This is how you can write fast and secure templates in an easy and comfortable way. If you have any problems or questions regarding Nette or any of its parts, feel free to ask at the official forum.