Skip to end of metadata
Go to start of metadata

<h1>Zend_View 2.0 Notes on development</h1>

<h2>Update to use PluginLoader</h2>

<p>Currently, Zend_View uses its own system for managing plugins. This leads to issues when branching Zend_View, as well as to inconsistencies with the rest of the framework. It needs to be adapted to use Zend_Loader_PluginLoader for better consistency, to adhere to the DRY principle, and to allow for custom Plugin Loading solutions for helpers and filters.</p>

<p><strong>Note:</strong> this is currently done in the incubator.</p>

<h2>Allow optional use of streams to emulate short_open_tags on systems where it is disabled</h2>

<p>Currently, there's some confusion regarding the use of short_open_tags with ZF.<br />
Our coding standards dictate using full <?php tags at all times, but our<br />
documentation utilizes short tags for view scripts.</p>

<p>The recommendation all along is that library code should utilize fully qualified<br />
tags, but that view scripts can and should use short tags for brevity and<br />
clarity.</p>

<p>Unfortunately, current versions of PHP only allow setting short_open_tags at PER_DIR or stricter levels – and the php.ini-recommended disables it entirely, which means it is often disabled on end user systems.</p>

<p>Fortunately, we can emulate short_open_tags using stream wrappers. Adding this capability to Zend_View – and the option to disable it – would offer a flexible solution in line with our examples and messaging.</p>

<p><strong>NOTE:</strong> this is currently done in the incubator.</p>

<h2>Automatic escaping of view variables</h2>

<p>One criticism of Zend_View is that it makes it difficult to escape variables, which does not encourage good security. One easy change would be to simply have all variables retrieved via __get() be escaped by default, and instead require developers to call a special method when they want the raw value.</p>

<p>This will not help in all situations – return values from view variable method calls or properties, or values from arrays would not be escaped in this fashion. An enhanced stream wrapper could solve this issue.</p>

<h2>Helper Interface and Abstract</h2>

<p>Currently, it's not entirely clear that you have to implement setView() in your helpers to have view awareness. Additionally, the naming conventions often get in the way, and don't follow best practices ala design patterns. The recommendation is to have a helper interface like this:</p>

<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
interface Zend_View_Helper_Interface
{
public function setView(Zend_View_Interface $view);
public function getView();
public function direct(); // method called when helper invoked
}
]]></ac:plain-text-body></ac:macro>

<p>Additionally, an abstract class implementing this would be created:</p>

<ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[
abstract class Zend_View_Helper_Abstract implements Zend_View_Helper_Interface
{
public $view;

public function setView(Zend_View_Interface $view)

Unknown macro: { $this->view = $view; return $this; }

public function getView()

Unknown macro: { return $this->view; }

}
]]></ac:plain-text-body></ac:macro>

<p>Helpers would then extend the abstract class and implement the direct() method as necessary.</p>

<h2>Revisit Zend_View_Interface</h2>

<p>Zend_View_Interface aims to make it simple to wrap alternate view implementations and retain compatibility with ZF components. However, there are some places where this falls apart: Zend_View helpers, for instance, are very useful and in some cases providing convenience features not found in other templating systems, but may not work with an alternate implementation. We should explore ways of making helpers work with such implementations.</p>

<h2>Examine the usage of Zend_Registry for view variables</h2>

<p>By using a registry for view variables, we would achieve a greater separation of concerns within Zend_View. Currently, much care needs to be taken when using Zend_View as a view "engine" and when it is being used as a view script "variable store". By using $<em>registry = new Zend_Registry() (in the standard, lazy-loaded, accessor driven way), we gain this separation of concerns. __get()/</em>_set() would need to proxy to this registry. This also would allow the ability to drop context of view script variables..</p>

<p>Matthew R. also talks about context in this bug:</p>

