mirror of
https://github.com/smarty-php/smarty.git
synced 2025-08-04 18:34:27 +02:00
- bugfix a relative sub template path could fail if template_dir path did contain /../ https://github.com/smarty-php/smarty/issues/50
- optimization rework of path normalization
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
===== 3.1.25-dev===== (xx.xx.2015)
|
||||
14.06.2015
|
||||
- bugfix a relative sub template path could fail if template_dir path did contain /../ https://github.com/smarty-php/smarty/issues/50
|
||||
- optimization rework of path normalization
|
||||
|
||||
13.06.2015
|
||||
- bugfix a custom cache resource using smarty_cachereource_keyvaluestore.php did fail if php.ini mbstring.func_overload = 2 (forum topic 25568)
|
||||
|
||||
|
@@ -111,7 +111,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
/**
|
||||
* smarty version
|
||||
*/
|
||||
const SMARTY_VERSION = '3.1.25-dev/6';
|
||||
const SMARTY_VERSION = '3.1.25-dev/7';
|
||||
|
||||
/**
|
||||
* define variable scopes
|
||||
@@ -206,8 +206,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
/**
|
||||
* contains directories outside of SMARTY_DIR that are to be muted by muteExpectedErrors()
|
||||
*/
|
||||
public static $_muted_directories = array('./templates_c/' => null,
|
||||
'./cache/' => null);
|
||||
public static $_muted_directories = array('./templates_c/' => null, './cache/' => null);
|
||||
|
||||
/**
|
||||
* Flag denoting if Multibyte String functions are available
|
||||
@@ -617,10 +616,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $plugin_search_order = array('function',
|
||||
'block',
|
||||
'compiler',
|
||||
'class');
|
||||
public $plugin_search_order = array('function', 'block', 'compiler', 'class');
|
||||
|
||||
/**
|
||||
* registered objects
|
||||
@@ -973,7 +969,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
{
|
||||
$this->template_dir = array();
|
||||
foreach ((array) $template_dir as $k => $v) {
|
||||
$this->template_dir[$k] = rtrim(strtr($v, '\\', '/'), '/') . '/';
|
||||
$this->template_dir[$k] = rtrim($v, '/\\') . DS;
|
||||
}
|
||||
$this->joined_template_dir = join(' # ', $this->template_dir);
|
||||
return $this;
|
||||
@@ -1021,7 +1017,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
{
|
||||
$this->config_dir = array();
|
||||
foreach ((array) $config_dir as $k => $v) {
|
||||
$this->config_dir[$k] = rtrim(strtr($v, '\\', '/'), '/') . '/';
|
||||
$this->config_dir[$k] = rtrim($v, '/\\') . DS;
|
||||
}
|
||||
$this->joined_config_dir = join(' # ', $this->config_dir);
|
||||
return $this;
|
||||
@@ -1067,10 +1063,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
public function setPluginsDir($plugins_dir)
|
||||
{
|
||||
$this->plugins_dir = array();
|
||||
foreach ((array) $plugins_dir as $k => $v) {
|
||||
$this->plugins_dir[$k] = rtrim(strtr($v, '\\', '/'), '/') . '/';
|
||||
}
|
||||
$this->_is_file_cache = array();
|
||||
$this->addPluginsDir($plugins_dir);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -1083,7 +1076,11 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
*/
|
||||
public function addPluginsDir($plugins_dir)
|
||||
{
|
||||
$this->_addDir('plugins_dir', $plugins_dir);
|
||||
// make sure we're dealing with an array
|
||||
$this->plugins_dir = (array) $this->plugins_dir;
|
||||
foreach ((array) $plugins_dir as $v) {
|
||||
$this->plugins_dir[] = rtrim($v, '/\\') . DS;
|
||||
}
|
||||
$this->plugins_dir = array_unique($this->plugins_dir);
|
||||
$this->_is_file_cache = array();
|
||||
return $this;
|
||||
@@ -1108,7 +1105,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
*/
|
||||
public function setCompileDir($compile_dir)
|
||||
{
|
||||
$this->compile_dir = rtrim(strtr($compile_dir, '\\', '/'), '/') . '/';
|
||||
$this->compile_dir = rtrim($compile_dir, '/\\') . DS;
|
||||
if (!isset(Smarty::$_muted_directories[$this->compile_dir])) {
|
||||
Smarty::$_muted_directories[$this->compile_dir] = null;
|
||||
}
|
||||
@@ -1135,11 +1132,10 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
*/
|
||||
public function setCacheDir($cache_dir)
|
||||
{
|
||||
$this->cache_dir = rtrim(strtr($cache_dir, '\\', '/'), '/') . '/';
|
||||
$this->cache_dir = rtrim($cache_dir, '/\\') . DS;
|
||||
if (!isset(Smarty::$_muted_directories[$this->cache_dir])) {
|
||||
Smarty::$_muted_directories[$this->cache_dir] = null;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -1167,23 +1163,21 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
|
||||
if (is_array($dir)) {
|
||||
foreach ($dir as $k => $v) {
|
||||
$v = rtrim(strtr($v, '\\', '/'), '/') . '/';
|
||||
if (is_int($k)) {
|
||||
// indexes are not merged but appended
|
||||
$this->{$dirName}[] = $v;
|
||||
$this->{$dirName}[] = rtrim($v, '/\\') . DS;
|
||||
} else {
|
||||
// string indexes are overridden
|
||||
$this->{$dirName}[$k] = $v;
|
||||
$this->{$dirName}[$k] = rtrim($v, '/\\') . DS;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$v = rtrim(strtr($dir, '\\', '/'), '/') . '/';
|
||||
if ($key !== null) {
|
||||
// override directory at specified index
|
||||
$this->{$dirName}[$key] = $v;
|
||||
$this->{$dirName}[$key] = rtrim($dir, '/\\') . DS;
|
||||
} else {
|
||||
// append new directory
|
||||
$this->{$dirName}[] = $v;
|
||||
$this->{$dirName}[] = rtrim($dir, '/\\') . DS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1420,8 +1414,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
|
||||
// loop through plugin dirs and find the plugin
|
||||
foreach ($this->getPluginsDir() as $_plugin_dir) {
|
||||
$names = array($_plugin_dir . $_plugin_filename,
|
||||
$_plugin_dir . strtolower($_plugin_filename),);
|
||||
$names = array($_plugin_dir . $_plugin_filename, $_plugin_dir . strtolower($_plugin_filename),);
|
||||
foreach ($names as $file) {
|
||||
if (isset($this->_is_file_cache[$file]) ? $this->_is_file_cache[$file] : $this->_is_file_cache[$file] = is_file($file)) {
|
||||
require_once($file);
|
||||
@@ -1678,10 +1671,8 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$allowed = array('template_dir' => 'getTemplateDir',
|
||||
'config_dir' => 'getConfigDir',
|
||||
'plugins_dir' => 'getPluginsDir',
|
||||
'compile_dir' => 'getCompileDir',
|
||||
$allowed = array('template_dir' => 'getTemplateDir', 'config_dir' => 'getConfigDir',
|
||||
'plugins_dir' => 'getPluginsDir', 'compile_dir' => 'getCompileDir',
|
||||
'cache_dir' => 'getCacheDir',);
|
||||
|
||||
if (isset($allowed[$name])) {
|
||||
@@ -1701,10 +1692,8 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$allowed = array('template_dir' => 'setTemplateDir',
|
||||
'config_dir' => 'setConfigDir',
|
||||
'plugins_dir' => 'setPluginsDir',
|
||||
'compile_dir' => 'setCompileDir',
|
||||
$allowed = array('template_dir' => 'setTemplateDir', 'config_dir' => 'setConfigDir',
|
||||
'plugins_dir' => 'setPluginsDir', 'compile_dir' => 'setCompileDir',
|
||||
'cache_dir' => 'setCacheDir',);
|
||||
|
||||
if (isset($allowed[$name])) {
|
||||
@@ -1750,8 +1739,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
unset(Smarty::$_muted_directories[$key]);
|
||||
continue;
|
||||
}
|
||||
$dir = array('file' => $file,
|
||||
'length' => strlen($file),);
|
||||
$dir = array('file' => $file, 'length' => strlen($file),);
|
||||
}
|
||||
if (!strncmp($errfile, $dir['file'], $dir['length'])) {
|
||||
$_is_muted_directory = true;
|
||||
@@ -1793,8 +1781,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
||||
- between file_exists() and filemtime() a possible race condition is opened,
|
||||
which does not exist using the simple @filemtime() approach.
|
||||
*/
|
||||
$error_handler = array('Smarty',
|
||||
'mutingErrorHandler');
|
||||
$error_handler = array('Smarty', 'mutingErrorHandler');
|
||||
$previous = set_error_handler($error_handler);
|
||||
|
||||
// avoid dead loops
|
||||
|
@@ -18,6 +18,8 @@
|
||||
class Smarty_Internal_Resource_File extends Smarty_Resource
|
||||
{
|
||||
|
||||
private $dsMap = array('/' => array(array('\\', '/./'), '/.'), '\\' => array(array('/', '\\.\\'), '\\.'));
|
||||
|
||||
/**
|
||||
* build template filepath by traversing the template_dir array
|
||||
*
|
||||
@@ -29,44 +31,30 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
||||
*/
|
||||
protected function buildFilepath(Smarty_Template_Source $source, Smarty_Internal_Template $_template = null)
|
||||
{
|
||||
$file = str_replace(array('\\', '/./'), '/', $source->name);
|
||||
$file = $source->name;
|
||||
preg_match('#^(?P<absolute>[\\\/]|[a-zA-Z]:[\\\/])|(\[(?P<index>[^\]]+)\])|(?P<rel>\.[\\\/])#', $file, $fileMatch);
|
||||
// save basename
|
||||
if (!empty($fileMatch['absolute'])) {
|
||||
$file = $this->normalizePath($file);
|
||||
return is_file($file) ? $file : false;
|
||||
}
|
||||
// go relative to a given template?
|
||||
if (!empty($fileMatch['rel']) && $_template && $_template->parent instanceof Smarty_Internal_Template) {
|
||||
if ($_template->parent->source->type != 'file' && $_template->parent->source->type != 'extends' && !$_template->parent->allow_relative_path) {
|
||||
throw new SmartyException("Template '{$file}' cannot be relative to template of resource type '{$_template->parent->source->type}'");
|
||||
}
|
||||
$path = dirname($_template->parent->source->filepath) . DS . $file;
|
||||
// normalize path
|
||||
$path = $this->normalizePath($path);
|
||||
// files relative to a template only get one shot
|
||||
return is_file($path) ? $path : false;
|
||||
}
|
||||
|
||||
if ($source->isConfig) {
|
||||
$_directories = $source->smarty->getConfigDir();
|
||||
} else {
|
||||
$_directories = $source->smarty->getTemplateDir();
|
||||
}
|
||||
preg_match('#^((?P<absolute>[\/]|[a-zA-Z]:[\/])|(\[(?P<index>[^\]]+)\])|((?P<rel1>\.[\/])?(?P<rel2>(\.\.[\/])*))|(?P<skip>[\/]))?(?P<file>.+)$#', $file, $fileMatch);
|
||||
// save basename
|
||||
if (!empty($fileMatch['absolute'])) {
|
||||
return is_file($file) ? $file : false;
|
||||
}
|
||||
// go relative to a given template?
|
||||
if ($_template && $_template->parent instanceof Smarty_Internal_Template && (!empty($fileMatch['rel1']) || !empty($fileMatch['rel2']))) {
|
||||
if ($_template->parent->source->type != 'file' && $_template->parent->source->type != 'extends' && !$_template->parent->allow_relative_path) {
|
||||
throw new SmartyException("Template '{$file}' cannot be relative to template of resource type '{$_template->parent->source->type}'");
|
||||
}
|
||||
$path = dirname($_template->parent->source->filepath);
|
||||
if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $path)) {
|
||||
// the path gained from the parent template is relative to the current working directory
|
||||
// as expansions (like include_path) have already been done
|
||||
$path = str_replace('\\', '/', getcwd()) . '/' . $path;
|
||||
}
|
||||
// normalize path
|
||||
$path = str_replace(array('\\', './'), array('/', ''), $path);
|
||||
// simple relative
|
||||
if (!empty($fileMatch['rel1'])) {
|
||||
$file = $path . '/' . $fileMatch['file'];
|
||||
} else {
|
||||
for ($i = 1; $i <= substr_count($fileMatch['rel2'], '../'); $i ++) {
|
||||
$path = substr($path, 0, strrpos($path, '/'));
|
||||
}
|
||||
$file = $path . '/' . $fileMatch['file'];
|
||||
}
|
||||
// files relative to a template only get one shot
|
||||
return is_file($file) ? $file : false;
|
||||
}
|
||||
|
||||
$_filepath = null;
|
||||
// template_dir index?
|
||||
if (!empty($fileMatch['index'])) {
|
||||
$index = $fileMatch['index'];
|
||||
@@ -86,29 +74,24 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
||||
}
|
||||
}
|
||||
if ($_directory) {
|
||||
$_filepath = $_directory . $fileMatch['file'];
|
||||
if (is_file($_filepath)) {
|
||||
return $_filepath;
|
||||
preg_match('#\](.+)$#', $file, $fileMatch);
|
||||
$path = $_directory . $fileMatch[1];
|
||||
$path = $this->normalizePath($path);
|
||||
if (is_file($path)) {
|
||||
return $path;
|
||||
}
|
||||
} else {
|
||||
// index not found
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// relative file name?
|
||||
foreach ($_directories as $_directory) {
|
||||
if (empty($fileMatch['rel2'])) {
|
||||
$_filepath = $_directory . $fileMatch['file'];
|
||||
} else {
|
||||
if (false === strpos($_directory, '..')) {
|
||||
for ($i = 1; $i <= substr_count($fileMatch['rel2'], '../') + 1; $i ++) {
|
||||
$_directory = substr($_directory, 0, strrpos($_directory, '/'));
|
||||
}
|
||||
$_filepath = $_directory . '/' . $fileMatch['file'];
|
||||
} else {
|
||||
$_filepath = $_directory . $file;
|
||||
}
|
||||
}
|
||||
if (is_file($_filepath)) {
|
||||
return $_filepath;
|
||||
$_filepath = $_directory . $file;
|
||||
$path = $this->normalizePath($_filepath);
|
||||
if (is_file($path)) {
|
||||
return $path;
|
||||
}
|
||||
if ($source->smarty->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_directory)) {
|
||||
// try PHP include_path
|
||||
@@ -117,25 +100,38 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
||||
} else {
|
||||
$_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath);
|
||||
}
|
||||
|
||||
if ($_filepath !== false) {
|
||||
if (is_file($_filepath)) {
|
||||
return $_filepath;
|
||||
$path = $this->normalizePath($_filepath);
|
||||
if (is_file($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Could be relative to cwd
|
||||
$path = str_replace('\\', '/', getcwd());
|
||||
if (empty($fileMatch['rel2'])) {
|
||||
$file = $path . '/' . $fileMatch['file'];
|
||||
} else {
|
||||
for ($i = 1; $i <= substr_count($fileMatch['rel2'], '../'); $i ++) {
|
||||
$path = substr($path, 0, strrpos($path, '/'));
|
||||
}
|
||||
$file = $path . '/' . $fileMatch['file'];
|
||||
$path = $this->normalizePath(getcwd() . DS . $file);
|
||||
return is_file($path) ? $path : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize path
|
||||
* - remove /./ and /../
|
||||
* - make it absolute
|
||||
*
|
||||
* @param string $path file path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function normalizePath($path)
|
||||
{
|
||||
if ($path[0] == '.') {
|
||||
$path = getcwd() . DS . $path;
|
||||
}
|
||||
return is_file($file) ? $file : false;
|
||||
$path = str_replace($this->dsMap[DS][0], DS, $path);
|
||||
while (strrpos($path, $this->dsMap[DS][1]) !== false) {
|
||||
$path = preg_replace('#([\\\/][.][\\\/])|([\\\/][^\\\/]+[\\\/][.][.][\\\/])#', DS, $path);
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,13 +162,10 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
||||
if (is_object($source->smarty->security_policy)) {
|
||||
$source->smarty->security_policy->isTrustedResourceDir($source->filepath);
|
||||
}
|
||||
|
||||
$source->uid = sha1(getcwd() . $source->filepath);
|
||||
$source->exists = true;
|
||||
$source->uid = sha1($source->filepath);
|
||||
if ($source->smarty->compile_check && !isset($source->timestamp)) {
|
||||
$source->timestamp = $source->exists = is_file($source->filepath);
|
||||
if ($source->exists) {
|
||||
$source->timestamp = @filemtime($source->filepath);
|
||||
}
|
||||
$source->timestamp = @filemtime($source->filepath);
|
||||
}
|
||||
} else {
|
||||
$source->timestamp = false;
|
||||
|
Reference in New Issue
Block a user