Index: branches/RC/core/kernel/nparser/nparser.php =================================================================== diff -u -N --- branches/RC/core/kernel/nparser/nparser.php (revision 11934) +++ branches/RC/core/kernel/nparser/nparser.php (revision 0) @@ -1,727 +0,0 @@ -CompileRaw($data, $pre_parsed['tname'], $template_name)) { - // compilation failed during errors in template -// trigger_error('Template "' . $template_name . '" 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] = '\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], '')) { - $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] .= '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})(.*?)(? $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'] == ''; - 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 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).' - probably opening tag was removed or nested tags error', $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).' - probably missing <empty /> tag closing', $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 .= '\n"; -// $o .= '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 "{$tag['prefix']}_{$tag['name']}".($with_params ? ' '.$tag['attrs'] : '').""; - } - - 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).' - incorrect tag name or prefix ', $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 "' . $t . '" - 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) - { - $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, 'Rendering of undefined element '.$params['name'].'', $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 = 'CONTENT_OF_DESIGN: ' . $prepend; - - if (EDITING_MODE == EDITING_MODE_INSIDES) { - $decorate = true; - } - } - else { - if (strpos($block_params['name'], '__capture_') === 0) { - // capture tag (usually inside pair RenderElement) -// $prepend = 'CAPTURE: ' . $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 = 'PAIR_RENDER_ELEMENT: ' . $prepend; - - if (EDITING_MODE == EDITING_MODE_DESIGN) { - $decorate = true; - } - } - else { - // non-pair RenderElement -// $prepend = 'SINGLE_RENDER_ELEMENT: ' . $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 = ' -
-
-
- -
-
Edit
-
-
- %s -
-
'; - - // 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[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