SlideShare une entreprise Scribd logo
1  sur  45
Télécharger pour lire hors ligne
Twig
The flexible, fast, and secure
template language for PHP

Fabien Potencier
Fabien Potencier
•  Serial entrepreneur and developer by passion
•  Founder of Sensio
   –  Web Agency (France and USA)
   –  Since 1998
   –  70 people
   –  Open-Source Specialists
   –  Big corporate customers
   –  Consulting, training, development, web design, … and more

   –  Sponsor of a lot of Open-Source projects
      like symfony and Doctrine
Fabien Potencier
•  Creator and lead developer of symfony…
•  and creator and lead developer of some more:
   –  symfony components
   –  Swift Mailer : Powerful component based mailing library for PHP
   –  Twig : Fexible, fast, and secure template language for PHP
   –  Pirum : Simple PEAR Channel Server Manager
   –  Sismo : PHP continuous integration server
   –  Lime : Easy to use unit testing library for PHP
   –  Twitto : A web framework in a tweet
   –  Twittee : A Dependency Injection Container in a tweet
   –  Pimple : A small PHP 5.3 dependency injection container
Fabien Potencier

•  Read my technical blog: http://fabien.potencier.org/

•  Follow me on Twitter: @fabpot

•  Fork my code on Github: http://github.com/fabpot/
http://www.twig-project.org/
Twig history


I was looking for a good template engine

I don’t like to reinvent the wheel

I started to look around for existing ones
Twig history
But I found none that satisfied all my personal needs:
   –  Fast (templates should be compiled to PHP)
   –  Secure (flexible output escaping)
   –  Sandboxed (whitelist system)
   –  Not tied to only HTML templates (emails, …)
   –  Syntax similar to Django & Jinja (but flexible, nothing hardcoded)
   –  Embeddable
   –  “Modern” features (such as template inheritance)
   –  Easily extensible (should be able to override everything)
   –  Clean OO code (“real” lexer, parser, and compiler, DI)
Twig history
•  … except Twig, which was quite close and had a solid architecture

   –  written by Armin Ronacher (of Jinja fame – a python template engine)

•  … but

   –  not available as a standalone project (packaged with chypr, a blog platform)

   –  never really maintained

•  I stumbled upon it by chance
Twig history
•  I started hacking the code, found it immediately beautiful and flexible
•  I wrote an email to Armin
•  and I took over the maintenance of it
   –  I’m the lead developer since October 1st
   –  kept the source under a BSD license
   –  created a dedicated website, mailing-list, wrote some documentation… on
      October 7th
   –  announced Twig on my blog:
       •  http://fabien.potencier.org/article/34/templating-engines-in-php
       •  http://fabien.potencier.org/article/35/templating-engines-in-php-
          follow-up
Twig Installation
•  Download it
    –  http://github.com/fabpot/Twig/tarball/master
•  Use the Subversion repository
    –  http://svn.twig-project.org/trunk/
•  Get it on Github.com
    –  http://github.com/fabpot/twig
•  Install it via PEAR
    –  pear channel-discover pear.twig-project.org
    –  pear install twig/Twig-beta
