mirror of
https://github.com/smarty-php/smarty.git
synced 2025-08-05 02:44: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)
|
===== 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
|
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)
|
- 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
|
* smarty version
|
||||||
*/
|
*/
|
||||||
const SMARTY_VERSION = '3.1.25-dev/6';
|
const SMARTY_VERSION = '3.1.25-dev/7';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* define variable scopes
|
* 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()
|
* contains directories outside of SMARTY_DIR that are to be muted by muteExpectedErrors()
|
||||||
*/
|
*/
|
||||||
public static $_muted_directories = array('./templates_c/' => null,
|
public static $_muted_directories = array('./templates_c/' => null, './cache/' => null);
|
||||||
'./cache/' => null);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag denoting if Multibyte String functions are available
|
* Flag denoting if Multibyte String functions are available
|
||||||
@@ -617,10 +616,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
public $plugin_search_order = array('function',
|
public $plugin_search_order = array('function', 'block', 'compiler', 'class');
|
||||||
'block',
|
|
||||||
'compiler',
|
|
||||||
'class');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* registered objects
|
* registered objects
|
||||||
@@ -973,7 +969,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
{
|
{
|
||||||
$this->template_dir = array();
|
$this->template_dir = array();
|
||||||
foreach ((array) $template_dir as $k => $v) {
|
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);
|
$this->joined_template_dir = join(' # ', $this->template_dir);
|
||||||
return $this;
|
return $this;
|
||||||
@@ -1021,7 +1017,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
{
|
{
|
||||||
$this->config_dir = array();
|
$this->config_dir = array();
|
||||||
foreach ((array) $config_dir as $k => $v) {
|
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);
|
$this->joined_config_dir = join(' # ', $this->config_dir);
|
||||||
return $this;
|
return $this;
|
||||||
@@ -1067,10 +1063,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
public function setPluginsDir($plugins_dir)
|
public function setPluginsDir($plugins_dir)
|
||||||
{
|
{
|
||||||
$this->plugins_dir = array();
|
$this->plugins_dir = array();
|
||||||
foreach ((array) $plugins_dir as $k => $v) {
|
$this->addPluginsDir($plugins_dir);
|
||||||
$this->plugins_dir[$k] = rtrim(strtr($v, '\\', '/'), '/') . '/';
|
|
||||||
}
|
|
||||||
$this->_is_file_cache = array();
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1083,7 +1076,11 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
*/
|
*/
|
||||||
public function addPluginsDir($plugins_dir)
|
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->plugins_dir = array_unique($this->plugins_dir);
|
||||||
$this->_is_file_cache = array();
|
$this->_is_file_cache = array();
|
||||||
return $this;
|
return $this;
|
||||||
@@ -1108,7 +1105,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
*/
|
*/
|
||||||
public function setCompileDir($compile_dir)
|
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])) {
|
if (!isset(Smarty::$_muted_directories[$this->compile_dir])) {
|
||||||
Smarty::$_muted_directories[$this->compile_dir] = null;
|
Smarty::$_muted_directories[$this->compile_dir] = null;
|
||||||
}
|
}
|
||||||
@@ -1135,11 +1132,10 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
*/
|
*/
|
||||||
public function setCacheDir($cache_dir)
|
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])) {
|
if (!isset(Smarty::$_muted_directories[$this->cache_dir])) {
|
||||||
Smarty::$_muted_directories[$this->cache_dir] = null;
|
Smarty::$_muted_directories[$this->cache_dir] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1167,23 +1163,21 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
|
|
||||||
if (is_array($dir)) {
|
if (is_array($dir)) {
|
||||||
foreach ($dir as $k => $v) {
|
foreach ($dir as $k => $v) {
|
||||||
$v = rtrim(strtr($v, '\\', '/'), '/') . '/';
|
|
||||||
if (is_int($k)) {
|
if (is_int($k)) {
|
||||||
// indexes are not merged but appended
|
// indexes are not merged but appended
|
||||||
$this->{$dirName}[] = $v;
|
$this->{$dirName}[] = rtrim($v, '/\\') . DS;
|
||||||
} else {
|
} else {
|
||||||
// string indexes are overridden
|
// string indexes are overridden
|
||||||
$this->{$dirName}[$k] = $v;
|
$this->{$dirName}[$k] = rtrim($v, '/\\') . DS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$v = rtrim(strtr($dir, '\\', '/'), '/') . '/';
|
|
||||||
if ($key !== null) {
|
if ($key !== null) {
|
||||||
// override directory at specified index
|
// override directory at specified index
|
||||||
$this->{$dirName}[$key] = $v;
|
$this->{$dirName}[$key] = rtrim($dir, '/\\') . DS;
|
||||||
} else {
|
} else {
|
||||||
// append new directory
|
// 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
|
// loop through plugin dirs and find the plugin
|
||||||
foreach ($this->getPluginsDir() as $_plugin_dir) {
|
foreach ($this->getPluginsDir() as $_plugin_dir) {
|
||||||
$names = array($_plugin_dir . $_plugin_filename,
|
$names = array($_plugin_dir . $_plugin_filename, $_plugin_dir . strtolower($_plugin_filename),);
|
||||||
$_plugin_dir . strtolower($_plugin_filename),);
|
|
||||||
foreach ($names as $file) {
|
foreach ($names as $file) {
|
||||||
if (isset($this->_is_file_cache[$file]) ? $this->_is_file_cache[$file] : $this->_is_file_cache[$file] = is_file($file)) {
|
if (isset($this->_is_file_cache[$file]) ? $this->_is_file_cache[$file] : $this->_is_file_cache[$file] = is_file($file)) {
|
||||||
require_once($file);
|
require_once($file);
|
||||||
@@ -1678,10 +1671,8 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
*/
|
*/
|
||||||
public function __get($name)
|
public function __get($name)
|
||||||
{
|
{
|
||||||
$allowed = array('template_dir' => 'getTemplateDir',
|
$allowed = array('template_dir' => 'getTemplateDir', 'config_dir' => 'getConfigDir',
|
||||||
'config_dir' => 'getConfigDir',
|
'plugins_dir' => 'getPluginsDir', 'compile_dir' => 'getCompileDir',
|
||||||
'plugins_dir' => 'getPluginsDir',
|
|
||||||
'compile_dir' => 'getCompileDir',
|
|
||||||
'cache_dir' => 'getCacheDir',);
|
'cache_dir' => 'getCacheDir',);
|
||||||
|
|
||||||
if (isset($allowed[$name])) {
|
if (isset($allowed[$name])) {
|
||||||
@@ -1701,10 +1692,8 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
*/
|
*/
|
||||||
public function __set($name, $value)
|
public function __set($name, $value)
|
||||||
{
|
{
|
||||||
$allowed = array('template_dir' => 'setTemplateDir',
|
$allowed = array('template_dir' => 'setTemplateDir', 'config_dir' => 'setConfigDir',
|
||||||
'config_dir' => 'setConfigDir',
|
'plugins_dir' => 'setPluginsDir', 'compile_dir' => 'setCompileDir',
|
||||||
'plugins_dir' => 'setPluginsDir',
|
|
||||||
'compile_dir' => 'setCompileDir',
|
|
||||||
'cache_dir' => 'setCacheDir',);
|
'cache_dir' => 'setCacheDir',);
|
||||||
|
|
||||||
if (isset($allowed[$name])) {
|
if (isset($allowed[$name])) {
|
||||||
@@ -1750,8 +1739,7 @@ class Smarty extends Smarty_Internal_TemplateBase
|
|||||||
unset(Smarty::$_muted_directories[$key]);
|
unset(Smarty::$_muted_directories[$key]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$dir = array('file' => $file,
|
$dir = array('file' => $file, 'length' => strlen($file),);
|
||||||
'length' => strlen($file),);
|
|
||||||
}
|
}
|
||||||
if (!strncmp($errfile, $dir['file'], $dir['length'])) {
|
if (!strncmp($errfile, $dir['file'], $dir['length'])) {
|
||||||
$_is_muted_directory = true;
|
$_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,
|
- between file_exists() and filemtime() a possible race condition is opened,
|
||||||
which does not exist using the simple @filemtime() approach.
|
which does not exist using the simple @filemtime() approach.
|
||||||
*/
|
*/
|
||||||
$error_handler = array('Smarty',
|
$error_handler = array('Smarty', 'mutingErrorHandler');
|
||||||
'mutingErrorHandler');
|
|
||||||
$previous = set_error_handler($error_handler);
|
$previous = set_error_handler($error_handler);
|
||||||
|
|
||||||
// avoid dead loops
|
// avoid dead loops
|
||||||
|
@@ -18,6 +18,8 @@
|
|||||||
class Smarty_Internal_Resource_File extends Smarty_Resource
|
class Smarty_Internal_Resource_File extends Smarty_Resource
|
||||||
{
|
{
|
||||||
|
|
||||||
|
private $dsMap = array('/' => array(array('\\', '/./'), '/.'), '\\' => array(array('/', '\\.\\'), '\\.'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* build template filepath by traversing the template_dir 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)
|
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) {
|
if ($source->isConfig) {
|
||||||
$_directories = $source->smarty->getConfigDir();
|
$_directories = $source->smarty->getConfigDir();
|
||||||
} else {
|
} else {
|
||||||
$_directories = $source->smarty->getTemplateDir();
|
$_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?
|
// template_dir index?
|
||||||
if (!empty($fileMatch['index'])) {
|
if (!empty($fileMatch['index'])) {
|
||||||
$index = $fileMatch['index'];
|
$index = $fileMatch['index'];
|
||||||
@@ -86,29 +74,24 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($_directory) {
|
if ($_directory) {
|
||||||
$_filepath = $_directory . $fileMatch['file'];
|
preg_match('#\](.+)$#', $file, $fileMatch);
|
||||||
if (is_file($_filepath)) {
|
$path = $_directory . $fileMatch[1];
|
||||||
return $_filepath;
|
$path = $this->normalizePath($path);
|
||||||
|
if (is_file($path)) {
|
||||||
|
return $path;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// index not found
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// relative file name?
|
// relative file name?
|
||||||
foreach ($_directories as $_directory) {
|
foreach ($_directories as $_directory) {
|
||||||
if (empty($fileMatch['rel2'])) {
|
$_filepath = $_directory . $file;
|
||||||
$_filepath = $_directory . $fileMatch['file'];
|
$path = $this->normalizePath($_filepath);
|
||||||
} else {
|
if (is_file($path)) {
|
||||||
if (false === strpos($_directory, '..')) {
|
return $path;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
if ($source->smarty->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_directory)) {
|
if ($source->smarty->use_include_path && !preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $_directory)) {
|
||||||
// try PHP include_path
|
// try PHP include_path
|
||||||
@@ -117,25 +100,38 @@ class Smarty_Internal_Resource_File extends Smarty_Resource
|
|||||||
} else {
|
} else {
|
||||||
$_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath);
|
$_filepath = Smarty_Internal_Get_Include_Path::getIncludePath($_filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_filepath !== false) {
|
if ($_filepath !== false) {
|
||||||
if (is_file($_filepath)) {
|
$path = $this->normalizePath($_filepath);
|
||||||
return $_filepath;
|
if (is_file($path)) {
|
||||||
|
return $path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Could be relative to cwd
|
// Could be relative to cwd
|
||||||
$path = str_replace('\\', '/', getcwd());
|
$path = $this->normalizePath(getcwd() . DS . $file);
|
||||||
if (empty($fileMatch['rel2'])) {
|
return is_file($path) ? $path : false;
|
||||||
$file = $path . '/' . $fileMatch['file'];
|
}
|
||||||
} else {
|
|
||||||
for ($i = 1; $i <= substr_count($fileMatch['rel2'], '../'); $i ++) {
|
/**
|
||||||
$path = substr($path, 0, strrpos($path, '/'));
|
* Normalize path
|
||||||
}
|
* - remove /./ and /../
|
||||||
$file = $path . '/' . $fileMatch['file'];
|
* - 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)) {
|
if (is_object($source->smarty->security_policy)) {
|
||||||
$source->smarty->security_policy->isTrustedResourceDir($source->filepath);
|
$source->smarty->security_policy->isTrustedResourceDir($source->filepath);
|
||||||
}
|
}
|
||||||
|
$source->exists = true;
|
||||||
$source->uid = sha1(getcwd() . $source->filepath);
|
$source->uid = sha1($source->filepath);
|
||||||
if ($source->smarty->compile_check && !isset($source->timestamp)) {
|
if ($source->smarty->compile_check && !isset($source->timestamp)) {
|
||||||
$source->timestamp = $source->exists = is_file($source->filepath);
|
$source->timestamp = @filemtime($source->filepath);
|
||||||
if ($source->exists) {
|
|
||||||
$source->timestamp = @filemtime($source->filepath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$source->timestamp = false;
|
$source->timestamp = false;
|
||||||
|
Reference in New Issue
Block a user