Re: [SMARTY-DEV] [patch] add $smarty->escape_output feature

From: Date: Thu, 04 May 2006 22:59:20 +0000
Subject: Re: [SMARTY-DEV] [patch] add $smarty->escape_output feature
References: 1 2  Groups: php.smarty.dev 
Request: Send a blank email to php-smarty-dev+get-2860@lists.php.net to get a copy of this message
Monte Ohrt wrote:
Off the top of my head, you have to be careful to not escape the values when they are not direct output.
Agreed !
example: $smarty->assign('foo','<bar>'); {$foo} <-- variable output, so escape so it comes out &lt;bar&gt; {if $foo eq "<bar>"} <-- do not escape $foo here, it is in an IF condition This is a pathetic/extreme example.. If anyone even uses this kind of code with smarty they "should be taken out way before dawn and shot with a blunt bone arrow"
Whilst I understand the "extreme realms of possibility" are being considered, I do not consider it valid !!! automatically "escaping" output would be invaluable and imho as default would be very nice indeed. And whilst were on a subject ? Anyone written an output filter than converts <a href="{$SCRIPT_NAME}?foo=baa&hi=ho&this=that">A & M</a> to <a href="{$SCRIPT_NAME}?foo=baa&amp;hi=ho&amp;this=that">A & M</a> pete :-)
Andreas Korthaus wrote:
Hi! I've had a discussion with boots in the smarty forum about a new, optional(!) smarty feature for general output escaping, which should not break BC. The idea is to provide means for projects, which like to use something like a contract, which ensures, that every output from user-input in smarty template gets escaped if a special, new Smarty member variable ($smarty->escape_output) is set (the used escape-function is modifiable). Other template engines provide something like that (e.g. flexy, savant), in Smarty this is not possible today (forget about default_modifiers). You can find the discussion here: http://www.phpinsider.com/smarty-forum/viewtopic.php?t=7806 Attatched you can find a patch against CVS-HEAD, which implements the basic functionality. It's not ready yet, because I did not catch every point where input get's displayed without escaping. From what I understand the smarty code, I think I have catched everything beside some of the plugins. But I'm not sure here, so I'd be very happy if someone with better knowledge of the smarty compiler could check if it's OK. And I'd like to know what your general opinion about such a feature is. Best regards Andreas ------------------------------------------------------------------------ Index: libs/Smarty.class.php =================================================================== RCS file: /repository/smarty/libs/Smarty.class.php,v retrieving revision 1.524 diff -u -r1.524 Smarty.class.php --- libs/Smarty.class.php 18 Jan 2006 19:02:52 -0000 1.524 +++ libs/Smarty.class.php 3 May 2006 09:41:09 -0000 @@ -398,6 +398,29 @@
      */
     var $config_class          =   'Config_File';
+    /**
+     * This tells Smarty whether or not to auto-escape output (variables)
+     *
+     * Available values:
+     *    - null: no escaping (default)
+     *  - 'html': htmlspecialchars()
+     *  - 'htmlall': htmlentities()
+     *  - 'url': urlencode()
+     *
+     * @var null|string escape sequence name
+     */
+    var $escape_output = null;
+
+    /**
+     * This tells Smarty what character-set to use for output encoding
+     *
+     * The character set is passed to escaping-functions, if there is a
+     * parameter for that. Default is null.
+     *
+     * @var null|string character-set
+     */
+    var $output_charset = null;
+ /**#@+ * END Smarty Configuration Section * There should be no need to touch anything below this line. @@ -1481,6 +1504,8 @@
         $smarty_compiler->compile_id        = $this->_compile_id;
         $smarty_compiler->_config            = $this->_config;
         $smarty_compiler->request_use_auto_globals  = $this->request_use_auto_globals;
+        $smarty_compiler->escape_output     = $this->escape_output;
+        $smarty_compiler->output_encoding   = $this->output_encoding;
         if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) {
             $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path];
Index: libs/Smarty_Compiler.class.php =================================================================== RCS file: /repository/smarty/libs/Smarty_Compiler.class.php,v retrieving revision 1.379 diff -u -r1.379 Smarty_Compiler.class.php --- libs/Smarty_Compiler.class.php 22 Apr 2006 08:16:57 -0000 1.379 +++ libs/Smarty_Compiler.class.php 3 May 2006 09:45:09 -0000 @@ -435,15 +435,20 @@
                     ~xs', $template_tag, $match)) {
             $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__);
         }
-       +
         $tag_command = $match[1];
         $tag_modifier = isset($match[2]) ? $match[2] : null;
         $tag_args = isset($match[3]) ? $match[3] : null;
         if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) {
-            /* tag name is a variable or object */
+
+            /* tag name is a variable or object */
             $_return = $this->_parse_var_props($tag_command . $tag_modifier);
-            return "<?php echo $_return; " . $this->_additional_newline;
+
+            /* variable gets escaped, when $Smarty->escape_output is enabled */
+            $_return_escaped = $this->_escape_var($_return, $tag_modifier);
+
+            return "<?php echo $_return_escaped; " . $this->_additional_newline;
         }
         /* If the tag name is a registered object, we process it. */
@@ -2286,6 +2291,40 @@
                              E_USER_ERROR, __FILE__, __LINE__);
     }
+    /**
+     * add output-escaping around variable
+     * (called after modifiers)
+     *
+     * @param string $var_name
+     * @param string $modifier_string
+     */
+    function _escape_var($var_name, $modifier_string)
+    {
+      /* only escape if $Smarty->escape_output is set and "noescape" modifier is not used */
+        if (!is_null($this->escape_output) && !preg_match('~(^|\|)(no)?escape($|\|)~', $modifier_string)) {
+       +         if (is_null($this->output_charset)) {
+            $_charset = '';
+         }
+         else {
+            $_charset = ',' . $this->output_charset;
+         }
+            switch ($this->escape_output) {
+                case 'html':
+                    return "htmlspecialchars({$var_name}, ENT_QUOTES{$_charset});";
+                case 'htmlall':
+                    return "htmlentities({$var_name}, ENT_QUOTES{$_charset});";
+                case 'url':
+                    return "urlencode({$var_name});";
+                default:
+                   $this->_trigger_fatal_error("Smarty output escaping error: escapement type '$this->escape_output' is not implemented");
+           }
+        }
+        else {
+           return $var_name;
+        }
+    }
+ } /**


« previous php.smarty.dev (#2860) next »