How does Twig looks like?
Template side
                           comment
{# Twig template #}

{% for item in items %}           tag
  * {{ item.value }}          variable
{% endfor %}
                          filter
Hello {{ name|title }}

{{ items|join(', ') }}             filter with arguments
Template side
{{ item.value }}

Can be any of the following

$item['value']           mask the implementation
$item->value()
$item->getValue()
$item->value
PHP side
require_once '/path/to/Twig/Autoloader.php';
Twig_Autoloader::register();
                                      loader
$loader = new Twig_Loader_Filesystem(
     '/path/to/templates', '/path/to/cache');
$twig = new Twig_Environment($loader);
$twig->addExtension(new Twig_Extension_Escaper());
                                               extension
$template = $twig->loadTemplate('index.twig');
$params = array('name' => 'Fabien’);

$template->display($params);
Compiled template
class __TwigTemplate_5f8fa007771745904051c1db27ffc4e0 extends Twig_Template
{
  public function display(array $context)
  {                                                 compiled as a class
    // line 1
    echo "nnHello ";
                             debug information
        // line 3
        echo twig_escape_filter($this->getEnvironment(),
          (isset($context['name']) ? $context['name'] : null));
        echo "nn";

        // ...
    }
}
Template inheritance
{# Template #}
{% extends "layout.twig" %}        template extends another one
{% block title "Cool..." %}
                                          template override
{% block content %}
  Hello {{ name }}                          parent blocks
  {% parent %}
{% endblock %}          parent content
{# Layout #}
<html>
  <head>
    <title>{% block title '' %}</title>
  </head>
  <body>
    {% block content '' %}
  </body>                         define blocks with default values
</html>
Template inheritance
class __TwigTemplate_8a7c3cb36a4064e9c740c094a108a5a4 extends __TwigTemplate_c61404957758dfda283709e89376ab3e
{
  public function block_title($context)
  {
    // ...
  }

    public function block_content($context)
    {
      // ...
    }
}

class __TwigTemplate_c61404957758dfda283709e89376ab3e extends Twig_Template
{
  public function display(array $context)
  {
    echo "n <html>n     <head>n      <title>";
    $this->block_title($context);
    echo "</title>n    </head>n    <body>n      ";
    $this->block_content($context);
    echo "n    </body>n </html>";
  }

    public function block_title($context) {}

    public function block_content($context)    {}
}
Why Twig compiles templates to PHP classes?
•  Deep template inheritance becomes trivial to implement as PHP does all
   the job for us
•  Very fast in common cases
   –  For better reusability, small templates are created and included often (think
      partials in symfony)
{% for item in items %}
  * {% include "item_partial.twig" %}
{% endfor %}
   –  As each template is a stateless instance of a class,
      inclusion is just a method call away (no PHP include involved)
Macros
A macro is a reusable and configurable snippet of HTML
{# forms.twig #}
{% macro input(name, value, type, size) %}
  <input type="{{ type|default('text') }}"
    name="{{ name }}" value="{{ value|e }}"
    size="{{ size|default(20) }}" />
{% endmacro %}

{# In a template #}
{% import "forms.twig" as forms %}

{{ forms.input('username') }}
{{ forms.input('password', none, 'password') }}
Expressions
For display logic (not for business logic of course)

{% if 1 < foo < 4 and (not bar or foobar) %}
  {{ foo + 4 }}
{% endif %}
Extensibility
Extensibility
•  Everything in the core can be changed
   –  Uses dependency injection
   –  The syntax is not hardcoded
•  Built-in extension mechanism for day-to-day enhancements
   –  Adding tags
   –  Adding filters
   –  Adding node transformers
•  Extensions are used for the core features
Core extensions
•  Everything is an extension in the core

   –  Twig_Extension_Core: Provides the core features (tags and filters)


   –  Twig_Extension_Escaper: Adds automatic output-escaping and the possibility
      to escape/unescape blocks of code

   –  Twig_Extension_Sandbox: Adds a sandbox mode to the default Twig
      environment, making it safe to evaluate untrusted code
Registering an extension
•  The Core extension is automatically registered
•  Core and user extensions are managed in the same way

$twig = new Twig_Environment($loader);

$twig->addExtension(
   new Twig_Extension_Escaper()
);
Output Escaping
XSS protection
{# Manually #}
{{ post.author|escape }}               escape variable
{{ foo|escape('js') }}
                               escaping strategy
{# A whole block #}
{% autoescape on %}       escape all variables of the block
  {{ post.author }}
  {{ post.title|escape }}       won’t be double-escaped
  {{ post.html|safe }}
{% endautoescape %}     marked this as safe
{# Automatic #}
{{ post.author }}
{{ post.html|safe }}
XSS protection
•  Everything is done during compilation (see node transformers later on)

•  Nothing is decided on execution

•  No overhead between escaping by hand and auto-escaping
Sandbox
When do you need a sandbox?
•  When you need to evaluate non-trusted code; a user who can edit
   templates, typically a webmaster in a web backend
•  Security is managed by a policy instance
   (Twig_Sandbox_SecurityPolicy by default)
•  The code evaluated in a sandbox must respect the policy
•  The default policy works as follows
   –  Tags must be explicitly allowed
   –  Filters must be explicitly allowed
   –  Method calls must be explicitly allowed on a method basis
How to enable the sandbox mode?
$twig = new Twig_Environment($loader);

$tags = array('if');
$filters = array('upper');
$methods = array(
   'Article' => array('getTitle', 'getBody'),
);
$policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods);
$sandbox = new Twig_Extension_Sandbox($policy);

$twig->addExtension($sandbox);
Using the sandbox
Enable it globally

$sandbox = new Twig_Extension_Sandbox($policy, true);

Or on a template basis

{% include "user.twig" sandboxed %}
When to use Twig?
•  When users you don’t trust can edit some templates
    –  a webmaster can edit the look and feel of some templates
•  When you need to create a simple language for a domain specific problem
    –  Templates of a blog, or of an ecommerce software
•  Advantages of Twig in such cases
    –  You can use as little or as much features as you want
    –  Security
    –  Sandbox
    –  Possibility to create a DSL (a set of pre-defined tags,
       macros, and filters specific to the domain)
DSL
•  One of the goal of Twig is to provide the architecture that allows the
   developer to create its own language targeted at his specific domain
   –  Configure the syntax (delimiters)
   –  Override all built-in elements (tags, filters, …)
   –  Create your own tags, macros, and filters
•  All without having to write complex code
   –  The core classes (lexer, parser, and compiler) provides a simple API to let you do
      your job without understanding the nitty-gritty details of the internals
Under the hood
From a template to a PHP file
                                  Request
    Something decide which template to render (typically a controller)
                  if already compiled in cache (on the filesystem)
Twig_Loader

                               Template source (string)             happens once
Twig_Lexer                     Stream of tokens (Twig_Token)                 even faster
Twig_Parser                    Tree of nodes (Twig_Node)               if APC is enabled

Twig_Compiler
                               Compiled template (PHP class)

                                              HTML
The lexer
The lexer tokenizes the template source and returns a stream of tokens
$stream =
  $twig->tokenize('Hello {{ name|title }}');
echo $stream;

TEXT_TYPE(Hello )
VAR_START_TYPE()
NAME_TYPE(name)
VAR_END_TYPE()
EOF_TYPE()
The parser
The parser converts the stream of tokens into a tree of nodes
$nodes= $twig->parse($stream);
echo $nodes;

Twig_Node_Module(
  Twig_Node_Text(Hello )
  Twig_Node_Print(
    Twig_Node_Expression_Name(name)
  )
)
The parser
// with automatic output escaping
Twig_Node_Module(              added by manipulating
  Twig_Node_Text(Hello )              the AST
  Twig_Node_Print(
    Twig_Node_Expression_Filter(
      Twig_Node_Expression_Name(name)
      (escape())
    )
  )
)
Node transformer classes
•  Manipulate the AST (Abstract Syntax Tree), the tree of nodes, before
   compilation
•  Each transformer can visit the tree and do something with each node
   –  remove it
   –  visit its children
   –  change it by another node
   –  wrap it (with a filter for instance)
Node transformer classes
•  Used by the core extensions
   –  Escaper
       •  adds the escape filter to Twig_Node_Print nodes
       •  except when the node is already filtered with escape (to avoid double-escaping), or
          already filtered with safe (to avoid escaping safe HTML strings)
   –  Sandbox
       •  To collect calls to filters and tags in a template
   –  Filter blocks
       •  To apply a set of filters to a whole block
The compiler
    The compiler eventually converts the tree of nodes to PHP code
class __TwigTemplate_5f8fa007771745904051c1db27ffc4e0 extends Twig_Template
{
  public function display(array $context)
  {
    // line 1
    echo "Hello ";

        echo (isset($context['name']) ? $context['name'] : null);
    }
}
Integration
Integration with other frameworks
•  symfony
    –  sfTwigPlugin
•  Zend Framework
    –  http://svn.twig-project.org/branches/zend_adapter/

•  Yii
    –  http://www.yiiframework.com/extension/twig-view-renderer/

•  Kohana
    –  http://github.com/shadowhand/kohana-twig

•  … and more to come
Questions?
Sensio S.A.
    92-98, boulevard Victor Hugo
        92 115 Clichy Cedex
              FRANCE
       Tél. : +33 1 40 99 80 80

               Contact
           Fabien Potencier
    fabien.potencier at sensio.com




  http://www.sensiolabs.com/
http://www.symfony-project.org/
 http://fabien.potencier.org/

Contenu connexe

Tendances

Making Sense of Twig
Making Sense of TwigMaking Sense of Twig
Making Sense of TwigBrandon Kelly
 
PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021Ayesh Karunaratne
 
PHP Functions & Arrays
PHP Functions & ArraysPHP Functions & Arrays
PHP Functions & ArraysHenry Osborne
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?Nikita Popov
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)James Titcumb
 
Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?Nikita Popov
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Fabien Potencier
 
PHP 8.1 - What's new and changed
PHP 8.1 - What's new and changedPHP 8.1 - What's new and changed
PHP 8.1 - What's new and changedAyesh Karunaratne
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5 Wildan Maulana
 
Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Fwdays
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I thinkWim Godden
 
PHP Performance Trivia
PHP Performance TriviaPHP Performance Trivia
PHP Performance TriviaNikita Popov
 
Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsMark Baker
 
Class 2 - Introduction to PHP
Class 2 - Introduction to PHPClass 2 - Introduction to PHP
Class 2 - Introduction to PHPAhmed Swilam
 

Tendances (20)

Making Sense of Twig
Making Sense of TwigMaking Sense of Twig
Making Sense of Twig
 
PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021PHP Enums - PHPCon Japan 2021
PHP Enums - PHPCon Japan 2021
 
Design patterns in PHP
Design patterns in PHPDesign patterns in PHP
Design patterns in PHP
 
PHP Functions & Arrays
PHP Functions & ArraysPHP Functions & Arrays
PHP Functions & Arrays
 
What's new in PHP 8.0?
What's new in PHP 8.0?What's new in PHP 8.0?
What's new in PHP 8.0?
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
 
Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?
 
Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3Dependency Injection with PHP 5.3
Dependency Injection with PHP 5.3
 
PHP 8.1 - What's new and changed
PHP 8.1 - What's new and changedPHP 8.1 - What's new and changed
PHP 8.1 - What's new and changed
 
Design Patterns in PHP5
Design Patterns in PHP5 Design Patterns in PHP5
Design Patterns in PHP5
 
PHP 5.3 in practice
PHP 5.3 in practicePHP 5.3 in practice
PHP 5.3 in practice
 
Functions in PHP
Functions in PHPFunctions in PHP
Functions in PHP
 
Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"Nikita Popov "What’s new in PHP 8.0?"
Nikita Popov "What’s new in PHP 8.0?"
 
Sorting arrays in PHP
Sorting arrays in PHPSorting arrays in PHP
Sorting arrays in PHP
 
My app is secure... I think
My app is secure... I thinkMy app is secure... I think
My app is secure... I think
 
Php Tutorials for Beginners
Php Tutorials for BeginnersPhp Tutorials for Beginners
Php Tutorials for Beginners
 
PHP Performance Trivia
PHP Performance TriviaPHP Performance Trivia
PHP Performance Trivia
 
New in php 7
New in php 7New in php 7
New in php 7
 
Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL Iterators
 
Class 2 - Introduction to PHP
Class 2 - Introduction to PHPClass 2 - Introduction to PHP
Class 2 - Introduction to PHP
 

Similaire à The flexible, fast, and secure template language for PHP

Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress Maurizio Pelizzone
 
Twig for Drupal @ Frontendunited Amsterdam 2012
Twig for Drupal @ Frontendunited Amsterdam 2012Twig for Drupal @ Frontendunited Amsterdam 2012
Twig for Drupal @ Frontendunited Amsterdam 2012Rene Bakx
 
Php on the Web and Desktop
Php on the Web and DesktopPhp on the Web and Desktop
Php on the Web and DesktopElizabeth Smith
 
Thymeleaf and Spring Controllers.ppt
Thymeleaf and Spring Controllers.pptThymeleaf and Spring Controllers.ppt
Thymeleaf and Spring Controllers.pptPatiento Del Mar
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Hugo Hamon
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Ted Kulp
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2Hugo Hamon
 
The Way to Theme Enlightenment 2017
The Way to Theme Enlightenment 2017The Way to Theme Enlightenment 2017
The Way to Theme Enlightenment 2017Amanda Giles
 
Php on the desktop and php gtk2
Php on the desktop and php gtk2Php on the desktop and php gtk2
Php on the desktop and php gtk2Elizabeth Smith
 
TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkChristian Trabold
 
The Way to Theme Enlightenment
The Way to Theme EnlightenmentThe Way to Theme Enlightenment
The Way to Theme EnlightenmentAmanda Giles
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Michelangelo van Dam
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
Building Potent WordPress Websites
Building Potent WordPress WebsitesBuilding Potent WordPress Websites
Building Potent WordPress WebsitesKyle Cearley
 
WordPress Developers Israel Meetup #1
WordPress Developers Israel Meetup #1WordPress Developers Israel Meetup #1
WordPress Developers Israel Meetup #1Yoav Farhi
 
Writing and Publishing Puppet Modules
Writing and Publishing Puppet ModulesWriting and Publishing Puppet Modules
Writing and Publishing Puppet ModulesPuppet
 

Similaire à The flexible, fast, and secure template language for PHP (20)

Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress
 
Twig for Drupal @ Frontendunited Amsterdam 2012
Twig for Drupal @ Frontendunited Amsterdam 2012Twig for Drupal @ Frontendunited Amsterdam 2012
Twig for Drupal @ Frontendunited Amsterdam 2012
 
Extending Twig
Extending TwigExtending Twig
Extending Twig
 
Php on the Web and Desktop
Php on the Web and DesktopPhp on the Web and Desktop
Php on the Web and Desktop
 
Tornadoweb
TornadowebTornadoweb
Tornadoweb
 
Thymeleaf and Spring Controllers.ppt
Thymeleaf and Spring Controllers.pptThymeleaf and Spring Controllers.ppt
Thymeleaf and Spring Controllers.ppt
 
Twig
TwigTwig
Twig
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Seven deadly theming sins
Seven deadly theming sinsSeven deadly theming sins
Seven deadly theming sins
 
The Way to Theme Enlightenment 2017
The Way to Theme Enlightenment 2017The Way to Theme Enlightenment 2017
The Way to Theme Enlightenment 2017
 
Php on the desktop and php gtk2
Php on the desktop and php gtk2Php on the desktop and php gtk2
Php on the desktop and php gtk2
 
TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase framework
 
The Way to Theme Enlightenment
The Way to Theme EnlightenmentThe Way to Theme Enlightenment
The Way to Theme Enlightenment
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
Building Potent WordPress Websites
Building Potent WordPress WebsitesBuilding Potent WordPress Websites
Building Potent WordPress Websites
 
WordPress Developers Israel Meetup #1
WordPress Developers Israel Meetup #1WordPress Developers Israel Meetup #1
WordPress Developers Israel Meetup #1
 
Writing and Publishing Puppet Modules
Writing and Publishing Puppet ModulesWriting and Publishing Puppet Modules
Writing and Publishing Puppet Modules
 

Plus de Fabien Potencier

Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Fabien Potencier
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Fabien Potencier
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Fabien Potencier
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010Fabien Potencier
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010Fabien Potencier
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201Fabien Potencier
 
Caching on the Edge with Symfony2
Caching on the Edge with Symfony2Caching on the Edge with Symfony2
Caching on the Edge with Symfony2Fabien Potencier
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Fabien Potencier
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 WorldFabien Potencier
 
Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010Fabien Potencier
 

Plus de Fabien Potencier (20)

Varnish
VarnishVarnish
Varnish
 
Look beyond PHP
Look beyond PHPLook beyond PHP
Look beyond PHP
 
Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4Dependency injection in PHP 5.3/5.4
Dependency injection in PHP 5.3/5.4
 
Dependency injection-zendcon-2010
Dependency injection-zendcon-2010Dependency injection-zendcon-2010
Dependency injection-zendcon-2010
 
Caching on the Edge
Caching on the EdgeCaching on the Edge
Caching on the Edge
 
Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3Design patterns revisited with PHP 5.3
Design patterns revisited with PHP 5.3
 
The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
PhpBB meets Symfony2
PhpBB meets Symfony2PhpBB meets Symfony2
PhpBB meets Symfony2
 
Dependency injection - phpday 2010
Dependency injection - phpday 2010Dependency injection - phpday 2010
Dependency injection - phpday 2010
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010Symfony2 - OSIDays 2010
Symfony2 - OSIDays 2010
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
Caching on the Edge with Symfony2
Caching on the Edge with Symfony2Caching on the Edge with Symfony2
Caching on the Edge with Symfony2
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010Dependency Injection - ConFoo 2010
Dependency Injection - ConFoo 2010
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Symfony Components
Symfony ComponentsSymfony Components
Symfony Components
 
Symfony2 revealed
Symfony2 revealedSymfony2 revealed
Symfony2 revealed
 

Dernier

SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 

Dernier (20)

SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 

The flexible, fast, and secure template language for PHP

  • 1. Twig The flexible, fast, and secure template language for PHP Fabien Potencier
  • 2. Fabien Potencier •  Serial entrepreneur and developer by passion •  Founder of Sensio –  Web Agency (France and USA) –  Since 1998 –  70 people –  Open-Source Specialists –  Big corporate customers –  Consulting, training, development, web design, … and more –  Sponsor of a lot of Open-Source projects like symfony and Doctrine
  • 3. Fabien Potencier •  Creator and lead developer of symfony… •  and creator and lead developer of some more: –  symfony components –  Swift Mailer : Powerful component based mailing library for PHP –  Twig : Fexible, fast, and secure template language for PHP –  Pirum : Simple PEAR Channel Server Manager –  Sismo : PHP continuous integration server –  Lime : Easy to use unit testing library for PHP –  Twitto : A web framework in a tweet –  Twittee : A Dependency Injection Container in a tweet –  Pimple : A small PHP 5.3 dependency injection container
  • 4. Fabien Potencier •  Read my technical blog: http://fabien.potencier.org/ •  Follow me on Twitter: @fabpot •  Fork my code on Github: http://github.com/fabpot/
  • 6. Twig history I was looking for a good template engine I don’t like to reinvent the wheel I started to look around for existing ones
  • 7. Twig history But I found none that satisfied all my personal needs: –  Fast (templates should be compiled to PHP) –  Secure (flexible output escaping) –  Sandboxed (whitelist system) –  Not tied to only HTML templates (emails, …) –  Syntax similar to Django & Jinja (but flexible, nothing hardcoded) –  Embeddable –  “Modern” features (such as template inheritance) –  Easily extensible (should be able to override everything) –  Clean OO code (“real” lexer, parser, and compiler, DI)
  • 8. Twig history •  … except Twig, which was quite close and had a solid architecture –  written by Armin Ronacher (of Jinja fame – a python template engine) •  … but –  not available as a standalone project (packaged with chypr, a blog platform) –  never really maintained •  I stumbled upon it by chance
  • 9. Twig history •  I started hacking the code, found it immediately beautiful and flexible •  I wrote an email to Armin •  and I took over the maintenance of it –  I’m the lead developer since October 1st –  kept the source under a BSD license –  created a dedicated website, mailing-list, wrote some documentation… on October 7th –  announced Twig on my blog: •  http://fabien.potencier.org/article/34/templating-engines-in-php •  http://fabien.potencier.org/article/35/templating-engines-in-php- follow-up
  • 10. Twig Installation •  Download it –  http://github.com/fabpot/Twig/tarball/master •  Use the Subversion repository –  http://svn.twig-project.org/trunk/ •  Get it on Github.com –  http://github.com/fabpot/twig •  Install it via PEAR –  pear channel-discover pear.twig-project.org –  pear install twig/Twig-beta
  • 11. How does Twig looks like?
  • 12. Template side comment {# Twig template #} {% for item in items %} tag * {{ item.value }} variable {% endfor %} filter Hello {{ name|title }} {{ items|join(', ') }} filter with arguments
  • 13. Template side {{ item.value }} Can be any of the following $item['value'] mask the implementation $item->value() $item->getValue() $item->value
  • 14. PHP side require_once '/path/to/Twig/Autoloader.php'; Twig_Autoloader::register(); loader $loader = new Twig_Loader_Filesystem( '/path/to/templates', '/path/to/cache'); $twig = new Twig_Environment($loader); $twig->addExtension(new Twig_Extension_Escaper()); extension $template = $twig->loadTemplate('index.twig'); $params = array('name' => 'Fabien’); $template->display($params);
  • 15. Compiled template class __TwigTemplate_5f8fa007771745904051c1db27ffc4e0 extends Twig_Template { public function display(array $context) { compiled as a class // line 1 echo "nnHello "; debug information // line 3 echo twig_escape_filter($this->getEnvironment(), (isset($context['name']) ? $context['name'] : null)); echo "nn"; // ... } }
  • 16. Template inheritance {# Template #} {% extends "layout.twig" %} template extends another one {% block title "Cool..." %} template override {% block content %} Hello {{ name }} parent blocks {% parent %} {% endblock %} parent content {# Layout #} <html> <head> <title>{% block title '' %}</title> </head> <body> {% block content '' %} </body> define blocks with default values </html>
  • 17. Template inheritance class __TwigTemplate_8a7c3cb36a4064e9c740c094a108a5a4 extends __TwigTemplate_c61404957758dfda283709e89376ab3e { public function block_title($context) { // ... } public function block_content($context) { // ... } } class __TwigTemplate_c61404957758dfda283709e89376ab3e extends Twig_Template { public function display(array $context) { echo "n <html>n <head>n <title>"; $this->block_title($context); echo "</title>n </head>n <body>n "; $this->block_content($context); echo "n </body>n </html>"; } public function block_title($context) {} public function block_content($context) {} }
  • 18. Why Twig compiles templates to PHP classes? •  Deep template inheritance becomes trivial to implement as PHP does all the job for us •  Very fast in common cases –  For better reusability, small templates are created and included often (think partials in symfony) {% for item in items %} * {% include "item_partial.twig" %} {% endfor %} –  As each template is a stateless instance of a class, inclusion is just a method call away (no PHP include involved)
  • 19. Macros A macro is a reusable and configurable snippet of HTML {# forms.twig #} {% macro input(name, value, type, size) %} <input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" /> {% endmacro %} {# In a template #} {% import "forms.twig" as forms %} {{ forms.input('username') }} {{ forms.input('password', none, 'password') }}
  • 20. Expressions For display logic (not for business logic of course) {% if 1 < foo < 4 and (not bar or foobar) %} {{ foo + 4 }} {% endif %}
  • 22. Extensibility •  Everything in the core can be changed –  Uses dependency injection –  The syntax is not hardcoded •  Built-in extension mechanism for day-to-day enhancements –  Adding tags –  Adding filters –  Adding node transformers •  Extensions are used for the core features
  • 23. Core extensions •  Everything is an extension in the core –  Twig_Extension_Core: Provides the core features (tags and filters) –  Twig_Extension_Escaper: Adds automatic output-escaping and the possibility to escape/unescape blocks of code –  Twig_Extension_Sandbox: Adds a sandbox mode to the default Twig environment, making it safe to evaluate untrusted code
  • 24. Registering an extension •  The Core extension is automatically registered •  Core and user extensions are managed in the same way $twig = new Twig_Environment($loader); $twig->addExtension( new Twig_Extension_Escaper() );
  • 26. XSS protection {# Manually #} {{ post.author|escape }} escape variable {{ foo|escape('js') }} escaping strategy {# A whole block #} {% autoescape on %} escape all variables of the block {{ post.author }} {{ post.title|escape }} won’t be double-escaped {{ post.html|safe }} {% endautoescape %} marked this as safe {# Automatic #} {{ post.author }} {{ post.html|safe }}
  • 27. XSS protection •  Everything is done during compilation (see node transformers later on) •  Nothing is decided on execution •  No overhead between escaping by hand and auto-escaping
  • 29. When do you need a sandbox? •  When you need to evaluate non-trusted code; a user who can edit templates, typically a webmaster in a web backend •  Security is managed by a policy instance (Twig_Sandbox_SecurityPolicy by default) •  The code evaluated in a sandbox must respect the policy •  The default policy works as follows –  Tags must be explicitly allowed –  Filters must be explicitly allowed –  Method calls must be explicitly allowed on a method basis
  • 30. How to enable the sandbox mode? $twig = new Twig_Environment($loader); $tags = array('if'); $filters = array('upper'); $methods = array( 'Article' => array('getTitle', 'getBody'), ); $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods); $sandbox = new Twig_Extension_Sandbox($policy); $twig->addExtension($sandbox);
  • 31. Using the sandbox Enable it globally $sandbox = new Twig_Extension_Sandbox($policy, true); Or on a template basis {% include "user.twig" sandboxed %}
  • 32. When to use Twig? •  When users you don’t trust can edit some templates –  a webmaster can edit the look and feel of some templates •  When you need to create a simple language for a domain specific problem –  Templates of a blog, or of an ecommerce software •  Advantages of Twig in such cases –  You can use as little or as much features as you want –  Security –  Sandbox –  Possibility to create a DSL (a set of pre-defined tags, macros, and filters specific to the domain)
  • 33. DSL •  One of the goal of Twig is to provide the architecture that allows the developer to create its own language targeted at his specific domain –  Configure the syntax (delimiters) –  Override all built-in elements (tags, filters, …) –  Create your own tags, macros, and filters •  All without having to write complex code –  The core classes (lexer, parser, and compiler) provides a simple API to let you do your job without understanding the nitty-gritty details of the internals
  • 35. From a template to a PHP file Request Something decide which template to render (typically a controller) if already compiled in cache (on the filesystem) Twig_Loader Template source (string) happens once Twig_Lexer Stream of tokens (Twig_Token) even faster Twig_Parser Tree of nodes (Twig_Node) if APC is enabled Twig_Compiler Compiled template (PHP class) HTML
  • 36. The lexer The lexer tokenizes the template source and returns a stream of tokens $stream = $twig->tokenize('Hello {{ name|title }}'); echo $stream; TEXT_TYPE(Hello ) VAR_START_TYPE() NAME_TYPE(name) VAR_END_TYPE() EOF_TYPE()
  • 37. The parser The parser converts the stream of tokens into a tree of nodes $nodes= $twig->parse($stream); echo $nodes; Twig_Node_Module( Twig_Node_Text(Hello ) Twig_Node_Print( Twig_Node_Expression_Name(name) ) )
  • 38. The parser // with automatic output escaping Twig_Node_Module( added by manipulating Twig_Node_Text(Hello ) the AST Twig_Node_Print( Twig_Node_Expression_Filter( Twig_Node_Expression_Name(name) (escape()) ) ) )
  • 39. Node transformer classes •  Manipulate the AST (Abstract Syntax Tree), the tree of nodes, before compilation •  Each transformer can visit the tree and do something with each node –  remove it –  visit its children –  change it by another node –  wrap it (with a filter for instance)
  • 40. Node transformer classes •  Used by the core extensions –  Escaper •  adds the escape filter to Twig_Node_Print nodes •  except when the node is already filtered with escape (to avoid double-escaping), or already filtered with safe (to avoid escaping safe HTML strings) –  Sandbox •  To collect calls to filters and tags in a template –  Filter blocks •  To apply a set of filters to a whole block
  • 41. The compiler The compiler eventually converts the tree of nodes to PHP code class __TwigTemplate_5f8fa007771745904051c1db27ffc4e0 extends Twig_Template { public function display(array $context) { // line 1 echo "Hello "; echo (isset($context['name']) ? $context['name'] : null); } }
  • 43. Integration with other frameworks •  symfony –  sfTwigPlugin •  Zend Framework –  http://svn.twig-project.org/branches/zend_adapter/ •  Yii –  http://www.yiiframework.com/extension/twig-view-renderer/ •  Kohana –  http://github.com/shadowhand/kohana-twig •  … and more to come
  • 45. Sensio S.A. 92-98, boulevard Victor Hugo 92 115 Clichy Cedex FRANCE Tél. : +33 1 40 99 80 80 Contact Fabien Potencier fabien.potencier at sensio.com http://www.sensiolabs.com/ http://www.symfony-project.org/ http://fabien.potencier.org/