function EditTheme() { global $context, $settings, $scripturl, $boarddir, $smcFunc; if (isset($_REQUEST['preview'])) { // !!! Should this be removed? die; } isAllowedTo('admin_forum'); loadTemplate('Themes'); $_GET['th'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) @$_GET['id']; if (empty($_GET['th'])) { $request = $smcFunc['db_query']('', ' SELECT id_theme, variable, value FROM {db_prefix}themes WHERE variable IN ({string:name}, {string:theme_dir}, {string:theme_templates}, {string:theme_layers}) AND id_member = {int:no_member}', array('name' => 'name', 'theme_dir' => 'theme_dir', 'theme_templates' => 'theme_templates', 'theme_layers' => 'theme_layers', 'no_member' => 0)); $context['themes'] = array(); while ($row = $smcFunc['db_fetch_assoc']($request)) { if (!isset($context['themes'][$row['id_theme']])) { $context['themes'][$row['id_theme']] = array('id' => $row['id_theme'], 'num_default_options' => 0, 'num_members' => 0); } $context['themes'][$row['id_theme']][$row['variable']] = $row['value']; } $smcFunc['db_free_result']($request); foreach ($context['themes'] as $key => $theme) { // There has to be a Settings template! if (!file_exists($theme['theme_dir'] . '/index.template.php') && !file_exists($theme['theme_dir'] . '/css/index.css')) { unset($context['themes'][$key]); } else { if (!isset($theme['theme_templates'])) { $templates = array('index'); } else { $templates = explode(',', $theme['theme_templates']); } foreach ($templates as $template) { if (file_exists($theme['theme_dir'] . '/' . $template . '.template.php')) { // Fetch the header... a good 256 bytes should be more than enough. $fp = fopen($theme['theme_dir'] . '/' . $template . '.template.php', 'rb'); $header = fread($fp, 256); fclose($fp); // Can we find a version comment, at all? if (preg_match('~(?://|/\\*)\\s*Version:\\s+(.+?);\\s*' . $template . '(?:[\\s]{2}|\\*/)~i', $header, $match) == 1) { $ver = $match[1]; if (!isset($context['themes'][$key]['version']) || $context['themes'][$key]['version'] > $ver) { $context['themes'][$key]['version'] = $ver; } } } } $context['themes'][$key]['can_edit_style'] = file_exists($theme['theme_dir'] . '/css/index.css'); } } $context['sub_template'] = 'edit_list'; return 'no_themes'; } $context['session_error'] = false; // Get the directory of the theme we are editing. $request = $smcFunc['db_query']('', ' SELECT value, id_theme FROM {db_prefix}themes WHERE variable = {string:theme_dir} AND id_theme = {int:current_theme} LIMIT 1', array('current_theme' => $_GET['th'], 'theme_dir' => 'theme_dir')); list($theme_dir, $context['theme_id']) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); if (!isset($_REQUEST['filename'])) { if (isset($_GET['directory'])) { if (substr($_GET['directory'], 0, 1) == '.') { $_GET['directory'] = ''; } else { $_GET['directory'] = preg_replace(array('~^[\\./\\:\\0\\n\\r]+~', '~[\\\\]~', '~/[\\./]+~'), array('', '/', '/'), $_GET['directory']); $temp = realpath($theme_dir . '/' . $_GET['directory']); if (empty($temp) || substr($temp, 0, strlen(realpath($theme_dir))) != realpath($theme_dir)) { $_GET['directory'] = ''; } } } if (isset($_GET['directory']) && $_GET['directory'] != '') { $context['theme_files'] = get_file_listing($theme_dir . '/' . $_GET['directory'], $_GET['directory'] . '/'); $temp = dirname($_GET['directory']); array_unshift($context['theme_files'], array('filename' => $temp == '.' || $temp == '' ? '/ (..)' : $temp . ' (..)', 'is_writable' => is_writable($theme_dir . '/' . $temp), 'is_directory' => true, 'is_template' => false, 'is_image' => false, 'is_editable' => false, 'href' => $scripturl . '?action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;directory=' . $temp, 'size' => '')); } else { $context['theme_files'] = get_file_listing($theme_dir, ''); } $context['sub_template'] = 'edit_browse'; return; } else { if (substr($_REQUEST['filename'], 0, 1) == '.') { $_REQUEST['filename'] = ''; } else { $_REQUEST['filename'] = preg_replace(array('~^[\\./\\:\\0\\n\\r]+~', '~[\\\\]~', '~/[\\./]+~'), array('', '/', '/'), $_REQUEST['filename']); $temp = realpath($theme_dir . '/' . $_REQUEST['filename']); if (empty($temp) || substr($temp, 0, strlen(realpath($theme_dir))) != realpath($theme_dir)) { $_REQUEST['filename'] = ''; } } if (empty($_REQUEST['filename'])) { fatal_lang_error('theme_edit_missing', false); } } if (isset($_POST['submit'])) { if (checkSession('post', '', false) == '') { if (is_array($_POST['entire_file'])) { $_POST['entire_file'] = implode("\n", $_POST['entire_file']); } $_POST['entire_file'] = rtrim(strtr($_POST['entire_file'], array("\r" => '', ' ' => "\t"))); // Check for a parse error! if (substr($_REQUEST['filename'], -13) == '.template.php' && is_writable($theme_dir) && @ini_get('display_errors')) { $request = $smcFunc['db_query']('', ' SELECT value FROM {db_prefix}themes WHERE variable = {string:theme_url} AND id_theme = {int:current_theme} LIMIT 1', array('current_theme' => $_GET['th'], 'theme_url' => 'theme_url')); list($theme_url) = $smcFunc['db_fetch_row']($request); $smcFunc['db_free_result']($request); $fp = fopen($theme_dir . '/tmp_' . session_id() . '.php', 'w'); fwrite($fp, $_POST['entire_file']); fclose($fp); // !!! Use fetch_web_data()? $error = @file_get_contents($theme_url . '/tmp_' . session_id() . '.php'); if (preg_match('~ <b>(\\d+)</b><br( /)?' . '>$~i', $error) != 0) { $error_file = $theme_dir . '/tmp_' . session_id() . '.php'; } else { unlink($theme_dir . '/tmp_' . session_id() . '.php'); } } if (!isset($error_file)) { $fp = fopen($theme_dir . '/' . $_REQUEST['filename'], 'w'); fwrite($fp, $_POST['entire_file']); fclose($fp); redirectexit('action=admin;area=theme;th=' . $_GET['th'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=edit;directory=' . dirname($_REQUEST['filename'])); } } else { loadLanguage('Errors'); $context['session_error'] = true; $context['sub_template'] = 'edit_file'; // Recycle the submitted data. $context['entire_file'] = htmlspecialchars($_POST['entire_file']); // You were able to submit it, so it's reasonable to assume you are allowed to save. $context['allow_save'] = true; return; } } $context['allow_save'] = is_writable($theme_dir . '/' . $_REQUEST['filename']); $context['allow_save_filename'] = strtr($theme_dir . '/' . $_REQUEST['filename'], array($boarddir => '...')); $context['edit_filename'] = htmlspecialchars($_REQUEST['filename']); if (substr($_REQUEST['filename'], -4) == '.css') { $context['sub_template'] = 'edit_style'; $context['entire_file'] = htmlspecialchars(strtr(file_get_contents($theme_dir . '/' . $_REQUEST['filename']), array("\t" => ' '))); } elseif (substr($_REQUEST['filename'], -13) == '.template.php') { $context['sub_template'] = 'edit_template'; if (!isset($error_file)) { $file_data = file($theme_dir . '/' . $_REQUEST['filename']); } else { if (preg_match('~(<b>.+?</b>:.+?<b>).+?(</b>.+?<b>\\d+</b>)<br( /)?' . '>$~i', $error, $match) != 0) { $context['parse_error'] = $match[1] . $_REQUEST['filename'] . $match[2]; } $file_data = file($error_file); unlink($error_file); } $j = 0; $context['file_parts'] = array(array('lines' => 0, 'line' => 1, 'data' => '')); for ($i = 0, $n = count($file_data); $i < $n; $i++) { if (isset($file_data[$i + 1]) && substr($file_data[$i + 1], 0, 9) == 'function ') { // Try to format the functions a little nicer... $context['file_parts'][$j]['data'] = trim($context['file_parts'][$j]['data']) . "\n"; if (empty($context['file_parts'][$j]['lines'])) { unset($context['file_parts'][$j]); } $context['file_parts'][++$j] = array('lines' => 0, 'line' => $i + 1, 'data' => ''); } $context['file_parts'][$j]['lines']++; $context['file_parts'][$j]['data'] .= htmlspecialchars(strtr($file_data[$i], array("\t" => ' '))); } $context['entire_file'] = htmlspecialchars(strtr(implode('', $file_data), array("\t" => ' '))); } else { $context['sub_template'] = 'edit_file'; $context['entire_file'] = htmlspecialchars(strtr(file_get_contents($theme_dir . '/' . $_REQUEST['filename']), array("\t" => ' '))); } }
/** * Handles user browsing in theme directories. * * What it does: * - The display will allow to choose a file for editing, * if it is writable. * - accessed with ?action=admin;area=theme;sa=browse */ public function action_browse() { global $context, $scripturl; loadTemplate('ManageThemes'); // We'll work hard with them themes! require_once SUBSDIR . '/Themes.subs.php'; $selectedTheme = isset($_GET['th']) ? (int) $_GET['th'] : (isset($_GET['id']) ? (int) $_GET['id'] : 0); if (empty($selectedTheme)) { redirectexit('action=admin;area=theme;sa=themelist'); } // Get first the directory of the theme we are editing. $context['theme_id'] = isset($_GET['th']) ? (int) $_GET['th'] : (isset($_GET['id']) ? (int) $_GET['id'] : 0); $theme_dir = themeDirectory($context['theme_id']); // Eh? not trying to sneak a peek outside the theme directory are we if (!file_exists($theme_dir . '/index.template.php') && !file_exists($theme_dir . '/css/index.css')) { fatal_lang_error('theme_edit_missing', false); } // Now, where exactly are you? if (isset($_GET['directory'])) { if (substr($_GET['directory'], 0, 1) === '.') { $_GET['directory'] = ''; } else { $_GET['directory'] = preg_replace(array('~^[\\./\\:\\0\\n\\r]+~', '~[\\\\]~', '~/[\\./]+~'), array('', '/', '/'), $_GET['directory']); $temp = realpath($theme_dir . '/' . $_GET['directory']); if (empty($temp) || substr($temp, 0, strlen(realpath($theme_dir))) != realpath($theme_dir)) { $_GET['directory'] = ''; } } } if (isset($_GET['directory']) && $_GET['directory'] != '') { $context['theme_files'] = get_file_listing($theme_dir . '/' . $_GET['directory'], $_GET['directory'] . '/'); $temp = dirname($_GET['directory']); array_unshift($context['theme_files'], array('filename' => $temp == '.' || $temp == '' ? '/ (..)' : $temp . ' (..)', 'is_writable' => is_writable($theme_dir . '/' . $temp), 'is_directory' => true, 'is_template' => false, 'is_image' => false, 'is_editable' => false, 'href' => $scripturl . '?action=admin;area=theme;th=' . $context['theme_id'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';sa=browse;directory=' . $temp, 'size' => '')); } else { $context['theme_files'] = get_file_listing($theme_dir, ''); } // finally, load the sub-template $context['sub_template'] = 'browse'; }