Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Sun, Feb 2, 6:35 PM

in-portal

Index: branches/5.0.x/core/kernel/nparser/nparser.php
===================================================================
--- branches/5.0.x/core/kernel/nparser/nparser.php (revision 12228)
+++ branches/5.0.x/core/kernel/nparser/nparser.php (revision 12229)
@@ -1,727 +1,732 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
include_once(KERNEL_PATH.'/nparser/ntags.php');
define('TAG_NAMESPACE', 'inp2:');
define('TAG_NAMESPACE_LENGTH', 5);
class NParser extends kBase {
var $Stack = array();
var $Level = 0;
var $Buffers = array();
var $InsideComment = false;
var $Params = array();
var $ParamsStack = array();
var $ParamsLevel = 0;
var $Definitions = '';
var $Elements = array(); // holds dynamic elements to function names mapping during execution
/**
* Holds location of element definitions inside templates.
* key - element function name, value - array of 2 keys: {from_pos, to_pos}
*
* @var Array
*/
var $ElementLocations = Array ();
var $DataExists = false;
var $TemplateName = null;
var $TempalteFullPath = null;
var $CachePointers = array();
var $Cachable = array();
function NParser()
{
parent::kBase();
}
function Compile($pre_parsed, $template_name = 'unknown')
{
$data = file_get_contents($pre_parsed['tname']);
if (!$this->CompileRaw($data, $pre_parsed['tname'], $template_name)) {
// compilation failed during errors in template
// trigger_error('Template "<strong>' . $template_name . '</strong>" not compiled because of errors', E_USER_WARNING);
return false;
}
// saving compiled version (only when compilation was successful)
if (defined('SAFE_MODE') && SAFE_MODE) { // store cache files in database since can't save on filesystem
if (!isset($conn)) $conn =& $this->Application->GetADODBConnection();
$conn->Query('REPLACE INTO '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ('.$conn->qstr($pre_parsed['fname']).','.$conn->qstr($this->Buffers[0]).','.adodb_mktime().')');
}
else {
$compiled = fopen($pre_parsed['fname'], 'w');
if (!fwrite($compiled, $this->Buffers[0])) {
trigger_error('Saving compiled template failed', E_USER_ERROR);
}
fclose($compiled);
}
return true;
}
function Parse($raw_template, $name = null)
{
$this->CompileRaw($raw_template, $name);
ob_start();
$_parser =& $this;
eval('?'.'>'.$this->Buffers[0]);
return ob_get_clean();
}
function CompileRaw($data, $t_name, $template_name = 'unknown')
{
$code = "extract (\$_parser->Params);\n";
$code .= "\$_parser->ElementLocations['{$template_name}'] = Array('template' => '{$template_name}', 'start_pos' => 0, 'end_pos' => " . strlen($data) . ");\n";
// $code .= "__@@__DefinitionsMarker__@@__\n";
// $code .= "if (!\$this->CacheStart('".abs(crc32($t_name))."_0')) {\n";
$this->Buffers[0] = '<?'."php $code ?>\n";
$this->Cacheable[0] = true;
$this->Definitions = '';
// finding all the tags
$reg = '(.*?)(<[\\/]?)' . TAG_NAMESPACE . '([^>]*?)([\\/]?>)(\r\n){0,1}';
preg_match_all('/'.$reg.'/s', $data, $results, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
$this->InsideComment = false;
foreach ($results as $tag_data) {
$tag = array(
'opening' => $tag_data[2][0],
'tag' => $tag_data[3][0],
'closing' => $tag_data[4][0],
'line' => substr_count(substr($data, 0, $tag_data[2][1]), "\n")+1,
'pos' => $tag_data[2][1],
'file' => $t_name,
'template' => $template_name,
);
// the idea is to count number of comment openings and closings before current tag
// if the numbers do not match we inverse the status of InsideComment
if (substr_count($tag_data[1][0], '<!--') != substr_count($tag_data[1][0], '-->')) {
$this->InsideComment = !$this->InsideComment;
}
// appending any text/html data found before tag
$this->Buffers[$this->Level] .= $tag_data[1][0];
if (!$this->InsideComment) {
$tmp_tag = $this->Application->CurrentNTag;
$this->Application->CurrentNTag = $tag;
if ($this->ProcessTag($tag) === false) {
$this->Application->CurrentNTag = $tmp_tag;
return false;
}
$this->Application->CurrentNTag = $tmp_tag;
}
else {
$this->Buffers[$this->Level] .= $tag_data[2][0].$tag_data[3][0].$tag_data[4][0];
}
}
if ($this->Level > 0) {
$this->Application->handleError(E_USER_ERROR, 'Unclosed tag opened by '.$this->TagInfo($this->Stack[$this->Level]->Tag), $this->Stack[$this->Level]->Tag['file'], $this->Stack[$this->Level]->Tag['line']);
return false;
}
// appending text data after last tag (after its closing pos),
// if no tag was found at all ($tag_data is not set) - append the whole $data
$this->Buffers[$this->Level] .= isset($tag_data) ? substr($data, $tag_data[4][1]+strlen($tag_data[4][0])) : $data;
$this->Buffers[$this->Level] = preg_replace('/<!--##(.*?)##-->/s', '', $this->Buffers[$this->Level]); // remove hidden comments IB#23065
// $this->Buffers[$this->Level] .= '<?'.'php '."\n\$_parser->CacheEnd();\n}\n"." ?".">\n";
// $this->Buffers[$this->Level] = str_replace('__@@__DefinitionsMarker__@@__', $this->Definitions, $this->Buffers[$this->Level]);
return true;
}
function SplitParamsStr($params_str)
{
preg_match_all('/([\${}a-zA-Z0-9_.\\-\\\\#\\[\\]]+)=(["\']{1,1})(.*?)(?<!\\\)\\2/s', $params_str, $rets, PREG_SET_ORDER);
$values = Array();
// we need to replace all occurences of any current param $key with {$key} for correct variable substitution
foreach ($rets AS $key => $val){
$values[$val[1]] = str_replace('\\' . $val[2], $val[2], $val[3]);
}
return $values;
}
function SplitTag($tag)
{
if (!preg_match('/([^_ \t\r\n]*)[_]?([^ \t\r\n]*)[ \t\r\n]*(.*)$$/s', $tag['tag'], $parts)) {
// this is virtually impossible, but just in case
$this->Application->handleError(E_USER_ERROR, 'Incorrect tag format: '.$tag['tag'], $tag['file'], $tag['line']);
return false;
}
$splited['prefix'] = $parts[2] ? $parts[1] : '__auto__';
$splited['name'] = $parts[2] ? $parts[2] : $parts[1];
$splited['attrs'] = $parts[3];
return $splited;
}
function ProcessTag($tag)
{
$splited = $this->SplitTag($tag);
if ($splited === false) {
return false;
}
$tag = array_merge($tag, $splited);
$tag['processed'] = false;
$tag['NP'] = $this->SplitParamsStr($tag['attrs']);
$o = '';
$tag['is_closing'] = $tag['opening'] == '</' || $tag['closing'] == '/>';
if (class_exists('_Tag_'.$tag['name'])) { // block tags should have special handling class
if ($tag['opening'] == '<') {
$class = '_Tag_'.$tag['name'];
$instance = new $class($tag);
$instance->Parser =& $this;
/* @var $instance _BlockTag */
$this->Stack[++$this->Level] =& $instance;
$this->Buffers[$this->Level] = '';
$this->Cachable[$this->Level] = true;
$open_code = $instance->Open($tag);
if ($open_code === false) {
return false;
}
$o .= $open_code;
}
if ($tag['is_closing']) { // not ELSE here, because tag may be <empty/> and still has a handler-class
if ($this->Level == 0) {
$dump = array();
foreach ($this->Stack as $instance) {
$dump[] = $instance->Tag;
}
print_pre($dump);
$this->Application->handleError(E_USER_ERROR, 'Closing tag without an opening: '.$this->TagInfo($tag).' <b> - probably opening tag was removed or nested tags error</b>', $tag['file'], $tag['line']);
return false;
}
if ($this->Stack[$this->Level]->Tag['name'] != $tag['name']) {
$opening_tag = $this->Stack[$this->Level]->Tag;
$this->Application->handleError(E_USER_ERROR,
'Closing tag '.$this->TagInfo($tag).' does not match
opening tag at current nesting level ('.$this->TagInfo($opening_tag).'
opened at line '.$opening_tag['line'].')', $tag['file'], $tag['line']);
return false;
}
$o .= $this->Stack[$this->Level]->Close($tag); // DO NOT use $this->Level-- here because it's used inside Close
$this->Level--;
}
}
else { // regular tags - just compile
if (!$tag['is_closing']) {
$this->Application->handleError(E_USER_ERROR, 'Tag without a handler: '.$this->TagInfo($tag).' <b> - probably missing &lt;empty <span style="color: red">/</span>&gt; tag closing</b>', $tag['file'], $tag['line']);
return false;
}
if ($this->Level > 0) $o .= $this->Stack[$this->Level]->PassThrough($tag);
if (!$tag['processed']) {
$compiled = $this->CompileTag($tag);
if ($compiled === false) return false;
if (isset($tag['NP']['cachable']) && (!$tag['NP']['cachable'] || $tag['NP']['cachable'] == 'false')) {
$this->Cachable[$this->Level] = false;
}
$o .= '<?'.'php ' . $compiled . " ?>\n";
// $o .= '<?'.'php ';
// $o .= (isset($tag['NP']['cachable']) && (!$tag['NP']['cachable'] || $tag['NP']['cachable'] == 'false')) ? $this->BreakCache($compiled, $this->GetPointer($tag)) : $compiled;
// $o .= " ?".">\n";
}
}
$this->Buffers[$this->Level] .= $o;
return true;
}
function GetPointer($tag)
{
return abs(crc32($tag['file'])).'_'.$tag['line'];
}
function BreakCache($code, $pointer, $condition='')
{
return "\$_parser->CacheEnd();\n}\n" . $code."\nif ( !\$_parser->CacheStart('{$pointer}'" . ($condition ? ", {$condition}" : '') . ") ) {\n";
}
function TagInfo($tag, $with_params=false)
{
return "<b>{$tag['prefix']}_{$tag['name']}".($with_params ? ' '.$tag['attrs'] : '')."</b>";
}
function CompileParamsArray($arr)
{
$to_pass = 'Array(';
foreach ($arr as $name => $val) {
$to_pass .= '"'.$name.'" => "'.str_replace('"', '\"', $val).'",';
}
$to_pass .= ')';
return $to_pass;
}
function CompileTag($tag)
{
$to_pass = $this->CompileParamsArray($tag['NP']);
$code = '';
if ($tag['prefix'] == '__auto__') {
$prefix = $this->GetParam('PrefixSpecial');
$code .= '$_p_ =& $_parser->GetProcessor($PrefixSpecial);'."\n";
$code .= 'echo $_p_->ProcessParsedTag(\''.$tag['name'].'\', '.$to_pass.', "$PrefixSpecial", \''.$tag['file'].'\', '.$tag['line'].');'."\n";
}
else {
$prefix = $tag['prefix'];
$code .= '$_p_ =& $_parser->GetProcessor("'.$tag['prefix'].'");'."\n";
$code .= 'echo $_p_->ProcessParsedTag(\''.$tag['name'].'\', '.$to_pass.', "'.$tag['prefix'].'", \''.$tag['file'].'\', '.$tag['line'].');'."\n";
}
if (isset($tag['NP']['result_to_var'])) {
$code .= "\$params['{$tag['NP']['result_to_var']}'] = \$_parser->GetParam('{$tag['NP']['result_to_var']}');\n";
$code .= "\${$tag['NP']['result_to_var']} = \$params['{$tag['NP']['result_to_var']}'];\n";
}
if ($prefix && strpos($prefix, '$') === false) {
$p =& $this->GetProcessor($prefix);
if (!is_object($p) || !$p->CheckTag($tag['name'], $tag['prefix'])) {
$this->Application->handleError(E_USER_ERROR, 'Unknown tag: '.$this->TagInfo($tag).' <b> - incorrect tag name or prefix </b>', $tag['file'], $tag['line']);
return false;
}
}
return $code;
}
function CheckTemplate($t, $silent=null)
{
$pre_parsed = $this->Application->TemplatesCache->GetPreParsed($t);
if (!$pre_parsed) {
if (!$silent) {
if ($this->Application->isDebugMode()) $this->Application->Debugger->appendTrace();
trigger_error('Cannot include "<strong>' . $t . '</strong>" - file does not exist', E_USER_ERROR);
}
return false;
}
$force_compile = defined('DBG_NPARSER_FORCE_COMPILE') && DBG_NPARSER_FORCE_COMPILE;
if (!$pre_parsed || !$pre_parsed['active'] || $force_compile) {
$inc_parser = new NParser();
if ($force_compile) {
// remove Front-End theme markings during total compilation
$t = preg_replace('/^theme:.*?\//', '', $t);
}
if (!$inc_parser->Compile($pre_parsed, $t)) return false;
}
return $pre_parsed;
}
function Run($t, $silent=null)
{
+ if ((strpos($t, '../') !== false) || (trim($t) !== $t)) {
+ // when relative paths or special chars are found template names from url, then it's hacking attempt
+ return false;
+ }
+
$pre_parsed = $this->CheckTemplate($t, $silent);
if (!$pre_parsed) return false;
$backup_template = $this->TemplateName;
$backup_fullpath = $this->TempalteFullPath;
$this->TemplateName = $t;
$this->TempalteFullPath = $pre_parsed['tname'];
ob_start();
$_parser =& $this;
if (defined('SAFE_MODE') && SAFE_MODE) { // read cache files from database since can't save on filesystem
$conn =& $this->Application->GetADODBConnection();
$cached = $conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'Cache WHERE VarName = "'.$pre_parsed['fname'].'"');
if ($cached !== false && $cached['Cached'] > filemtime($pre_parsed['tname'])) {
eval('?'.'>'.$cached['Data']);
}
}
else {
if ($pre_parsed['mode'] == 'file') {
include($pre_parsed['fname']);
}
else {
eval('?'.'>'.$pre_parsed['content']);
}
}
$output = ob_get_contents();
ob_end_clean();
$this->TemplateName = $backup_template;
$this->TempalteFullPath = $backup_fullpath;
return $output;
}
function &GetProcessor($prefix)
{
static $Processors = array();
if (!isset($Processors[$prefix])) {
$Processors[$prefix] = $this->Application->recallObject($prefix.'_TagProcessor');
}
return $Processors[$prefix];
}
function SelectParam($params, $possible_names)
{
if (!is_array($params)) return;
if (!is_array($possible_names))
$possible_names = explode(',', $possible_names);
foreach ($possible_names as $name)
{
if( isset($params[$name]) ) return $params[$name];
}
return false;
}
function SetParams($params)
{
$this->Params = $params;
$keys = array_keys($this->Params);
}
function GetParam($name)
{
return isset($this->Params[$name]) ? $this->Params[$name] : false;
}
function SetParam($name, $value)
{
$this->Params[$name] = $value;
}
function PushParams($params)
{
$this->ParamsStack[$this->ParamsLevel++] = $this->Params;
$this->Params = $params;
}
function PopParams()
{
$this->Params = $this->ParamsStack[--$this->ParamsLevel];
}
function ParseBlock($params, $pass_params=false)
{
if (isset($params['cache_timeout']) && ($ret = $this->CacheGet($this->FormCacheKey('element_'.$params['name'])))) {
return $ret;
}
if (substr($params['name'], 0, 5) == 'html:') {
return substr($params['name'], 6);
}
if (!array_key_exists($params['name'], $this->Elements) && array_key_exists('default_element', $params)) {
// when given element not found, but default element name given, then render it instead
$params['name'] = $params['default_element'];
unset($params['default_element']);
return $this->ParseBlock($params, $pass_params);
}
$original_params = $params;
if ($pass_params || isset($params['pass_params'])) $params = array_merge($this->Params, $params);
$this->PushParams($params);
$data_exists_bak = $this->DataExists;
// if we are parsing design block and we have block_no_data - we need to wrap block_no_data into design,
// so we should set DataExists to true manually, otherwise the design block will be skipped because of data_exists in params (by Kostja)
//
// keep_data_exists is used by block RenderElement (always added in ntags.php), to keep the DataExists value
// from inside-content block, otherwise when parsing the design block DataExists will be reset to false resulting missing design block (by Kostja)
//
// Inside-content block parsing result is given to design block in "content" parameter (ntags.php) and "keep_data_exists"
// is only passed, when parsing design block. In case, when $this->DataExists is set to true, but
// zero-length content (in 2 cases: method NParser::CheckNoData set it OR really empty block content)
// is returned from inside-content block, then design block also should not be shown (by Alex)
$this->DataExists = (isset($params['keep_data_exists']) && isset($params['content']) && $params['content'] != '' && $this->DataExists) || (isset($params['design']) && isset($params['block_no_data']) && $params['name'] == $params['design']);
if (!array_key_exists($params['name'], $this->Elements)) {
$pre_parsed = $this->Application->TemplatesCache->GetPreParsed($params['name']);
if ($pre_parsed) {
$ret = $this->IncludeTemplate($params);
if (array_key_exists('no_editing', $params) && $params['no_editing']) {
// when individual render element don't want to be edited
return $ret;
}
return defined('EDITING_MODE') ? $this->DecorateBlock($ret, $params, true) : $ret;
}
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendTrace();
}
$trace_results = debug_backtrace();
$this->Application->handleError(E_USER_ERROR, '<b>Rendering of undefined element '.$params['name'].'</b>', $trace_results[0]['file'], $trace_results[0]['line']);
return false;
}
$m_processor =& $this->GetProcessor('m');
$flag_values = $m_processor->PreparePostProcess($params);
$f_name = $this->Elements[$params['name']];
$ret = $f_name($this, $params);
$ret = $m_processor->PostProcess($ret, $flag_values);
$block_params = $this->Params; // input parameters, but modified inside rendered block
$this->PopParams();
$this->CheckNoData($ret, $params);
$this->DataExists = $data_exists_bak || $this->DataExists;
if (isset($original_params['cache_timeout'])) {
$this->CacheSet($this->FormCacheKey('element_'.$original_params['name']), $ret, $original_params['cache_timeout']);
}
if (array_key_exists('no_editing', $block_params) && $block_params['no_editing']) {
// when individual render element don't want to be edited
return $ret;
}
return defined('EDITING_MODE') ? $this->DecorateBlock($ret, $params) : $ret;
}
function DecorateBlock($block_content, $block_params, $is_template = false)
{
static $used_ids = Array (), $base_url = null;
if (!isset($base_url)) {
$base_url = $this->Application->BaseURL();
}
// $prepend = '[name: ' . $block_params['name'] . '] [params: ' . implode(', ', array_keys($block_params)) . ']';
$decorate = false;
if ($is_template) {
// content inside pair RenderElement tag
// $prepend = '<strong>CONTENT_OF_DESIGN:</strong> ' . $prepend;
if (EDITING_MODE == EDITING_MODE_INSIDES) {
$decorate = true;
}
}
else {
if (strpos($block_params['name'], '__capture_') === 0) {
// capture tag (usually inside pair RenderElement)
// $prepend = '<strong>CAPTURE:</strong> ' . $prepend;
if (EDITING_MODE == EDITING_MODE_INSIDES) {
$decorate = true;
}
}
elseif (array_key_exists('content', $block_params)) {
// pair RenderElement (on template, were it's used)
// $prepend = '<strong>PAIR_RENDER_ELEMENT:</strong> ' . $prepend;
if (EDITING_MODE == EDITING_MODE_DESIGN) {
$decorate = true;
}
}
else {
// non-pair RenderElement
// $prepend = '<strong>SINGLE_RENDER_ELEMENT:</strong> ' . $prepend;
if (EDITING_MODE == EDITING_MODE_INSIDES) {
$decorate = true;
}
if (array_key_exists('layout_view', $block_params) && $block_params['layout_view'] && (EDITING_MODE == EDITING_MODE_LAYOUT)) {
$decorate = true;
}
}
}
if (!$decorate) {
return $block_content;
}
else {
$block_content = /*$prepend .*/ $block_content;
}
$block_name = $block_params['name'];
$function_name = $is_template ? $block_name : $this->Elements[$block_name];
// ensure unique id for every div (used from print lists)
$container_num = 1;
$container_id = 'parser_block[' . $function_name . ']';
while (in_array($container_id . '_' . $container_num, $used_ids)) {
$container_num++;
}
$container_id .= '_' . $container_num;
$used_ids[] = $container_id;
// prepare parameter string
$param_string = $block_name . ':' . $function_name;
$block_editor = '
<div id="' . $container_id . '" params="' . $param_string . '" class="block-edit-btn-container">
<div class="cms-edit-btn">
<div class="cms-btn-image">
<img src="' . $base_url . 'core/admin_templates/img/top_frame/icons/content_mode.gif" width="15" height="16" alt=""/>
</div>
<div class="cms-btn-text" id="' . $container_id . '_btn">Edit</div>
</div>
<div class="cms-btn-content">
%s
</div>
</div>';
// 1 - text before, 2 - open tag, 3 - open tag attributes, 4 - content inside tag, 5 - closing tag, 6 - text after closing tag
if (preg_match('/^(\s*)<(td|span)(.*?)>(.*)<\/(td|span)>(.*)$/is', $block_content, $regs)) {
// div inside span -> put div outside span
return $regs[1] . '<' . $regs[2] . ' ' . $regs[3] . '>' . str_replace('%s', $regs[4], $block_editor) . '</' . $regs[5] . '>' . $regs[6];
}
return str_replace('%s', $block_content, $block_editor);
}
function IncludeTemplate($params, $silent=null)
{
$t = is_array($params) ? $this->SelectParam($params, 't,template,block,name') : $params;
if (isset($params['cache_timeout']) && ($ret = $this->CacheGet('template:'.$t))) {
return $ret;
}
$t = eregi_replace("\.tpl$", '', $t);
$data_exists_bak = $this->DataExists;
$this->DataExists = false;
if (!isset($silent) && array_key_exists('is_silent', $params)) {
$silent = $params['is_silent'];
}
if (isset($params['pass_params'])) {
// ability to pass params from block to template
$params = array_merge($this->Params, $params);
}
$this->PushParams($params);
$ret = $this->Run($t, $silent);
$this->PopParams();
$this->CheckNoData($ret, $params);
$this->DataExists = $data_exists_bak || $this->DataExists;
if (isset($params['cache_timeout'])) {
$this->CacheSet('template:'.$t, $ret, $params['cache_timeout']);
}
return $ret;
}
function CheckNoData(&$ret, $params)
{
if (array_key_exists('data_exists', $params) && $params['data_exists'] && !$this->DataExists) {
$block_no_data = isset($params['BlockNoData']) ? $params['BlockNoData'] : (isset($params['block_no_data']) ? $params['block_no_data'] : false);
if ($block_no_data) {
$ret = $this->ParseBlock(array('name'=>$block_no_data));
}
else {
$ret = '';
}
}
}
function CacheGet($name)
{
if (!$this->Application->ConfigValue('SystemTagCache')) return false;
return $this->Application->CacheGet($name);
}
function CacheSet($name, $value, $expiration=0)
{
if (!$this->Application->ConfigValue('SystemTagCache')) return false;
return $this->Application->CacheSet($name, $value, $expiration);
}
function FormCacheKey($element, $file=null, $add_prefixes=null)
{
if (!isset($file)) {
$file = str_replace(FULL_PATH, '', $this->TempalteFullPath).':'.$this->Application->GetVar('t');
}
$parts = array(
'file_'.$file.'('.filemtime($this->TempalteFullPath).')' => 'serials:file_ts', // theme + template timestamp
'm_lang_'.$this->Application->GetVar('m_lang') => 'serials:lang_ts',
'm_cat_id_'.$this->Application->GetVar('m_cat_id') => 'serials:cat_'.$this->Application->GetVar('m_cat_id').'_ts',
'm_cat_page'.$this->Application->GetVar('m_cat_page') => false,
);
if (isset($add_prefixes)) {
foreach ($add_prefixes as $prefix) {
$parts[$prefix.'_id_'.$this->Application->GetVar("{$prefix}_id")] = "serials:$prefix_".$this->Application->GetVar("{$prefix}_id").'_ts';
$parts[$prefix.'_page_'.$this->Application->GetVar("{$prefix}_Page")] = false;
}
}
$key = '';
foreach ($parts as $part => $ts_name) {
if ($ts_name) {
$ts = $this->Application->CacheGet($ts_name);
$key .= "$part($ts):";
}
else {
$key .= "$part:";
}
}
$key .= $element;
return crc32($key);
}
function PushPointer($pointer)
{
$this->CachePointers[++$this->CacheLevel] = $this->FormCacheKey('pointer:'.$pointer);
return $this->CachePointers[$this->CacheLevel];
}
function PopPointer()
{
return $this->CachePointers[$this->CacheLevel--];
}
function CacheStart($pointer=null)
{
if ($ret = $this->CacheGet($this->PushPointer($pointer)) ) {
echo $ret;
$this->PopPointer();
return true;
}
ob_start();
return false;
}
function CacheEnd($elem=null)
{
$ret = ob_get_clean();
$this->CacheSet($this->PopPointer(), $ret); // . ($this->CurrentKeyPart ? ':'.$this->CurrentKeyPart : '')
echo $ret;
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/parser/template.php
===================================================================
--- branches/5.0.x/core/kernel/parser/template.php (revision 12228)
+++ branches/5.0.x/core/kernel/parser/template.php (revision 12229)
@@ -1,298 +1,305 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
class Template {
var $Body = '';
var $BasePath = '';
var $Filename = '';
function Template($base_path=null, $filename=null, $silent=0)
{
if ($this->SetBasePath($base_path)) {
if (isset($filename)) {
$this->Filename = $filename;
$this->LoadTemplate($silent);
}
}
}
function SetBasePath($base_path=null)
{
if (isset($base_path)) {
$base_path = eregi_replace("/$", '', $base_path); //Cutting possible last slash
$this->BasePath = $base_path;
return true;
}
return false;
}
function GetFullPath()
{
return $this->BasePath.'/'.ltrim($this->Filename, '/').'.tpl';
}
/**
* Enter description here...
*
* @param int $silent template not found {0 - fatal error, 1 - warning, 2 - nothing}
* @return bool
*/
function LoadTemplate($silent = 0)
{
$filename = $this->GetFullPath();
if (file_exists($filename)) {
if (filesize ($filename) == 0) {
trigger_error("Template file size is 0: <b>$filename</b>", ($silent ? E_USER_NOTICE : E_USER_ERROR) );
}
// stripping out special comments
$this->SetBody(preg_replace('/<!--##.*##-->/sU', '', file_get_contents($filename)));
/*$handle = fopen ($filename, "r");
$contents = fread ($handle, filesize ($filename));
$this->SetBody($contents);
fclose ($handle);*/
return true;
}
else {
if (($silent != 2) && !$silent) {
$application =& kApplication::Instance();
if ($application->isDebugMode()) {
$application->Debugger->appendTrace();
}
trigger_error('File or block not found: <b>'.$filename.'</b> at '.$application->Parser->TemplateName, E_USER_ERROR);
}
return false;
}
}
function SetBody($body)
{
$this->Body = $body;
}
function GetBody()
{
return $this->Body;
}
}
class TemplatesCache extends kBase {
var $Templates = Array();
var $BasePath;
var $FileNames = Array();
/**
* Force templates cache to search templates on front-end:
* true - search for theme name in template name
* false - don't search anywhere
* name - theme name to prepend for each template name
*
* @var mixed
*/
var $forceThemeName = false;
function TemplatesCache()
{
parent::kBase();
$this->BasePath = FULL_PATH.THEMES_PATH;
$conn =& $this->Application->GetADODBConnection();
}
/**
* Based on template name gets it's location on disk and owner module
*
* @param string $filename
* @return Array 0 - path on disk, 1 - template name
*/
function GetTemplatePaths($filename)
{
if ($this->Application->IsAdmin() && isset($this->Application->ReplacementTemplates[$filename])) {
$filename = $this->Application->ReplacementTemplates[$filename];
}
// allows to use non-replaced version of replaced template
$filename = preg_replace('/^original:(.*)/', '\\1', $filename);
if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $filename, $regs)) {
$module_filename = $regs[2];
$first_dir = $regs[1];
}
else {
$first_dir = '';
$module_filename = $filename;
}
if (is_string($this->forceThemeName)) {
// when defined, then all templates are read from given theme name
$first_dir = 'theme:' . $this->forceThemeName . ($first_dir ? '/' . $first_dir : '');
}
// !preg_match for backward compatability with full-path plugins
if ($this->Application->IsAdmin() && $first_dir == 'plugins' && !preg_match('/admin_templates/', $module_filename)) {
if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $module_filename, $regs)) {;
$path = MODULES_PATH.'/'.mb_strtolower($first_dir).'/'.$regs[1].'/admin_templates';
$module_filename = $regs[2];
}
else {
$first_dir = '';
$module_filename = $filename;
}
}
elseif ( $this->Application->IsAdmin() && $this->Application->findModule('Name', $first_dir)) {
if ($first_dir == 'in-portal') {
$first_dir = 'kernel';
}
$path = MODULES_PATH.'/'.mb_strtolower($first_dir).'/admin_templates';
}
elseif ($this->forceThemeName && preg_match('/^theme:(.*)/', $first_dir, $regs)) {
// ability to use Front-End templates in admin (only during mass compilation)
$path = FULL_PATH . '/themes/' . $regs[1];
}
else {
$path = $this->BasePath;
$module_filename = $first_dir.'/'.$module_filename;
}
return Array ($path, $module_filename);
}
function LoadTemplate($filename, $title=NULL, $silent=0)
{
list ($path, $module_filename) = $this->GetTemplatePaths($filename);
$template = new Template($path, $module_filename, $silent);
if (!isset($title)) $title = $filename;
$this->SetTemplate($title, $template);
}
function GetRealFilename($filename)
{
list ($path, $module_filename) = $this->GetTemplatePaths($filename);
return $path.'/'.trim($module_filename, '/');
}
function SetTemplate($title, &$template, $filename=null)
{
if (!isset($filename)) $filename=$title;
$this->Templates[$title] = $template;
$this->FileNames[$title] = $filename;
}
function &GetTemplate($title, $silent=0)
{
if (!isset($this->Templates[$title])) {
$this->LoadTemplate($title, null, $silent);
}
return $this->Templates[$title];
}
function GetTemplateBody($title, $silent=0)
{
$template =& $this->GetTemplate($title, $silent);
if ( !is_object($template) ) {
return '';
}
return $template->GetBody();
}
function GetTemplateFileName($title)
{
return getArrayValue($this->FileNames, $title);
}
function SetTemplateBody($title, $body)
{
$template = new Template();
$template->SetBody($body);
$this->SetTemplate($title, $template);
}
function ParseTemplate($template_name)
{
$Parser = new TemplateParser($this->Application);
return $Parser->Parse( $this->GetTemplateBody($template_name) );
}
function TemplateExists($filename)
{
+ if ((strpos($filename, '../') !== false) || (trim($filename) !== $filename)) {
+ // when relative paths or special chars are found template names from url, then it's hacking attempt
+ return false;
+ }
+
$real_file = $this->GetRealFilename( strtolower($filename) );
- if (!preg_match('/\.tpl$/', $real_file)) {
+ if (substr($real_file, -4) != '.tpl') {
+ // add ".tpl" file extension, when not specified in template name
$real_file .= '.tpl';
}
+
return file_exists($real_file);
}
function GetPreParsed($template)
{
$real_name = $this->GetRealFilename($template);
$fname = $real_name.'.php';
$fname = str_replace(FULL_PATH, WRITEABLE . '/cache', $fname);
$tname = $real_name.'.tpl';
if (!file_exists($tname)) {
return false;
}
if (defined('SAFE_MODE') && SAFE_MODE) {
$conn =& $this->Application->GetADODBConnection();
$cached = $conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'Cache WHERE VarName = "'.$fname.'"');
if ($cached !== false && $cached['Cached'] > filemtime($tname)) {
return array('active' => 1, 'fname' => $fname, 'tname' => $tname, 'mode' => 'db', 'content' => $cached['Data']);
}
}
else {
if (file_exists($fname) && file_exists($tname) && filemtime($fname) > filemtime($tname)) {
return array('active' => 1, 'fname' => $fname, 'tname' => $tname, 'mode' => 'file');
}
if (!file_exists($fname)) {
// make sure to create directory if pre-parsed file does not exist
$this->CheckDir( dirname($fname), WRITEABLE . '/cache' );
}
}
return array('active' => 0, 'fname' => $fname, 'tname' => $tname, 'mode'=>'file');
}
/**
* Recursive mkdir
*
* @param string $dir
* @param string $base_path base path to directory where folders should be created in
*/
function CheckDir($dir, $base_path = '')
{
if (file_exists($dir)) {
return;
}
else {
// remove $base_path from beggining because it is already created during install
$dir = preg_replace('/^'.preg_quote($base_path.'/', '/').'/', '', $dir, 1);
$segments = explode('/', $dir);
$cur_path = $base_path;
foreach ($segments as $segment) {
// do not add leading / for windows paths (c:\...)
$cur_path .= preg_match('/^[a-zA-Z]{1}:/', $segment) ? $segment : '/'.$segment;
if (!file_exists($cur_path)) {
mkdir($cur_path);
}
}
}
}
}
?>
\ No newline at end of file

Event Timeline