added trusted_dir functionality, cleaned up secure_dir logic

This commit is contained in:
mohrt
2001-12-03 20:29:51 +00:00
parent a93f90fbc9
commit 9847551176
5 changed files with 465 additions and 159 deletions

7
NEWS
View File

@@ -1,3 +1,10 @@
- added trusted_dir functionality (Monte)
- consolidated security tests to one function (Monte)
- prepend SMARTY_DIR to default directories in class constructor (Monte,
Ricard Pillosu)
- append _smarty_ to variable names in fetch() class function to avoid
namespace conflicts (Monte)
- fixed bug in _rm_auto with catendated null values (Monte, Thomas Pundt)
- introduced $compile_id class variable that can be used to set persistent - introduced $compile_id class variable that can be used to set persistent
compile identifier across multiple display calls. (Andrei) compile identifier across multiple display calls. (Andrei)
- fixed bug with concatenated null cache and compile identifiers. (Andrei) - fixed bug with concatenated null cache and compile identifiers. (Andrei)

View File

@@ -1,9 +1,9 @@
SMARTY QUICKSTART GUIDE SMARTY QUICKSTART GUIDE
----------------------- -----------------------
So you don't like reading documentation either? This guide is to help you Welcome to the Smarty QUICKSTART guide. This guide is to help you immediately
immediately get your feet wet in Smarty, get a feel for how it works and if it get your feet wet in Smarty, get a feel for how it works and if it will work
will work for you. for you.
We make a few assumptions here, such as you already have PHP installed on your We make a few assumptions here, such as you already have PHP installed on your
web server, you know the basics of unix file permissions, the basics of PHP and web server, you know the basics of unix file permissions, the basics of PHP and
@@ -15,9 +15,11 @@ INSTALLATION
Unpack the Smarty tarball. You will see four class files: Smarty.class.php, Unpack the Smarty tarball. You will see four class files: Smarty.class.php,
Smarty.addons.php, Smarty_Compiler.class.php and Config_File.class.php. You Smarty.addons.php, Smarty_Compiler.class.php and Config_File.class.php. You
will need to have all three of these files somewhere in your PHP include path, will need to have all four of these files somewhere in your PHP include path,
so when you call require("Smarty.class.php") from within your application, it so when you call require("Smarty.class.php") from within your application, it
can find the class. can find the class. Alternatively, you can set the SMARTY_DIR constant in your
application, and Smarty will use that directory as the path to the Smarty
class files. Be sure the path ends with a slash!
Smarty uses the PEAR libraries for some of its error handling routines. PEAR Smarty uses the PEAR libraries for some of its error handling routines. PEAR
libraries come with the distribution of PHP. Be sure that the path to these libraries come with the distribution of PHP. Be sure that the path to these
@@ -68,8 +70,8 @@ to PEAR.php (named like this in some distributions?)
Now we need to create two files, index.php and templates/index.tpl. index.php Now we need to create two files, index.php and templates/index.tpl. index.php
is the file that we will be calling from our web browser. index.tpl is the file is the file that we will be calling from our web browser. index.tpl is the file
that Smarty will use as its template file. (.tpl files are never called that Smarty will use as its template file. (Smarty template files are never
directly from the browser, only Smarty calls them.) accessed directly from the browser, only the Smarty class accesses them.)
--------- index.php -------- --------- index.php --------
@@ -96,7 +98,8 @@ http://your.host.com/Smarty/index.php
You should see "Hello, Ned!" in your browser. If not, retrace the steps above You should see "Hello, Ned!" in your browser. If not, retrace the steps above
and make sure you follow the instructions exactly as they say. Also check the and make sure you follow the instructions exactly as they say. Also check the
installation instructions in the documenation, and check your installation of installation instructions in the documenation, and check your installation of
PHP to be sure things are setup properly. PHP to be sure things are setup properly. If your still having problems, ask a
question on the mailing list, which you can find in the FAQ.
You see "Hello, Ned!" in your browser? Good! You see "Hello, Ned!" in your browser? Good!
@@ -108,16 +111,13 @@ templates_c directory. Out of sight, out of mind. You don't need to worry about
it, Smarty takes care of this technical stuff. Out of curiosity, you can see it, Smarty takes care of this technical stuff. Out of curiosity, you can see
how your templates look as compiled php scripts, but please don't edit them! how your templates look as compiled php scripts, but please don't edit them!
Now that we have Smarty functioning properly, let's get into the guts of Smarty Now that we have Smarty functioning properly, let's take a look at a few
and learn what thing is all about. I'll try to briefly show examples to cover features of the template language.
the most important features of Smarty.
ASSIGNING VARIABLES ASSIGNING VARIABLES
------------------- -------------------
Assigning variables to the template is very similar to the ways other template Assigning variables to the template is fairly straight forward. Example:
engines do it. Example:
--------- index.php -------- --------- index.php --------
@@ -195,10 +195,11 @@ $smarty->display("index.tpl");
Notice we are passing the variable "title" when we include the header.tpl file. Notice we are passing the variable "title" when we include the header.tpl file.
You can pass as many variables as you want. The included file inherits all the You can pass as many variables as you want. The included file inherits all the
current template vars, plus any that are passed to it. The passed variables are current template vars, plus any that are passed to it. The passed variables are
only available within the scope of the included file. Also notice the way the only available within the scope of the included file (and any files it may
$title variable is printed to the template. It uses a variable modifier called include.) Also notice the way the $title variable is printed to the template.
"default". Printing {$title|default:"no title"} means that if the value of It uses a variable modifier called "default". Printing {$title|default:"no
$title is empty, the text "no title" will be printed instead of nothing. title"} means that if the value of $title is empty, the text "no title" will be
printed instead of nothing.
IF/ELSEIF/ELSE IF/ELSEIF/ELSE
-------------- --------------
@@ -242,22 +243,23 @@ $smarty->display("index.tpl");
--------- templates/index.tpl -------- --------- templates/index.tpl --------
{include file="header.tpl" title="Home Page"} {include file="header.tpl" title="Home Page"}
{section name=people loop=$FirstName} {section name=people loop=$FirstName}
{%people.rownum%} {$FirstName[people]} {$LastName[people]}<br> {$smarty.section.people.rownum} {$FirstName[people]} {$LastName[people]}<br>
{sectionelse} {sectionelse}
There are no values to loop through. There are no values to loop through.
{/section} {/section}
<p> <p>
There were {%people.loop%} names in this list. There were {$smarty.section.people.loop} names in this list.
{include file="footer.tpl"} {include file="footer.tpl"}
Here we are introducing the {$smarty} variable, which is used to reference
Notice that when printing variables inside of the section, the section name must values internal to the template. Notice that when printing variables inside of
be referenced in the name of the variable being displayed. This lets Smarty the section, the section name must be referenced in the name of the variable
understand that you want to print the value in the array postion indexed by the being displayed. This lets Smarty understand that you want to print the value
current loop value. There are also internal template variables available within in the array postion indexed by the current loop value. There are also internal
the section that display the loop iteration and the total number of times the template variables available within the section that display the loop iteration
section is looped. Also note the {sectionelse}. This would have been displayed and the total number of times the section is looped. Also note the
had the loop array $FirstName been empty. {sectionelse}. This would have been displayed if looped array $FirstName was
empty.
You can access keys of arrays with this syntax: You can access keys of arrays with this syntax:
@@ -282,7 +284,7 @@ $smarty->display("index.tpl");
There are no values to loop through. There are no values to loop through.
{/section} {/section}
<p> <p>
There were {%people.loop%} names in this list. There were {$smarty.section.people.loop} names in this list.
{include file="footer.tpl"} {include file="footer.tpl"}
@@ -311,22 +313,67 @@ $smarty->display("index.tpl");
--------- templates/index.tpl -------- --------- templates/index.tpl --------
{include file="header.tpl" title="Home Page"} {include file="header.tpl" title="Home Page"}
{section name=people loop=$FirstName} {section name=people loop=$FirstName}
{%people.rownum%} {$FirstName[people]} {$LastName[people]}<br> {$smarty.section.people.rownum} {$FirstName[people]} {$LastName[people]}<br>
{section name=contacts loop=$ContactNames[people]} {section name=contacts loop=$ContactNames[people]}
{* for fun, lets bold every other row *} {* for fun, lets bold every other row *}
{if %contacts.rownum% is even}<b>{/if} {if $smarty.section.contacts.rownum is even}<b>{/if}
{$ContactNames[people][contacts]}: {$ContactVals[people][contacts]}<br> {$ContactNames[people][contacts]}: {$ContactVals[people][contacts]}<br>
{if %contacts.rownum% is even}</b>{/if} {if $smarty.section.contacts.rownum is even}</b>{/if}
{/section} {/section}
<br> <br>
{sectionelse} {sectionelse}
There are no values to loop through. There are no values to loop through.
{/section} {/section}
<p> <p>
There were {%people.loop%} names in this list. There were {$smarty.sectin.people.loop} names in this list.
{include file="footer.tpl"} {include file="footer.tpl"}
FOREACH
-------
There is also an alternative way to loop through associative arrays that may be
a bit easier for you, especially if you only need to loop over one variable.
Here's an example that works with the default index.php that comes with Smarty:
{foreach name=outer item=contact from=$contacts}
{foreach key=key item=item from=$contact}
{$smarty.foreach.outer.iteration}. contact {$key}: {$item}
{/foreach}
{foreachelse}
no contacts
{/foreach}
Possible attributes:
from: the array you are looping through
item: the name of the variable that is the current element
key: the name of the variable that is the current key (optional)
name: the name of the of foreach (optional)
The 'name' has to be used if you want to refer to any of the foreach
properties.
Properties (if 'name' is used):
name: the name of foreach
iteration: current iteration
total: total number of iterations
first: if it's first iteration
last: it it's last iteration
show: if foreach was shown at all
Here's another neat example, dumps all properties of foreach:
{foreach name=outer item=contact from=$contacts}
{foreach key=key item=item from=$smarty.foreach.outer}
{$key}: {$item}
{/foreach}
{/foreach}
This should be enough to get your feet wet. Also, check out config file This should be enough to get your feet wet. Also, check out config file
variables, built-in functions, custom functions, variable modifiers, all sorts variables, built-in functions, custom functions, variable modifiers, all sorts
of good stuff. Now go read the documentation, and Good Luck! of good stuff. Now go read the documentation, join the mailing list and have
fun!

View File

@@ -127,6 +127,9 @@ class Smarty
'PHP_TAGS' => false, 'PHP_TAGS' => false,
'MODIFIER_FUNCS' => array('count') 'MODIFIER_FUNCS' => array('count')
); );
var $trusted_dir = array(); // array of directories where trusted templates
// reside ($security is disabled during their
// execution.)
var $left_delimiter = '{'; // template tag delimiters. var $left_delimiter = '{'; // template tag delimiters.
var $right_delimiter = '}'; var $right_delimiter = '}';
@@ -212,6 +215,18 @@ class Smarty
\*======================================================================*/ \*======================================================================*/
function Smarty() function Smarty()
{ {
$this->template_dir = SMARTY_DIR.$this->template_dir;
$this->config_dir = SMARTY_DIR.$this->config_dir;
$this->compile_dir = SMARTY_DIR.$this->compile_dir;
$this->cache_dir = SMARTY_DIR.$this->cache_dir;
for($x=0; $x < count($this->secure_dir); $x++) {
$this->secure_dir[$x] = SMARTY_DIR.$this->secure_dir[$x];
}
for($x=0; $x < count($this->trusted_dir); $x++) {
$this->trusted_dir[$x] = SMARTY_DIR.$this->trusted_dir[$x];
}
foreach ($this->global_assign as $key => $var_name) { foreach ($this->global_assign as $key => $var_name) {
if (is_array($var_name)) { if (is_array($var_name)) {
foreach ($var_name as $var) { foreach ($var_name as $var) {
@@ -511,7 +526,7 @@ class Smarty
Function: fetch() Function: fetch()
Purpose: executes & returns or displays the template results Purpose: executes & returns or displays the template results
\*======================================================================*/ \*======================================================================*/
function fetch($smarty_tpl_file, $smarty_cache_id = null, $smarty_compile_id = null, $smarty_display = false) function fetch($_smarty_tpl_file, $_smarty_cache_id = null, $_smarty_compile_id = null, $_smarty_display = false)
{ {
global $HTTP_SERVER_VARS, $QUERY_STRING, $HTTP_COOKIE_VARS; global $HTTP_SERVER_VARS, $QUERY_STRING, $HTTP_COOKIE_VARS;
@@ -524,27 +539,24 @@ class Smarty
// capture time for debugging info // capture time for debugging info
$debug_start_time = $this->_get_microtime(); $debug_start_time = $this->_get_microtime();
$this->_smarty_debug_info[] = array('type' => 'template', $this->_smarty_debug_info[] = array('type' => 'template',
'filename' => $smarty_tpl_file, 'filename' => $_smarty_tpl_file,
'depth' => 0); 'depth' => 0);
$included_tpls_idx = count($this->_smarty_debug_info) - 1; $included_tpls_idx = count($this->_smarty_debug_info) - 1;
} }
$this->_compile_id = $_smarty_compile_id;
if (!isset($compile_id))
$compile_id = $this->compile_id;
$this->_inclusion_depth = 0; $this->_inclusion_depth = 0;
if ($this->caching) { if ($this->caching) {
$this->_cache_info[] = array('template', $smarty_tpl_file); $this->_cache_info[] = array('template', $_smarty_tpl_file);
if ($this->_read_cache_file($smarty_tpl_file, $smarty_cache_id, $smarty_compile_id, $smarty_results)) { if ($this->_read_cache_file($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $_smarty_results)) {
if ($this->insert_tag_check) { if ($this->insert_tag_check) {
$smarty_results = $this->_process_cached_inserts($smarty_results); $_smarty_results = $this->_process_cached_inserts($_smarty_results);
} }
if ($smarty_display) { if ($_smarty_display) {
echo $smarty_results; echo $_smarty_results;
if ($this->debugging) if ($this->debugging)
{ {
// capture time for debugging info // capture time for debugging info
@@ -554,7 +566,7 @@ class Smarty
} }
return; return;
} else { } else {
return $smarty_results; return $_smarty_results;
} }
} }
} }
@@ -577,51 +589,66 @@ class Smarty
'files' => array())); 'files' => array()));
if ($this->show_info_header) { if ($this->show_info_header) {
$info_header = '<!-- Smarty '.$this->_version.' '.strftime("%Y-%m-%d %H:%M:%S %Z").' -->'."\n\n"; $_smarty_info_header = '<!-- Smarty '.$this->_version.' '.strftime("%Y-%m-%d %H:%M:%S %Z").' -->'."\n\n";
} else { } else {
$info_header = ''; $_smarty_info_header = '';
} }
$compile_path = $this->_get_compile_path($smarty_tpl_file); $compile_path = $this->_get_compile_path($_smarty_tpl_file);
if($this->security && $this->_is_trusted($_smarty_tpl_file)) {
$_smarty_trusted = true;
$this->security = false;
} else {
$_smarty_trusted = false;
}
// if we just need to display the results, don't perform output // if we just need to display the results, don't perform output
// buffering - for speed // buffering - for speed
if ($smarty_display && !$this->caching) { if ($_smarty_display && !$this->caching) {
echo $info_header; echo $_smarty_info_header;
if ($this->_process_template($smarty_tpl_file, $compile_path)) if ($this->_process_template($_smarty_tpl_file, $compile_path))
{ {
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_BEGIN: ".$smarty_tpl_file." -->\n"; echo "\n<!-- SMARTY_BEGIN: ".$_smarty_tpl_file." -->\n";
} }
include($compile_path); if($this->security && $this->_is_trusted($_smarty_tpl_file)) {
$this->security = false;
include($compile_path);
$this->security = true;
} else {
include($compile_path);
}
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_END: ".$smarty_tpl_file." -->\n"; echo "\n<!-- SMARTY_END: ".$_smarty_tpl_file." -->\n";
} }
} }
} else { } else {
ob_start(); ob_start();
echo $info_header; echo $_smarty_info_header;
if ($this->_process_template($smarty_tpl_file, $compile_path)) if ($this->_process_template($_smarty_tpl_file, $compile_path))
{ {
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_BEGIN: ".$smarty_tpl_file." -->\n"; echo "\n<!-- SMARTY_BEGIN: ".$_smarty_tpl_file." -->\n";
} }
include($compile_path); include($compile_path);
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_END: ".$smarty_tpl_file." -->\n"; echo "\n<!-- SMARTY_END: ".$_smarty_tpl_file." -->\n";
} }
} }
$smarty_results = ob_get_contents(); $_smarty_results = ob_get_contents();
ob_end_clean(); ob_end_clean();
} }
if($_smarty_trusted) {
$this->security = true;
}
if ($this->caching) { if ($this->caching) {
$this->_write_cache_file($smarty_tpl_file, $smarty_cache_id, $smarty_compile_id, $smarty_results); $this->_write_cache_file($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $_smarty_results);
$smarty_results = $this->_process_cached_inserts($smarty_results); $_smarty_results = $this->_process_cached_inserts($_smarty_results);
} }
if ($smarty_display) { if ($_smarty_display) {
if (isset($smarty_results)) { echo $smarty_results; } if (isset($_smarty_results)) { echo $_smarty_results; }
if ($this->debugging) if ($this->debugging)
{ {
// capture time for debugging info // capture time for debugging info
@@ -631,7 +658,7 @@ class Smarty
} }
return; return;
} else { } else {
if (isset($smarty_results)) { return $smarty_results; } if (isset($_smarty_results)) { return $_smarty_results; }
} }
} }
@@ -699,13 +726,108 @@ function _generate_debug_output() {
return $results; return $results;
} }
/*======================================================================*\
Function: _is_trusted()
Purpose: determins if a template is trusted or not. If trusted,
$security is disabled during its execution.
\*======================================================================*/
function _is_trusted($tpl_file) {
static $_trusted_tpls = array();
if(in_array($tpl_file,$_trusted_tpls)) {
return true;
}
$_smarty_trusted = false;
if($this->security && !empty($this->trusted_dir)) {
// see if template file is within a trusted directory. If so,
// disable security during the execution of the template.
// if template is on local file system, check if trusted
$tpl_path_parts = explode(':', $tpl_file, 2);
if (count($tpl_path_parts) == 1) {
// no resource type, treat as type "file"
$resource_type = 'file';
$resource_name = $tpl_path_parts[0];
} else {
$resource_type = $tpl_path_parts[0];
$resource_name = $tpl_path_parts[1];
}
if ($resource_type == 'file') {
if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/",$resource_name)) {
// relative pathname to $template_dir
$resource_name = $this->template_dir.'/'.$resource_name;
}
foreach ($this->trusted_dir as $curr_dir) {
if (substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) {
$_smarty_trusted = true;
$_trusted_tpls[] = $tpl_file;
break;
}
}
} else {
// resource is not on local file system
$_smarty_trusted = false;
}
}
return $_smarty_trusted;
}
/*======================================================================*\
Function: _is_secure()
Purpose: determins if a template is secure or not.
\*======================================================================*/
function _is_secure($tpl_file) {
static $_secure_tpls = array();
if(!$this->security || $this->security_settings['INCLUDE_ANY'] || in_array($tpl_file,$_secure_tpls)) {
return true;
}
$_smarty_secure = false;
// if template is on local file system, check if secure
$tpl_path_parts = explode(':', $tpl_file, 2);
if (count($tpl_path_parts) == 1) {
// no resource type, treat as type "file"
$resource_type = 'file';
$resource_name = $tpl_path_parts[0];
} else {
$resource_type = $tpl_path_parts[0];
$resource_name = $tpl_path_parts[1];
}
if ($resource_type == 'file') {
if(!empty($this->secure_dir)) {
if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/",$resource_name)) {
// relative pathname to $template_dir
$resource_name = $this->template_dir.'/'.$resource_name;
}
foreach ($this->secure_dir as $curr_dir) {
if (substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) {
$_smarty_secure = true;
$_secure_tpls[] = $tpl_file;
break;
}
}
}
} else {
// resource is not on local file system
$_smarty_secure = true;
}
return $_smarty_secure;
}
/*======================================================================*\ /*======================================================================*\
Function: _process_template() Function: _process_template()
Purpose: Purpose:
\*======================================================================*/ \*======================================================================*/
function _process_template($tpl_file, $compile_path) function _process_template($tpl_file, $compile_path)
{ {
// test if template needs to be compiled // test if template needs to be compiled
if (!$this->force_compile && $this->_compiled_template_exists($compile_path)) { if (!$this->force_compile && $this->_compiled_template_exists($compile_path)) {
if (!$this->compile_check) { if (!$this->compile_check) {
// no need to check if the template needs recompiled // no need to check if the template needs recompiled
@@ -787,6 +909,11 @@ function _generate_debug_output() {
\*======================================================================*/ \*======================================================================*/
function _fetch_template_info($tpl_path, &$template_source, &$template_timestamp, $get_source=true) function _fetch_template_info($tpl_path, &$template_source, &$template_timestamp, $get_source=true)
{ {
if ($this->security && !$this->_is_secure($tpl_path) && !$this->_is_trusted($tpl_path)) {
$this->_trigger_error_msg("(secure mode) accessing \"$tpl_path\" is not allowed");
return false;
}
// split tpl_path by the first colon // split tpl_path by the first colon
$tpl_path_parts = explode(':', $tpl_path, 2); $tpl_path_parts = explode(':', $tpl_path, 2);
@@ -814,20 +941,6 @@ function _generate_debug_output() {
$this->_trigger_error_msg("unable to read template resource: \"$tpl_path\""); $this->_trigger_error_msg("unable to read template resource: \"$tpl_path\"");
return false; return false;
} }
// if security is on, make sure template comes from a $secure_dir
if ($this->security && !$this->security_settings['INCLUDE_ANY']) {
$resource_is_secure = false;
foreach ($this->secure_dir as $curr_dir) {
if (substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) {
$resource_is_secure = true;
break;
}
}
if (!$resource_is_secure) {
$this->_trigger_error_msg("(secure mode) including \"$resource_name\" is not allowed");
return false;
}
}
break; break;
default: default:
if (isset($this->resource_funcs[$resource_type])) { if (isset($this->resource_funcs[$resource_type])) {
@@ -905,17 +1018,27 @@ function _generate_debug_output() {
array_unshift($this->_config, $this->_config[0]); array_unshift($this->_config, $this->_config[0]);
$compile_path = $this->_get_compile_path($_smarty_include_tpl_file); $compile_path = $this->_get_compile_path($_smarty_include_tpl_file);
if($this->security && $this->_is_trusted($_smarty_include_tpl_file)) {
$_smarty_trusted = true;
$this->security = false;
} else {
$_smarty_trusted = false;
}
if ($this->_process_template($_smarty_include_tpl_file, $compile_path)) { if ($this->_process_template($_smarty_include_tpl_file, $compile_path)) {
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_BEGIN: ".$_smarty_include_tpl_file." -->\n"; echo "\n<!-- SMARTY_BEGIN: ".$_smarty_include_tpl_file." -->\n";
} }
include($compile_path); include($compile_path);
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_END: ".$_smarty_include_tpl_file." -->\n"; echo "\n<!-- SMARTY_END: ".$_smarty_include_tpl_file." -->\n";
} }
} }
if ($_smarty_trusted) {
$this->security = true;
}
array_shift($this->_config); array_shift($this->_config);
$this->_inclusion_depth--; $this->_inclusion_depth--;

View File

@@ -1697,11 +1697,11 @@ email: zaphod@slartibartfast.com&lt;br&gt;
<sect2> <sect2>
<title>Variables internal to template</title> <title>Variables internal to template</title>
<para> <para>
Variables that are internal to the templates are displayed by enclosing Variables that are internal to the templates are displayed by using
them with percent signs (%) and enclosing the variable in delimiters the special variable {$smarty}. For instance, you can reference the
like so: {%varname%} So far, section properties are the only internal current date/time with {$smarty.now}, or <link
variables used in Smarty, which can be found later in this document under linkend="builtin.functions.section">section loops</link> have
<link linkend="builtin.functions.section">section</link>. properties that are internal variables.
</para> </para>
</sect2> </sect2>
<sect2> <sect2>
@@ -2688,8 +2688,14 @@ e-mail: jane@mydomain.com&lt;p&gt;
</example> </example>
<para> <para>
Sections also have their own variables that handle section properties. Sections also have their own variables that handle section properties.
These are indicated by percent signs around the variable name, like so: These are indicated like so: {$smarty.section.sectionname.varname}
%sectionname.varname% </para>
<para>
NOTE: As of Smarty 1.5.0, the syntax for section property variables has
been changed from {%sectionname.varname%} to
{$smarty.section.sectionname.varname}. The old syntax is still
supported, but you will only see reference to the new syntax in the
manual examples.
</para> </para>
<sect3> <sect3>
<title>index</title> <title>index</title>
@@ -2707,7 +2713,7 @@ e-mail: jane@mydomain.com&lt;p&gt;
<title>section property index</title> <title>section property index</title>
<programlisting> <programlisting>
{section name=customer loop=$custid} {section name=customer loop=$custid}
{%customer.index%} id: {$custid[customer]}&lt;br&gt; {$smarty.section.customer.index} id: {$custid[customer]}&lt;br&gt;
{/section} {/section}
@@ -2730,7 +2736,7 @@ e-mail: jane@mydomain.com&lt;p&gt;
<title>section property index_prev</title> <title>section property index_prev</title>
<programlisting> <programlisting>
{section name=customer loop=$custid} {section name=customer loop=$custid}
{%customer.index%} id: {$custid[customer]}&lt;br&gt; {$smarty.section.customer.index} id: {$custid[customer]}&lt;br&gt;
{* FYI, $custid[customer.index] and $custid[customer] are identical in meaning *} {* FYI, $custid[customer.index] and $custid[customer] are identical in meaning *}
{if $custid[customer.index_prev] ne $custid[customer.index]} {if $custid[customer.index_prev] ne $custid[customer.index]}
The customer id changed&lt;br&gt; The customer id changed&lt;br&gt;
@@ -2761,7 +2767,7 @@ e-mail: jane@mydomain.com&lt;p&gt;
<title>section property index_next</title> <title>section property index_next</title>
<programlisting> <programlisting>
{section name=customer loop=$custid} {section name=customer loop=$custid}
{%customer.index%} id: {$custid[customer]}&lt;br&gt; {$smarty.section.customer.index} id: {$custid[customer]}&lt;br&gt;
{* FYI, $custid[customer.index] and $custid[customer] are identical in meaning *} {* FYI, $custid[customer.index] and $custid[customer] are identical in meaning *}
{if $custid[customer.index_next] ne $custid[customer.index]} {if $custid[customer.index_next] ne $custid[customer.index]}
The customer id will change&lt;br&gt; The customer id will change&lt;br&gt;
@@ -2797,8 +2803,8 @@ e-mail: jane@mydomain.com&lt;p&gt;
<title>section property iteration</title> <title>section property iteration</title>
<programlisting> <programlisting>
{section name=customer loop=$custid start=5 step=2} {section name=customer loop=$custid start=5 step=2}
current loop iteration: {%customer.iteration%}&lt;br&gt; current loop iteration: {$smarty.section.customer.iteration}&lt;br&gt;
{%customer.index%} id: {$custid[customer]}&lt;br&gt; {$smarty.section.customer.index} id: {$custid[customer]}&lt;br&gt;
{* FYI, $custid[customer.index] and $custid[customer] are identical in meaning *} {* FYI, $custid[customer.index] and $custid[customer] are identical in meaning *}
{if $custid[customer.index_next] ne $custid[customer.index]} {if $custid[customer.index_next] ne $custid[customer.index]}
The customer id will change&lt;br&gt; The customer id will change&lt;br&gt;
@@ -2831,14 +2837,14 @@ e-mail: jane@mydomain.com&lt;p&gt;
<title>section property first</title> <title>section property first</title>
<programlisting> <programlisting>
{section name=customer loop=$custid} {section name=customer loop=$custid}
{if %customer.first%} {if $smarty.section.customer.first}
&lt;table&gt; &lt;table&gt;
{/if} {/if}
&lt;tr&gt;&lt;td&gt;{%customer.index%} id: &lt;tr&gt;&lt;td&gt;{$smarty.section.customer.index} id:
{$custid[customer]}&lt;/td&gt;&lt;/tr&gt; {$custid[customer]}&lt;/td&gt;&lt;/tr&gt;
{if %customer.last%} {if $smarty.section.customer.last}
&lt;/table&gt; &lt;/table&gt;
{/if} {/if}
{/section} {/section}
@@ -2865,14 +2871,14 @@ e-mail: jane@mydomain.com&lt;p&gt;
<title>section property last</title> <title>section property last</title>
<programlisting> <programlisting>
{section name=customer loop=$custid} {section name=customer loop=$custid}
{if %customer.first%} {if $smarty.section.customer.first}
&lt;table&gt; &lt;table&gt;
{/if} {/if}
&lt;tr&gt;&lt;td&gt;{%customer.index%} id: &lt;tr&gt;&lt;td&gt;{$smarty.section.customer.index} id:
{$custid[customer]}&lt;/td&gt;&lt;/tr&gt; {$custid[customer]}&lt;/td&gt;&lt;/tr&gt;
{if %customer.last%} {if $smarty.section.customer.last}
&lt;/table&gt; &lt;/table&gt;
{/if} {/if}
{/section} {/section}
@@ -2899,7 +2905,7 @@ e-mail: jane@mydomain.com&lt;p&gt;
<title>section property rownum</title> <title>section property rownum</title>
<programlisting> <programlisting>
{section name=customer loop=$custid} {section name=customer loop=$custid}
{%customer.rownum%} id: {$custid[customer]}&lt;br&gt; {$smarty.section.customer.rownum} id: {$custid[customer]}&lt;br&gt;
{/section} {/section}
@@ -2922,10 +2928,10 @@ e-mail: jane@mydomain.com&lt;p&gt;
<title>section property index</title> <title>section property index</title>
<programlisting> <programlisting>
{section name=customer loop=$custid} {section name=customer loop=$custid}
{%customer.index%} id: {$custid[customer]}&lt;br&gt; {$smarty.section.customer.index} id: {$custid[customer]}&lt;br&gt;
{/section} {/section}
There were {%customer.loop%} customers shown above. There were {$smarty.section.customer.loop} customers shown above.
OUTPUT: OUTPUT:
@@ -2952,10 +2958,10 @@ e-mail: jane@mydomain.com&lt;p&gt;
{* $show_customer_info may have been passed from the PHP {* $show_customer_info may have been passed from the PHP
application, to regulate whether or not this section shows *} application, to regulate whether or not this section shows *}
{section name=customer loop=$custid show=$show_customer_info} {section name=customer loop=$custid show=$show_customer_info}
{%customer.rownum%} id: {$custid[customer]}&lt;br&gt; {$smarty.section.customer.rownum} id: {$custid[customer]}&lt;br&gt;
{/section} {/section}
{if %customer.show%} {if $smarty.section.customer.show}
the section was shown. the section was shown.
{else} {else}
the section was not shown. the section was not shown.
@@ -2986,10 +2992,10 @@ e-mail: jane@mydomain.com&lt;p&gt;
<title>section property total</title> <title>section property total</title>
<programlisting> <programlisting>
{section name=customer loop=$custid step=2} {section name=customer loop=$custid step=2}
{%customer.index%} id: {$custid[customer]}&lt;br&gt; {$smarty.section.customer.index} id: {$custid[customer]}&lt;br&gt;
{/section} {/section}
There were {%customer.total%} customers shown above. There were {$smarty.section.customer.total} customers shown above.
OUTPUT: OUTPUT:

View File

@@ -127,6 +127,9 @@ class Smarty
'PHP_TAGS' => false, 'PHP_TAGS' => false,
'MODIFIER_FUNCS' => array('count') 'MODIFIER_FUNCS' => array('count')
); );
var $trusted_dir = array(); // array of directories where trusted templates
// reside ($security is disabled during their
// execution.)
var $left_delimiter = '{'; // template tag delimiters. var $left_delimiter = '{'; // template tag delimiters.
var $right_delimiter = '}'; var $right_delimiter = '}';
@@ -212,6 +215,18 @@ class Smarty
\*======================================================================*/ \*======================================================================*/
function Smarty() function Smarty()
{ {
$this->template_dir = SMARTY_DIR.$this->template_dir;
$this->config_dir = SMARTY_DIR.$this->config_dir;
$this->compile_dir = SMARTY_DIR.$this->compile_dir;
$this->cache_dir = SMARTY_DIR.$this->cache_dir;
for($x=0; $x < count($this->secure_dir); $x++) {
$this->secure_dir[$x] = SMARTY_DIR.$this->secure_dir[$x];
}
for($x=0; $x < count($this->trusted_dir); $x++) {
$this->trusted_dir[$x] = SMARTY_DIR.$this->trusted_dir[$x];
}
foreach ($this->global_assign as $key => $var_name) { foreach ($this->global_assign as $key => $var_name) {
if (is_array($var_name)) { if (is_array($var_name)) {
foreach ($var_name as $var) { foreach ($var_name as $var) {
@@ -511,7 +526,7 @@ class Smarty
Function: fetch() Function: fetch()
Purpose: executes & returns or displays the template results Purpose: executes & returns or displays the template results
\*======================================================================*/ \*======================================================================*/
function fetch($smarty_tpl_file, $smarty_cache_id = null, $smarty_compile_id = null, $smarty_display = false) function fetch($_smarty_tpl_file, $_smarty_cache_id = null, $_smarty_compile_id = null, $_smarty_display = false)
{ {
global $HTTP_SERVER_VARS, $QUERY_STRING, $HTTP_COOKIE_VARS; global $HTTP_SERVER_VARS, $QUERY_STRING, $HTTP_COOKIE_VARS;
@@ -524,27 +539,24 @@ class Smarty
// capture time for debugging info // capture time for debugging info
$debug_start_time = $this->_get_microtime(); $debug_start_time = $this->_get_microtime();
$this->_smarty_debug_info[] = array('type' => 'template', $this->_smarty_debug_info[] = array('type' => 'template',
'filename' => $smarty_tpl_file, 'filename' => $_smarty_tpl_file,
'depth' => 0); 'depth' => 0);
$included_tpls_idx = count($this->_smarty_debug_info) - 1; $included_tpls_idx = count($this->_smarty_debug_info) - 1;
} }
$this->_compile_id = $_smarty_compile_id;
if (!isset($compile_id))
$compile_id = $this->compile_id;
$this->_inclusion_depth = 0; $this->_inclusion_depth = 0;
if ($this->caching) { if ($this->caching) {
$this->_cache_info[] = array('template', $smarty_tpl_file); $this->_cache_info[] = array('template', $_smarty_tpl_file);
if ($this->_read_cache_file($smarty_tpl_file, $smarty_cache_id, $smarty_compile_id, $smarty_results)) { if ($this->_read_cache_file($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $_smarty_results)) {
if ($this->insert_tag_check) { if ($this->insert_tag_check) {
$smarty_results = $this->_process_cached_inserts($smarty_results); $_smarty_results = $this->_process_cached_inserts($_smarty_results);
} }
if ($smarty_display) { if ($_smarty_display) {
echo $smarty_results; echo $_smarty_results;
if ($this->debugging) if ($this->debugging)
{ {
// capture time for debugging info // capture time for debugging info
@@ -554,7 +566,7 @@ class Smarty
} }
return; return;
} else { } else {
return $smarty_results; return $_smarty_results;
} }
} }
} }
@@ -577,51 +589,66 @@ class Smarty
'files' => array())); 'files' => array()));
if ($this->show_info_header) { if ($this->show_info_header) {
$info_header = '<!-- Smarty '.$this->_version.' '.strftime("%Y-%m-%d %H:%M:%S %Z").' -->'."\n\n"; $_smarty_info_header = '<!-- Smarty '.$this->_version.' '.strftime("%Y-%m-%d %H:%M:%S %Z").' -->'."\n\n";
} else { } else {
$info_header = ''; $_smarty_info_header = '';
} }
$compile_path = $this->_get_compile_path($smarty_tpl_file); $compile_path = $this->_get_compile_path($_smarty_tpl_file);
if($this->security && $this->_is_trusted($_smarty_tpl_file)) {
$_smarty_trusted = true;
$this->security = false;
} else {
$_smarty_trusted = false;
}
// if we just need to display the results, don't perform output // if we just need to display the results, don't perform output
// buffering - for speed // buffering - for speed
if ($smarty_display && !$this->caching) { if ($_smarty_display && !$this->caching) {
echo $info_header; echo $_smarty_info_header;
if ($this->_process_template($smarty_tpl_file, $compile_path)) if ($this->_process_template($_smarty_tpl_file, $compile_path))
{ {
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_BEGIN: ".$smarty_tpl_file." -->\n"; echo "\n<!-- SMARTY_BEGIN: ".$_smarty_tpl_file." -->\n";
} }
include($compile_path); if($this->security && $this->_is_trusted($_smarty_tpl_file)) {
$this->security = false;
include($compile_path);
$this->security = true;
} else {
include($compile_path);
}
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_END: ".$smarty_tpl_file." -->\n"; echo "\n<!-- SMARTY_END: ".$_smarty_tpl_file." -->\n";
} }
} }
} else { } else {
ob_start(); ob_start();
echo $info_header; echo $_smarty_info_header;
if ($this->_process_template($smarty_tpl_file, $compile_path)) if ($this->_process_template($_smarty_tpl_file, $compile_path))
{ {
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_BEGIN: ".$smarty_tpl_file." -->\n"; echo "\n<!-- SMARTY_BEGIN: ".$_smarty_tpl_file." -->\n";
} }
include($compile_path); include($compile_path);
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_END: ".$smarty_tpl_file." -->\n"; echo "\n<!-- SMARTY_END: ".$_smarty_tpl_file." -->\n";
} }
} }
$smarty_results = ob_get_contents(); $_smarty_results = ob_get_contents();
ob_end_clean(); ob_end_clean();
} }
if($_smarty_trusted) {
$this->security = true;
}
if ($this->caching) { if ($this->caching) {
$this->_write_cache_file($smarty_tpl_file, $smarty_cache_id, $smarty_compile_id, $smarty_results); $this->_write_cache_file($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $_smarty_results);
$smarty_results = $this->_process_cached_inserts($smarty_results); $_smarty_results = $this->_process_cached_inserts($_smarty_results);
} }
if ($smarty_display) { if ($_smarty_display) {
if (isset($smarty_results)) { echo $smarty_results; } if (isset($_smarty_results)) { echo $_smarty_results; }
if ($this->debugging) if ($this->debugging)
{ {
// capture time for debugging info // capture time for debugging info
@@ -631,7 +658,7 @@ class Smarty
} }
return; return;
} else { } else {
if (isset($smarty_results)) { return $smarty_results; } if (isset($_smarty_results)) { return $_smarty_results; }
} }
} }
@@ -699,13 +726,108 @@ function _generate_debug_output() {
return $results; return $results;
} }
/*======================================================================*\
Function: _is_trusted()
Purpose: determins if a template is trusted or not. If trusted,
$security is disabled during its execution.
\*======================================================================*/
function _is_trusted($tpl_file) {
static $_trusted_tpls = array();
if(in_array($tpl_file,$_trusted_tpls)) {
return true;
}
$_smarty_trusted = false;
if($this->security && !empty($this->trusted_dir)) {
// see if template file is within a trusted directory. If so,
// disable security during the execution of the template.
// if template is on local file system, check if trusted
$tpl_path_parts = explode(':', $tpl_file, 2);
if (count($tpl_path_parts) == 1) {
// no resource type, treat as type "file"
$resource_type = 'file';
$resource_name = $tpl_path_parts[0];
} else {
$resource_type = $tpl_path_parts[0];
$resource_name = $tpl_path_parts[1];
}
if ($resource_type == 'file') {
if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/",$resource_name)) {
// relative pathname to $template_dir
$resource_name = $this->template_dir.'/'.$resource_name;
}
foreach ($this->trusted_dir as $curr_dir) {
if (substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) {
$_smarty_trusted = true;
$_trusted_tpls[] = $tpl_file;
break;
}
}
} else {
// resource is not on local file system
$_smarty_trusted = false;
}
}
return $_smarty_trusted;
}
/*======================================================================*\
Function: _is_secure()
Purpose: determins if a template is secure or not.
\*======================================================================*/
function _is_secure($tpl_file) {
static $_secure_tpls = array();
if(!$this->security || $this->security_settings['INCLUDE_ANY'] || in_array($tpl_file,$_secure_tpls)) {
return true;
}
$_smarty_secure = false;
// if template is on local file system, check if secure
$tpl_path_parts = explode(':', $tpl_file, 2);
if (count($tpl_path_parts) == 1) {
// no resource type, treat as type "file"
$resource_type = 'file';
$resource_name = $tpl_path_parts[0];
} else {
$resource_type = $tpl_path_parts[0];
$resource_name = $tpl_path_parts[1];
}
if ($resource_type == 'file') {
if(!empty($this->secure_dir)) {
if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/",$resource_name)) {
// relative pathname to $template_dir
$resource_name = $this->template_dir.'/'.$resource_name;
}
foreach ($this->secure_dir as $curr_dir) {
if (substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) {
$_smarty_secure = true;
$_secure_tpls[] = $tpl_file;
break;
}
}
}
} else {
// resource is not on local file system
$_smarty_secure = true;
}
return $_smarty_secure;
}
/*======================================================================*\ /*======================================================================*\
Function: _process_template() Function: _process_template()
Purpose: Purpose:
\*======================================================================*/ \*======================================================================*/
function _process_template($tpl_file, $compile_path) function _process_template($tpl_file, $compile_path)
{ {
// test if template needs to be compiled // test if template needs to be compiled
if (!$this->force_compile && $this->_compiled_template_exists($compile_path)) { if (!$this->force_compile && $this->_compiled_template_exists($compile_path)) {
if (!$this->compile_check) { if (!$this->compile_check) {
// no need to check if the template needs recompiled // no need to check if the template needs recompiled
@@ -787,6 +909,11 @@ function _generate_debug_output() {
\*======================================================================*/ \*======================================================================*/
function _fetch_template_info($tpl_path, &$template_source, &$template_timestamp, $get_source=true) function _fetch_template_info($tpl_path, &$template_source, &$template_timestamp, $get_source=true)
{ {
if ($this->security && !$this->_is_secure($tpl_path) && !$this->_is_trusted($tpl_path)) {
$this->_trigger_error_msg("(secure mode) accessing \"$tpl_path\" is not allowed");
return false;
}
// split tpl_path by the first colon // split tpl_path by the first colon
$tpl_path_parts = explode(':', $tpl_path, 2); $tpl_path_parts = explode(':', $tpl_path, 2);
@@ -814,20 +941,6 @@ function _generate_debug_output() {
$this->_trigger_error_msg("unable to read template resource: \"$tpl_path\""); $this->_trigger_error_msg("unable to read template resource: \"$tpl_path\"");
return false; return false;
} }
// if security is on, make sure template comes from a $secure_dir
if ($this->security && !$this->security_settings['INCLUDE_ANY']) {
$resource_is_secure = false;
foreach ($this->secure_dir as $curr_dir) {
if (substr(realpath($resource_name),0,strlen(realpath($curr_dir))) == realpath($curr_dir)) {
$resource_is_secure = true;
break;
}
}
if (!$resource_is_secure) {
$this->_trigger_error_msg("(secure mode) including \"$resource_name\" is not allowed");
return false;
}
}
break; break;
default: default:
if (isset($this->resource_funcs[$resource_type])) { if (isset($this->resource_funcs[$resource_type])) {
@@ -905,17 +1018,27 @@ function _generate_debug_output() {
array_unshift($this->_config, $this->_config[0]); array_unshift($this->_config, $this->_config[0]);
$compile_path = $this->_get_compile_path($_smarty_include_tpl_file); $compile_path = $this->_get_compile_path($_smarty_include_tpl_file);
if($this->security && $this->_is_trusted($_smarty_include_tpl_file)) {
$_smarty_trusted = true;
$this->security = false;
} else {
$_smarty_trusted = false;
}
if ($this->_process_template($_smarty_include_tpl_file, $compile_path)) { if ($this->_process_template($_smarty_include_tpl_file, $compile_path)) {
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_BEGIN: ".$_smarty_include_tpl_file." -->\n"; echo "\n<!-- SMARTY_BEGIN: ".$_smarty_include_tpl_file." -->\n";
} }
include($compile_path); include($compile_path);
if ($this->show_info_include) { if ($this->show_info_include) {
echo "\n<!-- SMARTY_END: ".$_smarty_include_tpl_file." -->\n"; echo "\n<!-- SMARTY_END: ".$_smarty_include_tpl_file." -->\n";
} }
} }
if ($_smarty_trusted) {
$this->security = true;
}
array_shift($this->_config); array_shift($this->_config);
$this->_inclusion_depth--; $this->_inclusion_depth--;