/** * Compile a template into a list of appendable outputs, for the closure-style Tempcode implementation. * * @param string The template file contents * @param ID_TEXT The name of the template * @param ID_TEXT The name of the theme * @param ID_TEXT The language it is for * @param boolean Whether to tolerate errors * @return array A pair: array Compiled result structure, array preprocessable bits (special stuff needing attention that is referenced within the template) */ function compile_template($data, $template_name, $theme, $lang, $tolerate_errors = false) { if (strpos($data, '{$,Parser hint: pure}') !== false) { return array(array('"' . php_addslashes(preg_replace('#\\{\\$,.*\\}#U', '/*no minify*/', $data)) . '"'), array()); } $data = preg_replace('#<\\?php(.*)\\?' . '>#sU', '{+START,PHP}${1}{+END}', $data); $compilable_symbols = array('"ADDON_INSTALLED"', '"COPYRIGHT"', '"SITE_NAME"', '"BRAND_BASE_URL"', '"BRAND_NAME"', '"IMG_WIDTH"', '"IMG_HEIGHT"', '"LANG"', '"THEME"', '"VALUE_OPTION"', '"CONFIG_OPTION"'); if (function_exists('get_option') && get_option('enable_https', true) != '1') { $compilable_symbols[] = '"BASE_URL"'; } global $SITE_INFO; if (isset($SITE_INFO['no_keep_params']) && $SITE_INFO['no_keep_params'] == '1') { $compilable_symbols[] = '"PAGE_LINK"'; $compilable_symbols[] = '"FIND_SCRIPT"'; } require_code('lang'); require_code('urls'); $cl = fallback_lang(); $bits = array_values(preg_split('#(?<!\\\\)(\\{(?=[\\dA-Z\\$\\+\\!\\_]+[\\.`%\\*=\\;\\#\\-~\\^\\|\'&/@]*))|((?<!\\\\)\\,)|((?<!\\\\)\\})#', $data, -1, PREG_SPLIT_DELIM_CAPTURE)); // One error mail showed on a server it had weird indexes, somehow. Hence the array_values call to reindex it $count = count($bits); $stack = array(); $current_level_mode = PARSE_NO_MANS_LAND; $current_level_data = array(); $current_level_params = array(); $preprocessable_bits = array(); for ($i = 0; $i < $count; $i++) { $next_token = $bits[$i]; if ($next_token == '') { continue; } if ($i != $count - 1 && $next_token == '{' && preg_match('#^[\\dA-Z\\$\\+\\!\\_]#', $bits[$i + 1]) == 0) { $current_level_data[] = '"{}"'; continue; } switch ($next_token) { case '{': // Open a new level $stack[] = array($current_level_mode, $current_level_data, $current_level_params, NULL, NULL, NULL); ++$i; $next_token = isset($bits[$i]) ? $bits[$i] : NULL; if (is_null($next_token)) { if ($tolerate_errors) { continue; } warn_exit(do_lang_tempcode('ABRUPTED_DIRECTIVE_OR_BRACE', escape_html($template_name), integer_format(1 + substr_count(substr($data, 0, _length_so_far($bits, $i)), chr(10))))); } $current_level_data = array(); switch (substr($next_token, 0, 1)) { case '$': $current_level_mode = PARSE_SYMBOL; $current_level_data[] = '"' . php_addslashes(substr($next_token, 1)) . '"'; break; case '+': $current_level_mode = PARSE_DIRECTIVE; $current_level_data[] = '"' . php_addslashes(substr($next_token, 1)) . '"'; break; case '!': $current_level_mode = PARSE_LANGUAGE_REFERENCE; $current_level_data[] = '"' . php_addslashes(substr($next_token, 1)) . '"'; break; default: $current_level_mode = PARSE_PARAMETER; $current_level_data[] = '"' . php_addslashes($next_token) . '"'; break; } $current_level_params = array(); break; case '}': if (count($stack) == 0 || $current_level_mode == PARSE_DIRECTIVE_INNER) { $literal = php_addslashes($next_token); if ($GLOBALS['XSS_DETECT']) { ocp_mark_as_escaped($literal); } $current_level_data[] = '"' . $literal . '"'; break; } $opener_params = array_merge($current_level_params, array($current_level_data)); $__first_param = array_shift($opener_params); $_first_param = implode('.', $__first_param); if ($bits[$i - 1] == '') { $current_level_data[] = '""'; } // Return to the previous level $past_level_data = $current_level_data; $past_level_params = $current_level_params; $past_level_mode = $current_level_mode; if (count($stack) == 0) { if (!$tolerate_errors) { warn_exit(do_lang_tempcode('TEMPCODE_TOO_MANY_CLOSES', escape_html($template_name), integer_format(1 + _length_so_far($bits, $i)))); } } else { list($current_level_mode, $current_level_data, $current_level_params, , , ) = array_pop($stack); } // Handle the level we just closed if (function_exists('str_split')) { $_escaped = str_split(preg_replace('#[^:\\.`%\\*=\\;\\#\\-~\\^\\|\'&/@]:?#', '', $_first_param)); // :? is so that the ":" in lang strings does not get considered an escape } else { $temp = preg_replace('#[^:\\.`%\\*=\\;\\#\\-~\\^\\|\'&/@]:?#', '', $_first_param); $_escaped = array(); for ($j = 0; $j < strlen($temp); $j++) { $_escaped[] = $temp[$j]; } } $escaped = array(); foreach ($_escaped as $e) { switch ($e) { case '`': $escaped[] = NULL_ESCAPED; break; case '%': $escaped[] = NAUGHTY_ESCAPED; break; case '*': $escaped[] = ENTITY_ESCAPED; break; case '=': $escaped[] = FORCIBLY_ENTITY_ESCAPED; break; case ';': $escaped[] = SQ_ESCAPED; break; case '#': $escaped[] = DQ_ESCAPED; break; case '~': $escaped[] = NL_ESCAPED; break; case '^': $escaped[] = NL2_ESCAPED; break; case '|': $escaped[] = ID_ESCAPED; break; case '\'': $escaped[] = CSS_ESCAPED; break; case '&': $escaped[] = UL_ESCAPED; break; case '.': $escaped[] = UL2_ESCAPED; break; case '/': $escaped[] = JSHTML_ESCAPED; break; case '@': $escaped[] = CC_ESCAPED; break; // This is used as a hint to not preprocess // This is used as a hint to not preprocess case '-': } } $_opener_params = ''; foreach ($opener_params as $param) { if ($param == array()) { $param = array('""'); } if ($_opener_params != '') { $_opener_params .= ','; } $_opener_params .= implode('.', $param); } $first_param = str_replace(array('`', '%', '*', '=', ';', '#', '-', '~', '^', '|', '\'', '&', '.', '/', '@'), array('', '', '', '', '', '', '', '', '', '', '', '', '', '', ''), $_first_param); switch ($past_level_mode) { case PARSE_SYMBOL: $no_preprocess = in_array('-', $_escaped); if (!$no_preprocess) { switch ($first_param) { case '"CSS_INCLUDE"': case '"JAVASCRIPT_INCLUDE"': case '"JS_TEMPCODE"': case '"CSS_TEMPCODE"': case '"SET"': case '"BLOCK"': case '"LOAD_PAGE"': case '"LOAD_PANEL"': foreach ($stack as $level_test) { if ($level_test[3] == PARSE_DIRECTIVE && isset($level_test[5][1]) && isset($level_test[5][1][0]) && $level_test[5][1][0] == '"LOOP"') { $eval = @eval('return array(' . $_opener_params . ');'); if (is_array($eval)) { $pp_bit = array(array(), TC_SYMBOL, str_replace('"', '', $first_param), $eval); $preprocessable_bits[] = $pp_bit; } break 2; } } $symbol_params = array(); foreach ($opener_params as $param) { if ($param == array()) { $param = array('""'); } $myfunc = 'tcpfunc_' . fast_uniqid(); $funcdef = build_closure_function($myfunc, $param); $symbol_params[] = new ocp_tempcode(array($funcdef, array(array($myfunc, array(), TC_KNOWN, '', '')))); // Parameters will be bound in later. } $pp_bit = array(array(), TC_SYMBOL, str_replace('"', '', $first_param), $symbol_params); $preprocessable_bits[] = $pp_bit; break; } } if ($first_param == '"IMG"' && strpos($_opener_params, ',') === false) { $_opener_params .= ',"0","' . php_addslashes($theme) . '"'; } if ($first_param == '"?"') { if (implode('.', $opener_params[0]) == '"1".""') { if (isset($opener_params[1])) { $current_level_data[] = implode('.', $opener_params[1]); } break; } if (implode('.', $opener_params[0]) == '"0".""' || implode('.', $opener_params[0]) == '""') { if (isset($opener_params[2])) { $current_level_data[] = implode('.', $opener_params[2]); } break; } } if ($first_param != '""') { $new_line = 'ecv($cl,array(' . implode(',', $escaped) . '),' . strval(TC_SYMBOL) . ',' . $first_param . ',array(' . $_opener_params . '))'; if (in_array($first_param, $compilable_symbols) && preg_match('#^[^\\(\\)]*$#', $_opener_params) != 0) { $new_line = '"' . php_addslashes(eval('return ' . $new_line . ';')) . '"'; } $current_level_data[] = $new_line; } break; case PARSE_LANGUAGE_REFERENCE: $new_line = 'ecv($cl,array(' . implode(',', $escaped) . '),' . strval(TC_LANGUAGE_REFERENCE) . ',' . $first_param . ',array(' . $_opener_params . '))'; if ($_opener_params == '' && count($escaped) == 0) { $looked_up = do_lang(eval('return ' . $first_param . ';'), NULL, NULL, NULL, $lang, false); if (!is_null($looked_up)) { if (apply_tempcode_escaping($escaped, $looked_up) == $looked_up) { $new_line = '"' . php_addslashes($looked_up) . '"'; } } } $current_level_data[] = $new_line; break; case PARSE_PARAMETER: $parameter = str_replace('"', '', str_replace("'", '', $first_param)); $parameter = preg_replace('#[^\\w\\_\\d]#', '', $parameter); // security to stop PHP injection $temp = 'output_tempcode_parameter( isset ($bound_' . php_addslashes($parameter) . ')?$bound_' . php_addslashes($parameter) . ':NULL,"' . php_addslashes($parameter) . '","' . php_addslashes($template_name) . '")'; if (count($escaped) == 0) { $current_level_data[] = $temp; } else { $s_escaped = ''; foreach ($escaped as $esc) { if ($s_escaped != '') { $s_escaped .= ','; } $s_escaped .= strval($esc); } if ($s_escaped == strval(ENTITY_ESCAPED) && !$GLOBALS['XSS_DETECT']) { $current_level_data[] = '( isset ($bound_' . $parameter . ')?(((isset($bound_' . $parameter . '->preprocessable_bits)) && ($bound_' . $parameter . '->pure_lang))?' . $temp . ':str_replace($GLOBALS[\'HTML_ESCAPE_1_STRREP\'],$GLOBALS[\'HTML_ESCAPE_2\'],' . $temp . ')):attach_message(do_lang_tempcode(\'MISSING_TEMPLATE_PARAMETER\',"' . php_addslashes($parameter) . '","' . php_addslashes($template_name) . '"),"warn"))'; } else { if ($s_escaped == strval(ENTITY_ESCAPED)) { $current_level_data[] = '( isset ($bound_' . $parameter . ')?(((isset($bound_' . $parameter . '->preprocessable_bits)) && ($bound_' . $parameter . '->pure_lang))?' . $temp . ':apply_tempcode_escaping_inline(array(' . $s_escaped . '),' . $temp . ')):attach_message(do_lang_tempcode(\'MISSING_TEMPLATE_PARAMETER\',"' . php_addslashes($parameter) . '","' . php_addslashes($template_name) . '"),"warn"))'; } else { $current_level_data[] = '( isset ($bound_' . $parameter . ')?apply_tempcode_escaping_inline(array(' . $s_escaped . '),' . $temp . '):attach_message(do_lang_tempcode(\'MISSING_TEMPLATE_PARAMETER\',"' . php_addslashes($parameter) . '","' . php_addslashes($template_name) . '"),"warn"))'; } } } break; } // Handle directive nesting if ($past_level_mode == PARSE_DIRECTIVE) { $eval = @eval('return ' . $first_param . ';'); if (!is_string($eval)) { $eval = ''; } if ($eval == 'START') { // Open a new directive level $stack[] = array($current_level_mode, $current_level_data, $current_level_params, $past_level_mode, $past_level_data, $past_level_params); $current_level_data = array(); $current_level_params = array(); $current_level_mode = PARSE_DIRECTIVE_INNER; } elseif ($eval == 'END') { // Test that the top stack does represent a started directive, and close directive level $past_level_data = $current_level_data; if ($past_level_data == array()) { $past_level_data = array('""'); } $past_level_params = $current_level_params; $past_level_mode = $current_level_mode; if (count($stack) == 0) { if ($tolerate_errors) { continue; } warn_exit(do_lang_tempcode('TEMPCODE_TOO_MANY_CLOSES', escape_html($template_name), integer_format(1 + substr_count(substr($data, 0, _length_so_far($bits, $i)), chr(10))))); } list($current_level_mode, $current_level_data, $current_level_params, $directive_level_mode, $directive_level_data, $directive_level_params) = array_pop($stack); if (!is_array($directive_level_params)) { if ($tolerate_errors) { continue; } warn_exit(do_lang_tempcode('UNCLOSED_DIRECTIVE_OR_BRACE', escape_html($template_name), integer_format(1 + substr_count(substr($data, 0, _length_so_far($bits, $i)), chr(10))))); } $directive_opener_params = array_merge($directive_level_params, array($directive_level_data)); if ($directive_level_mode != PARSE_DIRECTIVE || $directive_opener_params[0][0] != '"START"') { if ($tolerate_errors) { continue; } warn_exit(do_lang_tempcode('TEMPCODE_TOO_MANY_CLOSES', escape_html($template_name), integer_format(1 + substr_count(substr($data, 0, _length_so_far($bits, $i)), chr(10))))); } // Handle directive if (count($directive_opener_params) == 1) { if ($tolerate_errors) { continue; } warn_exit(do_lang_tempcode('NO_DIRECTIVE_TYPE', escape_html($template_name), integer_format(1 + substr_count(substr($data, 0, _length_so_far($bits, $i)), chr(10))))); } $directive_params = ''; $first_directive_param = '""'; if ($directive_opener_params[1] == array()) { $directive_opener_params[1] = array('""'); } for ($j = 2; $j < count($directive_opener_params); $j++) { if ($directive_opener_params[$j] == array()) { $directive_opener_params[$j] = array('""'); } if ($directive_params != '') { $directive_params .= ','; } $directive_params .= implode('.', $directive_opener_params[$j]); if ($j == 2) { $first_directive_param = implode('.', $directive_opener_params[$j]); } } $eval = @eval('return ' . implode('.', $directive_opener_params[1]) . ';'); if (!is_string($eval)) { $eval = ''; } $directive_name = $eval; switch ($directive_name) { case 'FRACTIONAL_EDITABLE': $pp_bit = array(array(), TC_DIRECTIVE, str_replace('"', '', $directive_name), array()); $preprocessable_bits[] = $pp_bit; break; } switch ($directive_name) { case 'IF': if (preg_match('#^ecv\\(\\$cl,array\\(\\),0,"NOT",array\\("1"\\)\\).""$#', $first_directive_param) != 0) { $first_directive_param = '"0".""'; } if (preg_match('#^ecv\\(\\$cl,array\\(\\),0,"NOT",array\\("0"\\)\\).""$#', $first_directive_param) != 0) { $first_directive_param = '"1".""'; } if ($first_directive_param == '"1".""') { $current_level_data[] = '(' . implode('.', $past_level_data) . ')'; } elseif ($first_directive_param != '"0".""') { $current_level_data[] = '((' . $first_directive_param . '=="1")?(' . implode('.', $past_level_data) . '):\'\')'; } break; case 'IF_EMPTY': $current_level_data[] = '((' . $first_directive_param . '==\'\')?(' . implode('.', $past_level_data) . '):\'\')'; break; case 'WHILE': $current_level_data[] = 'closure_while_loop(array($parameters,$cl,$last_attach),' . chr(10) . 'create_function(\'$parameters,$cl,$last_attach\',"extract(\\$parameters,EXTR_PREFIX_ALL,\'bound\'); return (' . php_addslashes($first_directive_param) . ')==\\"1\\";"),' . chr(10) . 'create_function(\'$parameters,$cl,$last_attach\',"extract(\\$parameters,EXTR_PREFIX_ALL,\'bound\'); return ' . php_addslashes(implode('.', $past_level_data)) . ';"))'; break; case 'PHP': $current_level_data[] = 'closure_eval(' . implode('.', $past_level_data) . ',$parameters)'; break; case 'LOOP': $current_level_data[] = 'closure_loop(array(' . $directive_params . ',\'vars\'=>$parameters),array($parameters,$cl,$last_attach),' . chr(10) . 'create_function(\'$parameters,$cl,$last_attach\',"extract(\\$parameters,EXTR_PREFIX_ALL,\'bound\'); return ' . php_addslashes(implode('.', $past_level_data)) . ';"))'; break; case 'IF_NON_EMPTY': $current_level_data[] = '((' . $first_directive_param . '!=\'\')?(' . implode('.', $past_level_data) . '):\'\')'; break; case 'IF_PASSED': $eval = @eval('return ' . $first_directive_param . ';'); if (!is_string($eval)) { $eval = ''; } $current_level_data[] = '(isset($bound_' . preg_replace('#[^\\w\\d\\_]#', '', $eval) . ')?(' . implode('.', $past_level_data) . '):\'\')'; break; case 'IF_NON_PASSED': $eval = @eval('return ' . $first_directive_param . ';'); if (!is_string($eval)) { $eval = ''; } $current_level_data[] = '(!isset($bound_' . preg_replace('#[^\\w\\d\\_]#', '', $eval) . ')?(' . implode('.', $past_level_data) . '):\'\')'; break; case 'IF_ADJACENT': $current_level_data[] = '(($last_attach=="' . php_addslashes($template_name) . '")?(' . implode('.', $past_level_data) . '):\'\')'; break; case 'IF_NON_ADJACENT': $current_level_data[] = '(($last_attach!="' . php_addslashes($template_name) . '")?(' . implode('.', $past_level_data) . '):\'\')'; break; case 'SHIFT_ENCODE': $eval = @eval('return ' . implode('.', $directive_opener_params[2]) . ';'); if (!is_string($eval)) { $eval = ''; } $key = $eval; $set_op = '$GLOBALS[\'SHIFT_VARIABLES\']["' . php_addslashes($key) . '"]=make_string_tempcode(' . implode('.', $past_level_data) . ')'; if (array_key_exists(3, $directive_opener_params)) { $attach_op = '$GLOBALS[\'SHIFT_VARIABLES\']["' . php_addslashes($key) . '"]->attach(' . implode('.', $past_level_data) . ')'; $is_set_check = 'array_key_exists("' . php_addslashes($key) . '",$GLOBALS[\'SHIFT_VARIABLES\'])'; // NB: The "/*SHIFT_ENCODE*/" bit is critical, it's used as a marker for identifying the need for preexecution $current_level_data[] = '/*SHIFT_ENCODE*/(is_null(((!' . $is_set_check . ') || (' . implode('.', $directive_opener_params[3]) . '==\'0\'))' . '?' . $set_op . ':' . $attach_op . ')?\'\':\'\')'; } else { $current_level_data[] = '/*SHIFT_ENCODE*/(is_null(' . $set_op . ')?\'\':\'\')'; } break; case 'INCLUDE': global $FILE_ARRAY; if (count($directive_opener_params) == 3 && $past_level_data == array('""') && !isset($FILE_ARRAY)) { $eval = @eval('return ' . $first_directive_param . ';'); if (!is_string($eval)) { $eval = ''; } $found = find_template_place($eval, '', $theme, '.tpl', 'templates'); $_theme = $found[0]; $fullpath = get_custom_file_base() . '/themes/' . $_theme . $found[1] . $eval . '.tpl'; if (!is_file($fullpath)) { $fullpath = get_file_base() . '/themes/' . $_theme . $found[1] . $eval . '.tpl'; } $filecontents = @file_get_contents($fullpath, FILE_TEXT); if ($filecontents === false) { $filecontents = ''; } list($_current_level_data, $_preprocessable_bits) = compile_template($filecontents, $eval, $theme, $lang); $current_level_data = array_merge($current_level_data, $_current_level_data); $preprocessable_bits = array_merge($preprocessable_bits, $_preprocessable_bits); break; } default: if ($directive_params != '') { $directive_params .= ','; } $directive_params .= implode('.', $past_level_data); if (isset($GLOBALS['DIRECTIVES_NEEDING_VARS'][$directive_name])) { $current_level_data[] = 'ecv($cl,array(),' . strval(TC_DIRECTIVE) . ',' . implode('.', $directive_opener_params[1]) . ',array(' . $directive_params . ',\'vars\'=>$parameters))'; } else { $current_level_data[] = 'ecv($cl,array(),' . strval(TC_DIRECTIVE) . ',' . implode('.', $directive_opener_params[1]) . ',array(' . $directive_params . '))'; } break; } } else { $eval = @eval('return ' . $first_param . ';'); if (!is_string($eval)) { $eval = ''; } $directive_name = $eval; if (isset($GLOBALS['DIRECTIVES_NEEDING_VARS'][$directive_name])) { $current_level_data[] = 'ecv($cl,array(' . implode(',', $escaped) . '),' . strval(TC_DIRECTIVE) . ',' . $first_param . ',array(' . $_opener_params . ',\'vars\'=>$parameters))'; } else { $current_level_data[] = 'ecv($cl,array(' . implode(',', $escaped) . '),' . strval(TC_DIRECTIVE) . ',' . $first_param . ',array(' . $_opener_params . '))'; } } } break; case ',': switch ($current_level_mode) { case PARSE_NO_MANS_LAND: case PARSE_DIRECTIVE_INNER: $current_level_data[] = '\',\''; break; default: $current_level_params[] = $current_level_data; $current_level_data = array(); break; } break; default: $literal = php_addslashes(str_replace('\\,', ',', str_replace('\\}', '}', str_replace('\\{', '{', $next_token)))); if ($GLOBALS['XSS_DETECT']) { ocp_mark_as_escaped($literal); } $current_level_data[] = '"' . $literal . '"'; break; } } if (!array_key_exists('LAX_COMCODE', $GLOBALS) || !$GLOBALS['LAX_COMCODE']) { if (count($stack) != 0) { if (!$tolerate_errors) { warn_exit(do_lang_tempcode('UNCLOSED_DIRECTIVE_OR_BRACE', escape_html($template_name), integer_format(1 + substr_count(substr($data, 0, _length_so_far($bits, $i)), chr(10))))); } } } return array($current_level_data, $preprocessable_bits); }
/** * Get a tempcoded version of a normal XHTML template. It is perhaps the most common ocPortal function to load up templates using do_template, and then attach them together either as parameters to each other, or via the tempcode attach method. * * @param ID_TEXT The codename of the template being loaded * @param ?array A map of parameters for the template (key to value) (NULL: no parameters) * @param ?LANGUAGE_NAME The language to load the template in (templates can embed language references) (NULL: users own language) * @param boolean Whether to not produce a stack dump if the template is missing * @param ?ID_TEXT Alternate template to use if the primary one does not exist (NULL: none) * @param string File type suffix of template file (e.g. .tpl) * @param string Subdirectory type to look in * @set templates css * @param ?ID_TEXT Theme to use (NULL: current theme) * @return tempcode The tempcode for this template */ function do_template($codename, $parameters = NULL, $lang = NULL, $light_error = false, $fallback = NULL, $suffix = '.tpl', $type = 'templates', $theme = NULL) { if (!isset($lang) || $lang == '') { global $USER_LANG_CACHED; $lang = isset($USER_LANG_CACHED) ? $USER_LANG_CACHED : (function_exists('user_lang') ? user_lang() : 'EN'); } if ($GLOBALS['SEMI_DEBUG_MODE']) { if ($codename == strtolower($codename) && $type != 'css' && $codename != 'tempcode_test' && $codename != 'handle_conflict_resolution') { fatal_exit('Template names should be in upper case, and the files should be stored in upper case.'); } if (substr($codename, -7) == '_SCREEN' || substr($codename, -8) == '_OVERLAY' || $codename == 'POOR_XHTML_WRAPPER' || $codename == 'OCF_WRAPPER') { $GLOBALS['SCREEN_TEMPLATE_CALLED'] = $codename; } } global $TEMPLATE_PREVIEW_OP, $RECORD_TEMPLATES_USED, $RECORDED_TEMPLATES_USED, $FILE_ARRAY, $MEM_CACHE, $KEEP_MARKERS, $SHOW_EDIT_LINKS, $XHTML_SPIT_OUT, $CACHE_TEMPLATES, $FORUM_DRIVER, $POSSIBLY_IN_SAFE_MODE, $CACHED_THEME, $CACHED_FOUND, $LOADED_TPL_CACHE; $special_treatment = ($KEEP_MARKERS || $SHOW_EDIT_LINKS) && is_null($XHTML_SPIT_OUT); if ($RECORD_TEMPLATES_USED) { $RECORDED_TEMPLATES_USED[] = $codename; } // Variables we'll need if (!isset($theme)) { $theme = isset($CACHED_THEME) ? $CACHED_THEME : (isset($FORUM_DRIVER) && is_object($FORUM_DRIVER) && method_exists($FORUM_DRIVER, 'get_theme') ? filter_naughty($FORUM_DRIVER->get_theme()) : 'default'); } $prefix_default = get_file_base() . '/themes/'; $prefix = $theme == 'default' ? $prefix_default : get_custom_file_base() . '/themes/'; // Is it structurally cached on disk yet? if (!isset($CACHED_FOUND[$codename][$lang][$theme][$suffix][$type])) { $loaded_this_once = false; } else { $loaded_this_once = true; } $_data = false; if ($CACHE_TEMPLATES && !$TEMPLATE_PREVIEW_OP && (!$POSSIBLY_IN_SAFE_MODE || !in_safe_mode())) { $tcp_path = $prefix . $theme . '/templates_cached/' . $lang . '/' . $codename . $suffix . '.tcp'; if ($loaded_this_once) { if (isset($LOADED_TPL_CACHE[$codename][$theme])) { $_data = $LOADED_TPL_CACHE[$codename][$theme]; } else { $_data = new ocp_tempcode(); $test = $_data->from_assembly_executed($tcp_path, array($codename, $codename, $lang, $theme, $suffix, $type, $fallback)); if (!$test) { $_data = false; } // failed } } else { global $SITE_INFO; $support_smart_decaching = !isset($SITE_INFO['disable_smart_decaching']) || $SITE_INFO['disable_smart_decaching'] == '0'; if ($support_smart_decaching) { if (!isset($CACHED_FOUND[$codename][$lang][$theme][$suffix][$type])) { $found = find_template_place($codename, $lang, $theme, $suffix, $type); $CACHED_FOUND[$codename][$lang][$theme][$suffix][$type] = $found; } else { $found = $CACHED_FOUND[$codename][$lang][$theme][$suffix][$type]; } if (!is_null($found)) { if (isset($GLOBALS['CURRENT_SHARE_USER'])) { $file_path = get_custom_file_base() . '/themes/' . $found[0] . $found[1] . $codename . $suffix; if (!is_file($file_path)) { $file_path = get_file_base() . '/themes/' . $found[0] . $found[1] . $codename . $suffix; } } else { $file_path = ($theme == 'default' && $suffix != '.css' ? get_file_base() : get_custom_file_base()) . '/themes/' . $found[0] . $found[1] . $codename . $suffix; } $tcp_time = @filemtime($tcp_path); } else { $tcp_time = false; } } if (!$support_smart_decaching || $tcp_time !== false && is_file($file_path) && $found !== NULL) { if (!$support_smart_decaching || filemtime($file_path) < $tcp_time) { $_data = new ocp_tempcode(); $test = $_data->from_assembly_executed($tcp_path, array($codename, $codename, $lang, $theme, $suffix, $type, $fallback)); if (!$test) { $_data = false; } // failed } } } } if ($_data === false) { if (!isset($CACHED_FOUND[$codename][$lang][$theme][$suffix][$type])) { $found = find_template_place($codename, $lang, $theme, $suffix, $type); $CACHED_FOUND[$codename][$lang][$theme][$suffix][$type] = $found; } else { $found = $CACHED_FOUND[$codename][$lang][$theme][$suffix][$type]; } unset($CACHED_FOUND[$codename][$lang][$theme][$suffix][$type]); if (is_null($found)) { if (is_null($fallback)) { if ($light_error) { return paragraph(do_lang_tempcode('MISSING_TEMPLATE_FILE', escape_html($codename)), '34rwefwfdee'); } fatal_exit(do_lang_tempcode('MISSING_TEMPLATE_FILE', escape_html($codename))); } else { $result = do_template($fallback, $parameters, $lang); return $result; } } else { require_code('tempcode_compiler'); $_data = _do_template($found[0], $found[1], $codename, $codename, $lang, $suffix, $theme); } } if ($loaded_this_once) { // On 3rd load (and onwards) it will be fully cached $LOADED_TPL_CACHE[$codename][$theme] = $_data; } if (!isset($parameters)) { $out = new ocp_tempcode(); $out->codename = $codename; $out->code_to_preexecute = $_data->code_to_preexecute; $out->preprocessable_bits = $_data->preprocessable_bits; $out->seq_parts = $_data->seq_parts; foreach ($out->seq_parts as $i => $bit) { if ($bit[1] != array()) { $out->seq_parts[$i][1] = array(); } } return $out; } $ret = $_data->bind($parameters, $codename); if ($special_treatment) { $ret->codename = '(mixed)'; // Stop optimisation that assumes the codename represents the sole content of it } if ($special_treatment) { if ($KEEP_MARKERS) { $__data = new ocp_tempcode(); $__data->attach('<!-- START-TEMPLATE=' . escape_html($codename) . ' -->'); $__data->attach($ret); $__data->attach('<!-- END-TEMPLATE=' . escape_html($codename) . ' -->'); $ret = $__data; } if ($SHOW_EDIT_LINKS && $codename != 'PARAM_INFO') { $edit_url = build_url(array('page' => 'admin_themes', 'type' => '_edit_templates', 'theme' => $theme, 'f0file' => $codename), 'adminzone'); $parameters2 = array(); foreach ($parameters as $k => $v) { if (is_array($v)) { $parameters2[$k] = '(array)'; } elseif (!is_object($v)) { $parameters2[$k] = $v; } else { $parameters2[$k] = $v->evaluate(); if (strlen($parameters2[$k]) > 100) { $parameters2[$k] = substr($parameters2[$k], 0, 100) . '...'; } } } $param_info = do_template('PARAM_INFO', array('MAP' => $parameters2)); $SHOW_EDIT_LINKS = false; $ret = do_template('TEMPLATE_EDIT_LINK', array('_GUID' => '511ae911d31a5b237a4371ff22fc78fd', 'PARAM_INFO' => $param_info, 'CONTENTS' => $ret, 'CODENAME' => $codename, 'EDIT_URL' => $edit_url)); $SHOW_EDIT_LINKS = true; } } return $ret; }
/** * Force a CSS file to be cached. * * @param string The CSS file required * @param ?ID_TEXT The name of the theme (NULL: current theme) * @param ?boolean Whether to minify (NULL: read from environment) * @return string The path to the CSS file in the cache (blank: no file) */ function css_enforce($c, $theme = NULL, $minify = NULL) { $text_only = get_param_integer('keep_textonly', 0) == 1; if ($text_only) { $c .= '_textonly'; } if ($minify === NULL) { $minify = get_param_integer('keep_no_minify', 0) == 0; } global $SITE_INFO; // Make sure the CSS file exists if ($theme === NULL) { $theme = @method_exists($GLOBALS['FORUM_DRIVER'], 'get_theme') ? $GLOBALS['FORUM_DRIVER']->get_theme() : 'default'; } $active_theme = $theme; $dir = get_custom_file_base() . '/themes/' . $theme . '/templates_cached/' . filter_naughty(user_lang()); if (!isset($SITE_INFO['no_disk_sanity_checks']) || $SITE_INFO['no_disk_sanity_checks'] == '0') { if (!is_dir($dir)) { if (@mkdir($dir, 0777) === false) { warn_exit(do_lang_tempcode('WRITE_ERROR_DIRECTORY_REPAIR', escape_html($dir))); } fix_permissions($dir, 0777); sync_file($dir); } } $css_cache_path = $dir . '/' . filter_naughty_harsh($c); if (!$minify) { $css_cache_path .= '_non_minified'; } if (get_option('enable_https', true) == '1' && function_exists('is_page_https') && function_exists('get_zone_name') && (tacit_https() || is_page_https(get_zone_name(), get_page_name()))) { $css_cache_path .= '_ssl'; } if (is_mobile()) { $css_cache_path .= '_mobile'; } $css_cache_path .= '.css'; global $CACHE_TEMPLATES; $support_smart_decaching = !isset($SITE_INFO['disable_smart_decaching']) || $SITE_INFO['disable_smart_decaching'] == '0'; $is_cached = ($CACHE_TEMPLATES || !running_script('index')) && @(filesize($css_cache_path) != 0) && !is_browser_decacheing() && !in_safe_mode(); if ($support_smart_decaching || !$is_cached || $text_only) { $found = find_template_place($c, '', $theme, '.css', 'css'); if ($found === NULL) { return ''; } $theme = $found[0]; $fullpath = get_custom_file_base() . '/themes/' . $theme . $found[1] . $c . '.css'; if (!is_file($fullpath)) { $fullpath = get_file_base() . '/themes/' . $theme . $found[1] . $c . '.css'; } if ($text_only && !is_file($fullpath)) { return ''; } } if (!$is_cached || $support_smart_decaching && (@(filemtime($css_cache_path) < filemtime($fullpath)) && @filemtime($fullpath) < time())) { require_code('css_and_js'); css_compile($active_theme, $theme, $c, $fullpath, $css_cache_path, $minify); } if (@filesize($css_cache_path) == 0) { return ''; } return $css_cache_path; }
/** * Handle special page type output. * * @param ID_TEXT The special page type. * @set query templates tree lang * @param tempcode The normal script tempcode output * @param string The normal script evaluated output */ function special_page_types($special_page_type, &$out, $out_evaluated) { global $RECORDED_TEMPLATES_USED; if (function_exists('set_time_limit')) { @set_time_limit(280); } $echo = do_header(); //$echo->evaluate_echo(); $echo2 = new ocp_tempcode(); if (is_null($out_evaluated)) { ob_start(); $out->evaluate_echo(); // False evaluation ob_end_clean(); } // HACKHACK: Yuck. we have to after-the-fact make it wide, and empty lots of internal caching to reset the state. $_GET['wide_high'] = '1'; $_GET['wide'] = '1'; $GLOBALS['LOADED_PANELS'] = array(); $GLOBALS['IS_WIDE_HIGH'] = 1; $GLOBALS['IS_WIDE'] = 1; $GLOBALS['TEMPCODE_SETGET'] = array(); $GLOBALS['LOADED_TPL_CACHE'] = array(); $GLOBALS['HELPER_PANEL_PIC'] = NULL; $GLOBALS['HELPER_PANEL_TEXT'] = NULL; $GLOBALS['HELPER_PANEL_TUTORIAL'] = NULL; $GLOBALS['HELPER_PANEL_HTML'] = NULL; // CSS if (substr($special_page_type, -4) == '.css') { $url = build_url(array('page' => 'admin_themes', 'type' => 'edit_css', 'theme' => $GLOBALS['FORUM_DRIVER']->get_theme(), 'file' => $special_page_type, 'keep_wide_high' => 1), get_module_zone('admin_themes')); header('Location: ' . $url->evaluate()); exit; } // Site Tree Editor if ($special_page_type == 'site_tree') { $url = build_url(array('page' => 'admin_sitetree', 'type' => 'site_tree', 'id' => get_zone_name() . ':' . get_page_name()), get_module_zone('admin_sitetree')); header('Location: ' . $url->evaluate()); exit; } // IDE linkage if ($special_page_type == 'ide_linkage') { $title = get_page_title('IDE_LINKAGE'); $file_links = new ocp_tempcode(); global $JAVASCRIPTS, $CSSS, $_REQUIRED_CODE, $LANGS_REQUESTED; /*foreach (array_keys($JAVASCRIPTS) as $name) Already in list of templates { $txtmte_url='txmt://open?url=file://'.$name; $file_links->attach(do_template('INDEX_SCREEN_ENTRY',array('URL'=>$txtmte_url,'NAME'=>$name))); }*/ foreach (array_keys($CSSS) as $name) { $search = find_template_place($name, get_site_default_lang(), $GLOBALS['FORUM_DRIVER']->get_theme(), '.css', 'css'); if (!is_null($search)) { list($theme, $type) = $search; $txtmte_url = 'txmt://open?url=file://' . get_file_base() . '/themes/' . $theme . '/' . $type . '/' . $name . '.css'; $file_links->attach(do_template('INDEX_SCREEN_ENTRY', array('DISPLAY_STRING' => '(CSS)', 'URL' => $txtmte_url, 'NAME' => $name . '.css'))); } } foreach (array_keys($_REQUIRED_CODE) as $name) { $path_a = get_file_base() . '/' . (strpos($name, '.php') === false ? '/sources_custom/' . $name . '.php' : $name); $path_b = get_file_base() . '/' . (strpos($name, '.php') === false ? '/sources/' . $name . '.php' : str_replace('_custom', '', $name)); if (file_exists($path_a)) { $txtmte_url = 'txmt://open?url=file://' . $path_a; $file_links->attach(do_template('INDEX_SCREEN_ENTRY', array('DISPLAY_STRING' => '(PHP)', 'URL' => $txtmte_url, 'NAME' => $name . (strpos($name, '.php') === false ? '.php' : '')))); } if (file_exists($path_b)) { $txtmte_url = 'txmt://open?url=file://' . $path_b; $file_links->attach(do_template('INDEX_SCREEN_ENTRY', array('DISPLAY_STRING' => '(PHP)', 'URL' => $txtmte_url, 'NAME' => $name . (strpos($name, '.php') === false ? '.php' : '')))); } } foreach (array_keys($LANGS_REQUESTED) as $name) { if (file_exists(get_file_base() . '/lang_custom/' . fallback_lang() . '/' . $name . '.ini')) { $txtmte_url = 'txmt://open?url=file://' . get_file_base() . '/lang_custom/' . fallback_lang() . '/' . $name . '.ini'; $file_links->attach(do_template('INDEX_SCREEN_ENTRY', array('DISPLAY_STRING' => '(Language)', 'URL' => $txtmte_url, 'NAME' => $name . '.ini'))); } if (file_exists(get_file_base() . '/lang/' . fallback_lang() . '/' . $name . '.ini')) { $txtmte_url = 'txmt://open?url=file://' . get_file_base() . '/lang/' . fallback_lang() . '/' . $name . '.ini'; $file_links->attach(do_template('INDEX_SCREEN_ENTRY', array('DISPLAY_STRING' => '(Language)', 'URL' => $txtmte_url, 'NAME' => $name . '.ini'))); } } foreach (array_unique($RECORDED_TEMPLATES_USED) as $name) { $search = find_template_place($name, get_site_default_lang(), $GLOBALS['FORUM_DRIVER']->get_theme(), '.tpl', 'templates'); if (!is_null($search)) { list($theme, $type) = $search; $txtmte_url = 'txmt://open?url=file://' . get_file_base() . '/themes/' . $theme . '/' . $type . '/' . $name . '.tpl'; $file_links->attach(do_template('INDEX_SCREEN_ENTRY', array('DISPLAY_STRING' => '(Templates)', 'URL' => $txtmte_url, 'NAME' => $name . '.tpl'))); } } $echo2 = do_template('INDEX_SCREEN', array('TITLE' => $title, 'CONTENT' => $file_links, 'PRE' => do_lang_tempcode('TXMT_PROTOCOL_EXPLAIN'), 'POST' => '')); } // Theme images mode if ($special_page_type == 'theme_images') { $title = get_page_title('THEME_IMAGE_EDITING'); $theme_images = new ocp_tempcode(); global $RECORDED_IMG_CODES; foreach (array_keys($RECORDED_IMG_CODES) as $theme_image_details) { list($id, $theme, $lang) = unserialize($theme_image_details); $url = build_url(array('page' => 'admin_themes', 'type' => 'edit_image', 'theme' => is_null($theme) ? $GLOBALS['FORUM_DRIVER']->get_theme() : $theme, 'lang' => $lang, 'id' => $id), 'adminzone'); $image = find_theme_image($id, false, false, $theme, $lang); if ($image == '') { continue; } $theme_images->attach(do_template('INDEX_SCREEN_FANCIER_ENTRY', array('IMG' => $image, 'DESCRIPTION' => '', 'URL' => $url, 'NAME' => $id))); } $echo2 = do_template('INDEX_SCREEN_FANCIER_SCREEN', array('TITLE' => $title, 'CONTENT' => $theme_images, 'PRE' => do_lang_tempcode('CONTEXTUAL_EDITING_SCREEN'), 'POST' => '')); } // Profile mode? if ($special_page_type == 'profile') { if (function_exists('xdebug_dump_function_profile')) { $type = XDEBUG_PROFILER_FS_SUM; xdebug_dump_function_profile($type); } else { $echo2 = make_string_tempcode('Check out the dump using KCacheGrind.'); } } elseif (substr($special_page_type, 0, 12) == 'lang_content') { $map_a = get_file_base() . '/lang/langs.ini'; $map_b = get_custom_file_base() . '/lang_custom/langs.ini'; if (!file_exists($map_b)) { $map_b = $map_a; } $map = better_parse_ini_file($map_b); $lang_name = user_lang(); if (array_key_exists($lang_name, $map)) { $lang_name = $map[$lang_name]; } global $RECORDED_LANG_STRINGS_CONTENT; require_lang('lang'); require_code('form_templates'); $fields = new ocp_tempcode(); require_code('lang2'); $names = find_lang_content_names(array_keys($RECORDED_LANG_STRINGS_CONTENT)); foreach ($RECORDED_LANG_STRINGS_CONTENT as $key => $forum_db) { $value_found = get_translated_text($key, $forum_db ? $GLOBALS['FORUM_DB'] : $GLOBALS['SITE_DB']); if ($value_found != '') { $description = make_string_tempcode(escape_html($value_found)); if (get_value('google_translate_api_key') === NULL || user_lang() == get_site_default_lang()) { $actions = new ocp_tempcode(); } else { require_javascript('javascript_translate'); $actions = do_template('TRANSLATE_ACTION', array('LANG_FROM' => get_site_default_lang(), 'LANG_TO' => user_lang(), 'NAME' => 'trans_' . strval($key), 'OLD' => $value_found)); } $description->attach($actions); $fields->attach(form_input_text(is_null($names[$key]) ? '#' . strval($key) : $names[$key], $description, 'trans_' . strval($key), $value_found, false)); } } if ($fields->is_empty()) { inform_exit(do_lang_tempcode('NOTHING_TO_TRANSLATE')); } $title = get_page_title('__TRANSLATE_CONTENT', true, array($lang_name)); $post_url = build_url(array('page' => 'admin_lang', 'type' => '_content', 'contextual' => 1), 'adminzone'); $hidden = form_input_hidden('redirect', get_self_url(true, true)); $hidden = form_input_hidden('lang', user_lang()); $echo2 = do_template('FORM_SCREEN', array('_GUID' => '0d4dd16b023d0a7960f3eac85f54ddc4', 'SKIP_VALIDATION' => true, 'TITLE' => $title, 'HIDDEN' => $hidden, 'FIELDS' => $fields, 'URL' => $post_url, 'TEXT' => do_lang_tempcode('CONTEXTUAL_EDITING_SCREEN'), 'SUBMIT_NAME' => do_lang_tempcode('SAVE'))); } elseif (substr($special_page_type, 0, 4) == 'lang') { $map_a = get_file_base() . '/lang/langs.ini'; $map_b = get_custom_file_base() . '/lang_custom/langs.ini'; if (!file_exists($map_b)) { $map_b = $map_a; } $map = better_parse_ini_file($map_b); $lang_name = user_lang(); if (array_key_exists($lang_name, $map)) { $lang_name = $map[$lang_name]; } global $RECORDED_LANG_STRINGS; require_lang('lang'); require_code('form_templates'); require_code('lang2'); $fields = new ocp_tempcode(); $descriptions = get_lang_file_descriptions(fallback_lang()); foreach (array_keys($RECORDED_LANG_STRINGS) as $key) { $value_found = do_lang($key, NULL, NULL, NULL, NULL, false); $description = array_key_exists($key, $descriptions) ? make_string_tempcode($descriptions[$key]) : new ocp_tempcode(); if (!is_null($value_found)) { if (get_value('google_translate_api_key') === NULL || user_lang() == get_site_default_lang()) { $actions = new ocp_tempcode(); } else { require_javascript('javascript_translate'); $actions = do_template('TRANSLATE_ACTION', array('LANG_FROM' => get_site_default_lang(), 'LANG_TO' => user_lang(), 'NAME' => 'l_' . $key, 'OLD' => str_replace('\\n', chr(10), $value_found))); } $description->attach($actions); $fields->attach(form_input_text($key, $description, 'l_' . $key, str_replace('\\n', chr(10), $value_found), false)); } } $title = get_page_title('__TRANSLATE_CODE', true, array($lang_name)); $post_url = build_url(array('page' => 'admin_lang', 'type' => '_code2'), 'adminzone'); $hidden = form_input_hidden('redirect', get_self_url(true, true)); $hidden = form_input_hidden('lang', user_lang()); $echo2 = do_template('FORM_SCREEN', array('_GUID' => '0d4dd16b023d0a7960f3eac85f54ddc4', 'SKIP_VALIDATION' => true, 'TITLE' => $title, 'HIDDEN' => $hidden, 'FIELDS' => $fields, 'URL' => $post_url, 'TEXT' => do_lang_tempcode('CONTEXTUAL_EDITING_SCREEN'), 'SUBMIT_NAME' => do_lang_tempcode('SAVE'))); } // Template mode? if ($special_page_type == 'templates' || $special_page_type == 'tree') { require_lang('themes'); global $RECORD_TEMPLATES_USED; $RECORD_TEMPLATES_USED = false; $templates = new ocp_tempcode(); if ($special_page_type == 'templates') { $title = get_page_title('TEMPLATES'); $_RECORDED_TEMPLATES_USED = array_count_values($RECORDED_TEMPLATES_USED); ksort($_RECORDED_TEMPLATES_USED); foreach ($_RECORDED_TEMPLATES_USED as $name => $count) { //$restore_from=find_template_path($name); $file = $name . '.tpl'; $edit_url = build_url(array('page' => 'admin_themes', 'type' => '_edit_templates', 'theme' => $GLOBALS['FORUM_DRIVER']->get_theme(), 'f0file' => $file), 'adminzone', NULL, false, true); $templates->attach(do_template('TEMPLATE_LIST_ENTRY', array('COUNT' => integer_format($count), 'NAME' => $name, 'EDIT_URL' => $edit_url))); } } else { $title = get_page_title('TEMPLATE_TREE'); $hidden = new ocp_tempcode(); global $CSSS, $JAVASCRIPTS; foreach (array_keys($CSSS) as $c) { $hidden->attach(form_input_hidden('f' . strval(mt_rand(0, 100000)) . 'file', $c . '.css')); } foreach (array_keys($JAVASCRIPTS) as $c) { $hidden->attach(form_input_hidden('f' . strval(mt_rand(0, 100000)) . 'file', strtoupper($c) . '.tpl')); } $edit_url = build_url(array('page' => 'admin_themes', 'type' => '_edit_templates', 'preview_url' => get_self_url(true, false, array('special_page_type' => NULL)), 'theme' => $GLOBALS['FORUM_DRIVER']->get_theme()), 'adminzone', NULL, false, true); $tree = find_template_tree_nice($out->codename, $out->children, $out->fresh); $templates = do_template('TEMPLATE_TREE', array('_GUID' => 'ff2a2233b8b4045ba4d8777595ef64c7', 'HIDDEN' => $hidden, 'EDIT_URL' => $edit_url, 'TREE' => $tree)); } $echo2 = do_template('TEMPLATE_LIST_SCREEN', array('_GUID' => 'ab859f67dcb635fcb4d1747d3c6a2c17', 'TITLE' => $title, 'TEMPLATES' => $templates)); } // Query mode? if ($special_page_type == 'query') { require_lang("profiling"); global $QUERY_LIST; $queries = new ocp_tempcode(); $total_time = 0.0; global $M_SORT_KEY; $M_SORT_KEY = 'time'; usort($QUERY_LIST, 'multi_sort'); $QUERY_LIST = array_reverse($QUERY_LIST); foreach ($QUERY_LIST as $query) { $queries->attach(do_template('QUERY_LOG', array('_GUID' => 'ab88e1e92609136229ad920c30647647', 'TIME' => float_format($query['time'], 3), 'TEXT' => $query['text']))); $total_time += $query['time']; } $title = get_page_title("VIEW_PAGE_QUERIES"); $total = count($QUERY_LIST); $echo2 = do_template('QUERY_SCREEN', array('_GUID' => '5f679c8f657b4e4ae94ae2d0ed4843fa', 'TITLE' => $title, 'TOTAL' => integer_format($total), 'TOTAL_TIME' => float_format($total_time, 3), 'QUERIES' => $queries)); } $echo->attach(globalise($echo2)); $echo->attach(do_footer()); $echo->handle_symbol_preprocessing(); $echo->evaluate_echo(); exit; }