/** * Processes a raw template for conditionals, phrases etc into PHP code for eval() * * @param string Template * * @return string */ function compile_template($template, &$errors = array()) { $orig_template = $template; $template = preg_replace('#[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F]#', '', $template); $new_syntax = (strpos($template, '<vb:') !== false OR strpos($template, '{vb:') !== false); $old_syntax = (strpos($template, '<if') !== false OR strpos($template, '<phrase') !== false); $maybe_old_syntax = preg_match('/(^|[^{])\$[a-z0-9_]+\[?/si', $template); if (!$new_syntax AND ($old_syntax OR $maybe_old_syntax)) { $template = addslashes($template); $template = process_template_conditionals($template); $template = process_template_phrases('phrase', $template, 'parse_phrase_tag'); $template = process_seo_urls($template); if (!function_exists('replace_template_variables') OR !function_exists('validate_string_for_interpolation')) { require_once(DIR . '/includes/functions_misc.php'); } //only check the old style syntax, the new style doesn't use string interpolation and isn't affected //by this exploit. The new syntax doesn't 100% pass this check. if(!validate_string_for_interpolation($template)) { global $vbphrase; echo "<p> </p><p> </p>"; print_form_header('', '', 0, 1, '', '65%'); print_table_header($vbphrase['vbulletin_message']); print_description_row($vbphrase['template_text_not_safe']); print_table_footer(2, construct_button_code($vbphrase['go_back'], 'javascript:history.back(1)')); print_cp_footer(); exit; } $template = replace_template_variables($template, false); $template = str_replace('\\\\$', '\\$', $template); if (function_exists('token_get_all')) { $tokens = @token_get_all('<?php $var = "' . $template . '"; ?>'); foreach ($tokens AS $token) { if (is_array($token)) { switch ($token[0]) { case T_INCLUDE: case T_INCLUDE_ONCE: case T_REQUIRE: case T_REQUIRE_ONCE: { global $vbphrase; echo "<p> </p><p> </p>"; print_form_header('', '', 0, 1, '', '65%'); print_table_header($vbphrase['vbulletin_message']); print_description_row($vbphrase['file_inclusion_not_permitted']); print_table_footer(2, construct_button_code($vbphrase['go_back'], 'javascript:history.back(1)')); print_cp_footer(); exit; } } } } } } else { require_once(DIR . '/includes/class_template_parser.php'); $parser = new vB_TemplateParser($orig_template); try { $parser->validate($errors); } catch (vB_Exception_TemplateFatalError $e) { global $vbphrase; echo "<p> </p><p> </p>"; print_form_header('', '', 0, 1, '', '65%'); print_table_header($vbphrase['vbulletin_message']); print_description_row($vbphrase[$e->getMessage()]); print_table_footer(2, construct_button_code($vbphrase['go_back'], 'javascript:history.back(1)')); print_cp_footer(); exit; } $template = $parser->compile(); // TODO: Reimplement these - if done, $session[], $bbuserinfo[], $vboptions will parse in the template without using {vb:raw, which isn't what we // necessarily want to happen /* if (!function_exists('replace_template_variables')) { require_once(DIR . '/includes/functions_misc.php'); } $template = replace_template_variables($template, false); */ } if (function_exists('verify_demo_template')) { verify_demo_template($template); } ($hook = vBulletinHook::fetch_hook('template_compile')) ? eval($hook) : false; return $template; }
/** * Compile a template. * * @param string $template_un The uncompiled content of a template. */ public function compile($template, $forcesaveonerror) { // @todo // Incorrect hack warning!!! // The legacy code in class_template_parser.php needs this to be set // but it apparrently does not actually need to be an instance of the // legacy db class for purposes of compiling a template. if (empty($GLOBALS['vbulletin']->db)) { $GLOBALS['vbulletin']->db = false; } require_once DIR . '/includes/class_template_parser.php'; require_once DIR . '/includes/adminfunctions_template.php'; // Required for check_template_errors() $parser = new vB_TemplateParser($template); try { $parser->validate($errors); } catch (vB_Exception_TemplateFatalError $e) { throw new vB_Exception_Api($e->getMessage()); } $template = $parser->compile(); // This is a comment from vB4 moved here. Need to figure out what replace_template_variables // is supposed to do. // TODO: Reimplement these - if done, $session[], $bbuserinfo[], $vboptions // will parse in the template without using {vb:raw, which isn't what we // necessarily want to happen /* if (!function_exists('replace_template_variables')) { require_once(DIR . '/includes/functions_misc.php'); } $template = replace_template_variables($template, false); */ if (function_exists('verify_demo_template')) { verify_demo_template($template); } // Legacy Hook 'template_compile' Removed // if (!$forcesaveonerror and !empty($errors)) { throw new vB_Exception_Api('template_compile_error', array($errors)); } //extra set of error checking. This can be skipped in many situations. if (!$forcesaveonerror) { $errors = check_template_errors($template); if (!empty($errors)) { $vb5_config =& vB::getConfig(); if (!is_array($errors) and $vb5_config['Misc']['debug']) { // show compiled template code with line numbers to debug the problem $errors .= '<h4>Compiled Template Code:</h4><div style="height:200px; overflow:auto; border:1px solid silver; font-style:normal; font-family:Courier New;"><ol><li>' . implode('</li><li>', explode("\n", htmlspecialchars($template))) . '</li></ol></div>'; } throw new vB_Exception_Api('template_eval_error', array($errors)); } } return $template; }