<p><a href="http://framework.zend.com/issues/browse/ZF-3166">http://framework.zend.com/issues/browse/ZF-3166</a></p>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Nov 11, 2009

    <p>How can not escaping stuff in Zend_View lead to safety failures? Usually one escapes data before going into the DB. Or maybe not, but the point basically is that Zend_View can impossibly know if its data has been escaped already.</p>

    <p>I'm not sure what the expected level of a general ZF developer is, but it seems the expectations are dropping and dropping. If developers want to show /path/../otherpath/view.phtml they should be allowed, without being overprotective and ask for some extra confirmation (ZF isn't being developed in Redmond right? <ac:emoticon ac:name="wink" /> ) by having to call a setLfi...() (whatever it was...).</p>

    <p>Imho ZF should definitely be expecting more from its users than some morons who're just starting with PHP, and think they use OOP when they put 2 functions in one class at random. It seems odd to me why a component should do everything for me...</p>

    <p>On a sidenote; will Zend_view in ZF 2.0 also implement the (imho) idiotic LFI protection?</p>

    1. Nov 11, 2009

      <p>Escaping for the database is very different than escaping for the view; they're orthogonal operations. Zend_Db actually <strong>does</strong> do automatic escaping for you already – insert() and update() operations use the adapter's native escaping operations on all passed data.</p>

      <p>The reason for auto-escaping is to provide a poka-yoke: do the right thing by default, and if you know what you're doing, allow retrieving the raw data to do as you will. This will benefit users in a variety of ways:</p>
      <ul>
      <li>security is now front and center</li>
      <li>elimination of most calls to escape() means less typing</li>
      <li>calling getRawValue($key) makes it explicit that you are using a raw value, and calls attention to the fact (it's easy to forget you're using a raw value otherwise)</li>
      </ul>

      <p>Should we be expecting more from users? Perhaps, perhaps not. Regardless, the design as proposed is one that a number of security consultants have recommended to us multiple times during ZF's lifecycle as a good defensive practice, and a good measure towards defense in depth.</p>

      1. Nov 11, 2009

        <blockquote><p>it's easy to forget you're using a raw value otherwise</p></blockquote>

        <p>I thought thinking about things like these is one aspect that makes the difference between a real programmer and wannabe scripters. But if that's the way to go, it's the way to go I guess.</p>

        <p>Does this also mean we'll keep the LFI 'protection'?</p>

        1. Nov 11, 2009

          <p><cite>I thought thinking about things like these is one aspect that makes the difference between a real programmer and wannabe scripters.</cite></p>

          <p>We have to consider all levels of developers. ZF is being used in shops that have everywhere from new to senior developers, and we need to provide tools that make creating secure applications as simple as possible. Yes, you, a seasoned developer, know to always call escape() in your views – but what about somebody with very little experience and just coming to ZF?</p>

          <p>As for the LFI protection, it may be a moot point once we do some refactoring of Zend_View; if it's still an issue, however, yes, the code will remain. Security should be the default condition, not the other way around.</p>

          1. Nov 12, 2009

            <p>What about making it configurable ?</p>

            <p>An option for Zend_View which influences the behaviour of $view->var;<br />
            by default escaping is turned on, if a developer thinks he doesn't like or want it,<br />
            he can set the option to false and $view->var returns an unmodified version of the variable.</p>

            <p>That probably would make both sides happy and everybody can choose how he wants to use the view.</p>

            1. Nov 12, 2009

              <p>I should have made this more clear: the plan is to continue to implement escape(), and also to make the behavior configurable. This last is key during migrations, particularly; without it, migrating view scripts will be quite difficult.</p>

      2. Nov 14, 2009

        <p>The problem with auto escaping is that there is a possibility of outputting content that has been escaped twice. Most of the stuff that gets outputted on my projects has already been escaped when entering into my system (yes I am talking mainly about HTML). </p>

        <p>Escaping for Db (for security reasons), and escaping HTML is not the same. When you try to escape HTML content which uses entities, like fore example "&" for an ampersand, you end up with "&amp;".</p>

        <p>But, if auto escaping feature gets implemented as a configuration option I guess that should make everybody happy.</p>

        1. Nov 20, 2009

          <p>Like Matthew said, ZF already does the right thing with using database driver's escaping functions.</p>

          <p>With regards to the view, I will definitely enjoy <strong>not having to type escape</strong> in every line that prints a variable. </p>

          1. Dec 07, 2009

            <p>I just want to add my support for auto-escaping all data sent to the view using __get() with the option to get the raw data if/when necessary. It's far too easy to miss places that should have $this->escape() and hard to find those places.</p>

  2. Nov 13, 2009

    <p>To Dolf - you do realise the change will mean far less typing. I don't know about wannabe scripters, but I'll enjoy not having to call escape every other line <ac:emoticon ac:name="wink" />.</p>

    <p>I would say the main concern that may arise is how performance is impacted. I haven't checked myself but Fabien seems really sure that automated escaping is a performance killer (at least in Symfony). I haven't found that myself using the simple wrapper I have here, so my comment is only to note that checking out whatever Symfony is doing might let us escape whatever problem they are having.</p>

  3. Dec 06, 2009

    <p>I think in the new version there should be support for a template language built-in. </p>

    <p>In my company we have non-programmers writing part of the views and the php default is more confusing, IMHO.</p>

    1. Dec 06, 2009

      <p>Imho we definitely should not. PHP itself is a templating language already, and adding an extra syntax, would only add extra abstraction that doesn't provide any benefit (except for being 'different'). This may be interesting to read: <a class="external-link" href="http://nosmarty.net/">http://nosmarty.net/</a> , though it's aimed at Smarty, you could replace the word 'Smarty' with 'templating engine'.</p>

      <p>Imho there's no difference between learning your non-programmers (since when do they touch code anyway?) the syntax of Smarty/other templating language or learning them the syntax of PHP itself (which by definition performs better).</p>

    2. Dec 07, 2009

      <p>One of the founding tenets of ZF from the beginning has been to leverage the language as much as possible – and this was one of the reasons PHP was chosen as the "templating language" used by Zend_View.</p>

      <p>Since prior to 1.0, we have supported custom templating engines by allowing developers to implement Zend_View_Interface to drop in their own engine – so if you want to use a different templating engine or one you've rolled yourself, you can do so.</p>

      <p>We will not officially support additional implementations, though we will accept them for the ZendX namespace (which is community supported only); we simply don't have the resources to support multiple implementations.</p>

  4. Dec 14, 2009

    <p>(This may be tied to the suggestion of using Zend_Registry for view variables.)</p>

    <p>It would be good to be able to create light-weight view objects for use by other classes. </p>

    <p>Lets say I have a Bug class, which just focuses on the features necessary for the domain model. I then introduce a BugFormatter to prepare bugs for display. This I pass a bug instance and the view, as it may need to perform escaping and such: </p>

    <p>//perhaps in my controller...<br />
    $bug = ... <br />
    $this->view->bug = new BugFormatter($bug, $this->view);</p>

    <p>This is all fine BUT either I pass in access to all assigned view variables (as in this example) or I end up having to clone the view object. (This way of looking at it inverts the usual helper/partial method of passing the object to the view but the problem is the same.)</p>

    <p>What would be good is if view object were cheap and we could use lots of them (as required) to build up the final <em>view</em>.</p>

    1. Sep 28, 2010

      <ac:macro ac:name="unmigrated-wiki-markup"><ac:plain-text-body><![CDATA[I use View Helpers already to more or less accomplish what you are talking about.
      class My\View\Helper\PrintBug extends Zend\View\Helper
      {
      public function printBug(Bug $bug)
      {
      // Do common formatting of bug (using partials, etc).
      }
      }
      Then in your controller: $this->view->bug = Bug::findBug();
      Then in your view: <?php echo $this->printBug($this->bug); ?>

      The printBug class would be available in ALL of your view scripts and would therefore print it consistently. Am I missing what you are saying?]]></ac:plain-text-body></ac:macro>

  5. Dec 14, 2009

    <p>One issue I am starting to run into is that for designers there isn't really an easy way to discover which variables and helpers are available to the current view script. Instead they have to go back to the Controller Action or via some plugin somewhere to discover which variables are available to them.</p>

    <p>Sure they can do a var_dump($this), but that usually runs outs of memory depending on what's been assigned... Plus for a designer the output is cryptic.</p>

    <p>I'm not sure if this is an issue being looked at for the 2.0 roadmap, or one that is already solved for 1.x by other means - if so, a link would be fantastic.</p>

    <p>I'm currently researching this area myself, and it looks like a custom implementation of a view helper to list assigned variables, and documentation to view helpers seems like the way to go - at least for my own use cases.</p>

    1. Dec 15, 2009

      <p>I use a View Helper here which is little more than a quick class using the Reflection API (only need an overview) and some neat list formatting. It's not pretty, but a designer can call it anywhere to get an idea of what the View contains for use. It doesn't solve every problem - View still will reference View Helpers which may conceal a lot of presentation logic, so it's important to use a sensible intuitive naming scheme and have at least some minimum of reference documentation (even a quick text file is okay) so designers have something to refer back to.</p>

  6. Dec 27, 2009

    <p>One problem which should be also solved is related to PartialLoop.</p>

    <p>As far as i checked some time ago (i hope things), at each item the partial file is loaded again... I think this may lead to weak performance for PartialLoop...</p>

    1. Dec 31, 2009

      <p>To accommodate such a change, we'd need to implement a templating engine.</p>

      <p>Since we are using PHP as our template language, we are using include() to both locate and evaluate the view script. This allows us to execute in the current variable scope, and relies on PHP to ensure the view script is valid, executable PHP. If we were to load into memory, we would need a template compiler and code for evaluating the view scripts – which means a complete template engine implementation.</p>

      <p>This is unlikely to happen for 2.0, if at all.</p>

      1. Jan 05, 2010

        <p>Is the performance actually bad? There is a presumption after all that users will employ an opcode cache as some minimum performance measure. While this can't cache opcode per se from the conditionally included file, does it not cache that file to memory (avoiding repetitive file reads) anyway at the very least?</p>

        1. Jan 05, 2010

          <p>Sorry i don't have some exact stats. My bad <ac:emoticon ac:name="sad" /></p>

          <p>For one project now 5 months i saw a slow performance with using partialLoops on one view. After switching that view using just for i noticed a great improvement of speed.</p>

          <p>As i said i don't have any specific stats right now, just pointed out the problem...</p>

        2. Jan 05, 2010

          <p>Didn't Matthew do some benchmarking a while back ... ? (I certainly remember him advising, on performance reasons I think, against using partials UNLESS you specifically needed the added ability to pass in model data.)</p>

          <p>In general, for me, partials seem a good way to go – but for the advice otherwise – as does (on a tangent) the ActionStack and the action() view helper. – It all goes towards the idea I was trying to get at previously of building a <strong>view</strong> from multiple components (each themselves to some extent reusable). – It would be good if for 2.0 these <strong>natural</strong> ways of doing it didn't need to be caveated with performance concerns...</p>

          <p>(On the Action Stack or action() view helper in particular, I've often seen the response to build a custom view helper and use that – but, especially with <strong>little actions</strong> responding to Ajaxy interactions, this often means repeating functionality that's already around in an action controller. I don't know... <ac:emoticon ac:name="smile" />)</p>

          1. Jan 05, 2010

            <p>Sorry Carlton, i don't hope so much on 2.0.</p>

            <p>I see the 1.x branch with too many opened bugs to hope 2.0 would be much better...</p>

            <p>Of course, i didn't do myself more than reporting bugs, sorry <ac:emoticon ac:name="sad" /> ... But anyway...</p>

            1. Jan 05, 2010

              <p>I'd reckon that's a bit too pessimistic Christian... I least I hope so... <ac:emoticon ac:name="smile" /></p>

  7. Mar 03, 2010

    <p>I wanted to add a use case regarding escaping data. </p>

    <p>When you have a search form, you need to spit back the query and preprocess and escape it in pretty much every imaginable way and probably some you never thought of. </p>

    <p>You have to deal potentially with smart quotes for queries pasted in the box. You have diacritic characters. You have suggested terms. You have pluses converted on the browser url bar...since it's a GET, sometimes people will type stuff in the URL bar and mess up the spaces and +'s and &20's. You need to properly capture + and - and phrases in quotes. They need to be spit back correctly for pagination. For suggested terms. In Meta keywords. Meta description. Title. The search input box....so when building this, I'd suggest considering a sample form I pastebin'ed here:
    <a class="external-link" href="http://pastebin.com/teJkBRGz">http://pastebin.com/teJkBRGz</a></p>

    <p>Personally, I wasn't a fan of $this->escape($var)...by default it's just a wrapper to htmlspecialchars, right? Saves 3 keys? What's the point? </p>

    <p>I'm also not a fan of automatically escaping them unless you do it the way facebook's XHP does, in a context sensitive manner: <a class="external-link" href="http://www.facebook.com/note.php?note_id=294003943919">http://www.facebook.com/note.php?note_id=294003943919</a>. In fact if there was some way to do something similar in Zend View, that might be cool...</p>

    <p>With $this->escape, the new ZF developer, who's unlikely to look up what escape does in the code, is just a step further away from understanding what's happening to his data. But automatically escaping vars is probably even worse, IMO. It's questionable if he's more secure, but he's certainly going to feel more secure and is less likely to learn how to escape properly in PHP...</p>

    <p>Just my 2 cents..</p>

    <p>Question. What's the syntax going to be for pulling the raw variable in the view and then urlencoding it? urlencode($this->getRawValue($q))?</p>

    1. Mar 03, 2010

      <p>Joe, you don't really raise a stance either way (for or against zend view escaping), however I'll join in and voice my opinion against it.</p>

      <p>Currently in my applications, escaping and sanitisation is all handled in the appropriate areas. Sanitisation is handled automatically via the Doctrine ORM providing I do pass the arguments over correctly to the DQL functions, and again for escaping/stripping I have made a doctrine listener such that anything I do work with is escaped/stripped appropriately. In the cases where I know the input hasn't been escaped appropriately already then I can fall back on the $this->escape (for such things as search queries).</p>

      <p>So that being said, sanitisation, escaping and encoding really feels as though it should be left up to the developer and the way he/she plan's to implement the system. The designer/implementor shouldn't have to worry about escaping (from my experience they don't anyway), it should be handled behind the scenes by the developer.</p>

      1. Mar 04, 2010

        <p>Benjamin, I guess I wasn't as clear as I thought. I'm against unless done contextually and therefore correctly...</p>

    2. Mar 04, 2010

      <p>Being honest, many developers don't know how to escape properly anyway. <ac:emoticon ac:name="wink" /> The escape() method always the advantage that it centralised the htmlspecialchars() parameters instead of needing to declare them everywhere. If you let developers set the encoding everywhere explicitly you're asking for problems.</p>

      <p>The main thing missing from the roadmap anyway is how escaping automatically will work - I haven't heard anything outside the suggestion of using streams to filter the templates and dynamically add the escape calls. The other alternative is implanting all variables into a proxy chain which automatically escapes all values being extracted which are strings (the rest are pushed into another link in the chain). This would allow for adding custom methods to the proxy class, e.g. getUrlencoded(), getRaw(), etc. and may allow for setting the context default escaper. Doesn't stop being sort of fugly - having everything encapsulated in proxy objects means the cost of escaping/proxying increases in line with the number of values being output.</p>

      <p>Streams would rely on single use regular expressions (probably faster) but make the template syntax take on magical properties, i.e. calling getRaw() on anything would be illegal syntax technically because we're relying on a stream to translate it to legal syntax on the fly. Also, would we be able to substitute stream classes, etc, to handle our context needs?</p>

      <p>Might as well flip coins until whoever is working on Zend_View 2.0 pushes out some more proposals.</p>

      1. Mar 04, 2010

        <p>The most obvious way to do it would be to use __get() to auto-escape.</p>

        <p>Thus <?php echo $this->var; ?> would automatically escape and <?php echo $this->getRaw('var'); ?> wouldn't.</p>

        1. Mar 04, 2010

          <p>Can't be chained if you meant via Zend_View. What is the variable is an object with methods? </p>

          <p>$this->object->getProp('someString')</p>

          <p>This is why it's either a stream (dynamically add the escape call) or a proxy chain (escape on string retrieval from the origin object).</p>

      2. Mar 04, 2010

        <p>>> If you let developers set the encoding everywhere explicitly you're asking for problems.<<</p>

        <p>True, but so far every solution sounds like a fugly problem too...</p>

        <p>>>Might as well flip coins until whoever is working on Zend_View 2.0 pushes out some more proposals.<<</p>

        <p>Paddy, if you were the one working on Zend_View, how would you propose handling automagically escaping vars?</p>

        1. Mar 04, 2010

          <p>Probably using a proxy system rather than streams. I like the concept of using streams to alter templates on the fly, but I'm wary of the magic syntax they would require - could get confusing explaining to everyone that templates are written in a pseudo PHP syntax where certain keywords get translated to valid syntax later. If we're going down that road, why not just use the template syntax and be done with it? At least the template tags can probably be extended very easily.</p>

          <p>I'd really like to see Ralph or Matthew dedicate a little time here.</p>

          <p>As for proxies, they carry the unusual cost of wrapping everything except printable scalars in a proxy object. This loses you some class identity (e.g. get_class()) but can transparently escape printable strings as they are extracted. Syntax remains valid common-use PHP. It also may (or should) let you add in context related methods or "escaper" classes even. It's the more object-oriented of the two options.</p>

          <p>The context question remains tricky though. We probably will not be able to depend on Facebook's strategy so either we use context methods, or allow its configuration beforehand when passing data into the view. It's almost a separate issue to generic escaping other than which path makes it easier to implement well. </p>

    3. Mar 04, 2010

      <p>Not sure why percent20's turned into & 20's above..either a typo or ironically escaping problems in this form...</p>

      <p>Hmm, ok let's try this:</p>

      <p>percent20: %20<br />
      ampersand20: &20</p>

  8. Jul 04, 2010

    <p>Hi. Not sure if it was discussed already, probably I missed it - sorry if so.</p>

    <p>Whether ZF has IoC DI container or not - either is fine for me, but there should be a way to inject dependencies in an application anyway. <br />
    Let's assume I don't want to use Zend_Registry.</p>

    <p>Now it's done for controllers + zend_application that have access to the container that holds the resources (or services), so at least I can get some resources I'm dependent to and utilize them in my controller.</p>

    <p>For view helpers currently there is just no way. I can neither access the container in a view helper nor add manually created helper to the view object.</p>

    <p>There is no way to easily extend zend_view_abstract because all those plugin members are private, so I have currently to create my own My_View implements Zend_View_Interface, copy everything from Zend_View and Zend_View_Abstract to just be able to pass the container to it and redeclare the way helpers are instantiated.</p>

    <p>There should be a built-in way to handle this, just like for the zend_application/controllers.</p>

  9. Apr 08, 2011

    <blockquote><p>The recommendation all along is that library code should utilize fully qualified tags, but that view scripts can and should use short tags for brevity and clarity.</p></blockquote>

    <p>I think you are wrong on this. Stream wrapper consume resources while php's short_open_tag directive are deprecated and disabled by default in recommended php.ini since ~5.2.x.</p>

  10. Jan 25, 2012

    <p>It would be really nice to add "linkTo" method to the Zend_View_Helper_Url.</p>

    <p>linkTo( string $caption, array $urlOptions = array, mixed $name = null, bool $reset = false, $encode = true ) : string</p>

    <p>should generate something like <a href="...">something</a>. You could have some additional options, like the Ruby on Rails link_to helper:
    <a class="external-link" href="http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to">http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to</a><br />
    (:confirm => 'Are you sure?' is really nice feature)</p>

    <p>It's really annoying and unclear to have:</p>
    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[<a href="<?= $this->url('default', array('controller' => 'album', 'action' => 'edit')) . '?id=' . $album->id ?>">Edit</a>]]></ac:plain-text-body></ac:macro>

    <p>all over the code. The query string should also be passed in some nicer manner (preferably in urlOptions array to be checked against the router).</p>