Beispiel #1
0
function copytree($source, $destination)
{
    global $package_ftp;
    if (!file_exists($destination) || !is_writable($destination)) {
        mktree($destination, 0755);
    }
    if (!is_writable($destination)) {
        mktree($destination, 0777);
    }
    $current_dir = opendir($source);
    if ($current_dir == false) {
        return;
    }
    while ($entryname = readdir($current_dir)) {
        if (in_array($entryname, array('.', '..'))) {
            continue;
        }
        if (isset($package_ftp)) {
            $ftp_file = strtr($destination . '/' . $entryname, array($_SESSION['pack_ftp']['root'] => ''));
        }
        if (is_file($source . '/' . $entryname)) {
            if (isset($package_ftp) && !file_exists($destination . '/' . $entryname)) {
                $package_ftp->create_file($ftp_file);
            } elseif (!file_exists($destination . '/' . $entryname)) {
                @touch($destination . '/' . $entryname);
            }
        }
        package_chmod($destination . '/' . $entryname);
        if (is_dir($source . '/' . $entryname)) {
            copytree($source . '/' . $entryname, $destination . '/' . $entryname);
        } elseif (file_exists($destination . '/' . $entryname)) {
            package_put_contents($destination . '/' . $entryname, package_get_contents($source . '/' . $entryname));
        } else {
            copy($source . '/' . $entryname, $destination . '/' . $entryname);
        }
    }
    closedir($current_dir);
}
Beispiel #2
0
function ThemeInstall()
{
    global $sourcedir, $boarddir, $boardurl, $txt, $context, $settings, $modSettings, $smcFunc;
    checkSession('request');
    isAllowedTo('admin_forum');
    checkSession('request');
    require_once $sourcedir . '/Subs-Package.php';
    loadTemplate('Themes');
    if (isset($_GET['theme_id'])) {
        $result = $smcFunc['db_query']('', '
			SELECT value
			FROM {db_prefix}themes
			WHERE id_theme = {int:current_theme}
				AND id_member = {int:no_member}
				AND variable = {string:name}
			LIMIT 1', array('current_theme' => (int) $_GET['theme_id'], 'no_member' => 0, 'name' => 'name'));
        list($theme_name) = $smcFunc['db_fetch_row']($result);
        $smcFunc['db_free_result']($result);
        $context['sub_template'] = 'installed';
        $context['page_title'] = $txt['theme_installed'];
        $context['installed_theme'] = array('id' => (int) $_GET['theme_id'], 'name' => $theme_name);
        return;
    }
    if (!empty($_FILES['theme_gz']) && (!isset($_FILES['theme_gz']['error']) || $_FILES['theme_gz']['error'] != 4) || !empty($_REQUEST['theme_gz'])) {
        $method = 'upload';
    } elseif (isset($_REQUEST['theme_dir']) && rtrim(realpath($_REQUEST['theme_dir']), '/\\') != realpath($boarddir . '/Themes') && file_exists($_REQUEST['theme_dir'])) {
        $method = 'path';
    } else {
        $method = 'copy';
    }
    if (!empty($_REQUEST['copy']) && $method == 'copy') {
        // Hopefully the themes directory is writable, or we might have a problem.
        if (!is_writable($boarddir . '/Themes')) {
            fatal_lang_error('theme_install_write_error', 'critical');
        }
        $theme_dir = $boarddir . '/Themes/' . preg_replace('~[^A-Za-z0-9_\\- ]~', '', $_REQUEST['copy']);
        umask(0);
        mkdir($theme_dir, 0777);
        @set_time_limit(600);
        if (function_exists('apache_reset_timeout')) {
            @apache_reset_timeout();
        }
        // Create subdirectories for css and javascript files.
        mkdir($theme_dir . '/css', 0777);
        mkdir($theme_dir . '/scripts', 0777);
        // Copy over the default non-theme files.
        $to_copy = array('/index.php', '/index.template.php', '/css/index.css', '/css/rtl.css', '/scripts/theme.js');
        foreach ($to_copy as $file) {
            copy($settings['default_theme_dir'] . $file, $theme_dir . $file);
            @chmod($theme_dir . $file, 0777);
        }
        // And now the entire images directory!
        copytree($settings['default_theme_dir'] . '/images', $theme_dir . '/images');
        package_flush_cache();
        $theme_name = $_REQUEST['copy'];
        $images_url = $boardurl . '/Themes/' . basename($theme_dir) . '/images';
        $theme_dir = realpath($theme_dir);
        // Lets get some data for the new theme.
        $request = $smcFunc['db_query']('', '
			SELECT variable, value
			FROM {db_prefix}themes
			WHERE variable IN ({string:theme_templates}, {string:theme_layers})
				AND id_member = {int:no_member}
				AND id_theme = {int:default_theme}', array('no_member' => 0, 'default_theme' => 1, 'theme_templates' => 'theme_templates', 'theme_layers' => 'theme_layers'));
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            if ($row['variable'] == 'theme_templates') {
                $theme_templates = $row['value'];
            } elseif ($row['variable'] == 'theme_layers') {
                $theme_layers = $row['value'];
            } else {
                continue;
            }
        }
        $smcFunc['db_free_result']($request);
        // Lets add a theme_info.xml to this theme.
        $xml_info = '<' . '?xml version="1.0"?' . '>
<theme-info xmlns="http://www.simplemachines.org/xml/theme-info" xmlns:smf="http://www.simplemachines.org/">
	<!-- For the id, always use something unique - put your name, a colon, and then the package name. -->
	<id>smf:' . $smcFunc['strtolower'](str_replace(array(' '), '_', $_REQUEST['copy'])) . '</id>
	<version>' . $modSettings['smfVersion'] . '</version>
	<!-- Theme name, used purely for aesthetics. -->
	<name>' . $_REQUEST['copy'] . '</name>
	<!-- Author: your email address or contact information. The name attribute is optional. -->
	<author name="Simple Machines">info@simplemachines.org</author>
	<!-- Website... where to get updates and more information. -->
	<website>http://www.simplemachines.org/</website>
	<!-- Template layers to use, defaults to "html,body". -->
	<layers>' . (empty($theme_layers) ? 'html,body' : $theme_layers) . '</layers>
	<!-- Templates to load on startup. Default is "index". -->
	<templates>' . (empty($theme_templates) ? 'index' : $theme_templates) . '</templates>
	<!-- Base this theme off another? Default is blank, or no. It could be "default". -->
	<based-on></based-on>
</theme-info>';
        // Now write it.
        $fp = @fopen($theme_dir . '/theme_info.xml', 'w+');
        if ($fp) {
            fwrite($fp, $xml_info);
            fclose($fp);
        }
    } elseif (isset($_REQUEST['theme_dir']) && $method == 'path') {
        if (!is_dir($_REQUEST['theme_dir']) || !file_exists($_REQUEST['theme_dir'] . '/theme_info.xml')) {
            fatal_lang_error('theme_install_error', false);
        }
        $theme_name = basename($_REQUEST['theme_dir']);
        $theme_dir = $_REQUEST['theme_dir'];
    } elseif ($method = 'upload') {
        // Hopefully the themes directory is writable, or we might have a problem.
        if (!is_writable($boarddir . '/Themes')) {
            fatal_lang_error('theme_install_write_error', 'critical');
        }
        require_once $sourcedir . '/Subs-Package.php';
        // Set the default settings...
        $theme_name = strtok(basename(isset($_FILES['theme_gz']) ? $_FILES['theme_gz']['name'] : $_REQUEST['theme_gz']), '.');
        $theme_name = preg_replace(array('/\\s/', '/\\.[\\.]+/', '/[^\\w_\\.\\-]/'), array('_', '.', ''), $theme_name);
        $theme_dir = $boarddir . '/Themes/' . $theme_name;
        if (isset($_FILES['theme_gz']) && is_uploaded_file($_FILES['theme_gz']['tmp_name']) && (@ini_get('open_basedir') != '' || file_exists($_FILES['theme_gz']['tmp_name']))) {
            $extracted = read_tgz_file($_FILES['theme_gz']['tmp_name'], $boarddir . '/Themes/' . $theme_name, false, true);
        } elseif (isset($_REQUEST['theme_gz'])) {
            // Check that the theme is from simplemachines.org, for now... maybe add mirroring later.
            if (preg_match('~^http://[\\w_\\-]+\\.simplemachines\\.org/~', $_REQUEST['theme_gz']) == 0 || strpos($_REQUEST['theme_gz'], 'dlattach') !== false) {
                fatal_lang_error('not_on_simplemachines');
            }
            $extracted = read_tgz_file($_REQUEST['theme_gz'], $boarddir . '/Themes/' . $theme_name, false, true);
        } else {
            redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']);
        }
    }
    // Something go wrong?
    if ($theme_dir != '' && basename($theme_dir) != 'Themes') {
        // Defaults.
        $install_info = array('theme_url' => $boardurl . '/Themes/' . basename($theme_dir), 'images_url' => isset($images_url) ? $images_url : $boardurl . '/Themes/' . basename($theme_dir) . '/images', 'theme_dir' => $theme_dir, 'name' => $theme_name);
        if (file_exists($theme_dir . '/theme_info.xml')) {
            $theme_info = file_get_contents($theme_dir . '/theme_info.xml');
            $xml_elements = array('name' => 'name', 'theme_layers' => 'layers', 'theme_templates' => 'templates', 'based_on' => 'based-on');
            foreach ($xml_elements as $var => $name) {
                if (preg_match('~<' . $name . '>(?:<!\\[CDATA\\[)?(.+?)(?:\\]\\]>)?</' . $name . '>~', $theme_info, $match) == 1) {
                    $install_info[$var] = $match[1];
                }
            }
            if (preg_match('~<images>(?:<!\\[CDATA\\[)?(.+?)(?:\\]\\]>)?</images>~', $theme_info, $match) == 1) {
                $install_info['images_url'] = $install_info['theme_url'] . '/' . $match[1];
                $explicit_images = true;
            }
            if (preg_match('~<extra>(?:<!\\[CDATA\\[)?(.+?)(?:\\]\\]>)?</extra>~', $theme_info, $match) == 1) {
                $install_info += unserialize($match[1]);
            }
        }
        if (isset($install_info['based_on'])) {
            if ($install_info['based_on'] == 'default') {
                $install_info['theme_url'] = $settings['default_theme_url'];
                $install_info['images_url'] = $settings['default_images_url'];
            } elseif ($install_info['based_on'] != '') {
                $install_info['based_on'] = preg_replace('~[^A-Za-z0-9\\-_ ]~', '', $install_info['based_on']);
                $request = $smcFunc['db_query']('', '
					SELECT th.value AS base_theme_dir, th2.value AS base_theme_url' . (!empty($explicit_images) ? '' : ', th3.value AS images_url') . '
					FROM {db_prefix}themes AS th
						INNER JOIN {db_prefix}themes AS th2 ON (th2.id_theme = th.id_theme
							AND th2.id_member = {int:no_member}
							AND th2.variable = {string:theme_url})' . (!empty($explicit_images) ? '' : '
						INNER JOIN {db_prefix}themes AS th3 ON (th3.id_theme = th.id_theme
							AND th3.id_member = {int:no_member}
							AND th3.variable = {string:images_url})') . '
					WHERE th.id_member = {int:no_member}
						AND (th.value LIKE {string:based_on} OR th.value LIKE {string:based_on_path})
						AND th.variable = {string:theme_dir}
					LIMIT 1', array('no_member' => 0, 'theme_url' => 'theme_url', 'images_url' => 'images_url', 'theme_dir' => 'theme_dir', 'based_on' => '%/' . $install_info['based_on'], 'based_on_path' => '%' . "\\" . $install_info['based_on']));
                $temp = $smcFunc['db_fetch_assoc']($request);
                $smcFunc['db_free_result']($request);
                // !!! An error otherwise?
                if (is_array($temp)) {
                    $install_info = $temp + $install_info;
                    if (empty($explicit_images) && !empty($install_info['base_theme_url'])) {
                        $install_info['theme_url'] = $install_info['base_theme_url'];
                    }
                }
            }
            unset($install_info['based_on']);
        }
        // Find the newest id_theme.
        $result = $smcFunc['db_query']('', '
			SELECT MAX(id_theme)
			FROM {db_prefix}themes', array());
        list($id_theme) = $smcFunc['db_fetch_row']($result);
        $smcFunc['db_free_result']($result);
        // This will be theme number...
        $id_theme++;
        $inserts = array();
        foreach ($install_info as $var => $val) {
            $inserts[] = array($id_theme, $var, $val);
        }
        if (!empty($inserts)) {
            $smcFunc['db_insert']('insert', '{db_prefix}themes', array('id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), $inserts, array('id_theme', 'variable'));
        }
        updateSettings(array('knownThemes' => strtr($modSettings['knownThemes'] . ',' . $id_theme, array(',,' => ','))));
    }
    redirectexit('action=admin;area=theme;sa=install;theme_id=' . $id_theme . ';' . $context['session_var'] . '=' . $context['session_id']);
}
 /**
  * List operations
  */
 public function action_showoperations()
 {
     global $context, $txt;
     // Can't be in here buddy.
     isAllowedTo('admin_forum');
     // We need to know the operation key for the search and replace, mod file looking at, is it a board mod?
     if (!isset($_REQUEST['operation_key'], $_REQUEST['filename']) && !is_numeric($_REQUEST['operation_key'])) {
         fatal_lang_error('operation_invalid', 'general');
     }
     // Load the required file.
     require_once SUBSDIR . '/Package.subs.php';
     require_once SUBSDIR . '/Themes.subs.php';
     // Uninstalling the mod?
     $reverse = isset($_REQUEST['reverse']) ? true : false;
     // Get the base name.
     $context['filename'] = preg_replace('~[\\.]+~', '.', $_REQUEST['package']);
     // We need to extract this again.
     if (is_file(BOARDDIR . '/packages/' . $context['filename'])) {
         $context['extracted_files'] = read_tgz_file(BOARDDIR . '/packages/' . $context['filename'], BOARDDIR . '/packages/temp');
         if ($context['extracted_files'] && !file_exists(BOARDDIR . '/packages/temp/package-info.xml')) {
             foreach ($context['extracted_files'] as $file) {
                 if (basename($file['filename']) == 'package-info.xml') {
                     $context['base_path'] = dirname($file['filename']) . '/';
                     break;
                 }
             }
         }
         if (!isset($context['base_path'])) {
             $context['base_path'] = '';
         }
     } elseif (is_dir(BOARDDIR . '/packages/' . $context['filename'])) {
         copytree(BOARDDIR . '/packages/' . $context['filename'], BOARDDIR . '/packages/temp');
         $context['extracted_files'] = listtree(BOARDDIR . '/packages/temp');
         $context['base_path'] = '';
     }
     // Load up any custom themes we may want to install into...
     $theme_paths = getThemesPathbyID();
     // For uninstall operations we only consider the themes in which the package is installed.
     if (isset($_REQUEST['reverse']) && !empty($_REQUEST['install_id'])) {
         $install_id = (int) $_REQUEST['install_id'];
         if ($install_id > 0) {
             $old_themes = loadThemesAffected($install_id);
             foreach ($theme_paths as $id => $data) {
                 if ($id != 1 && !in_array($id, $old_themes)) {
                     unset($theme_paths[$id]);
                 }
             }
         }
     }
     // Boardmod?
     if (isset($_REQUEST['boardmod'])) {
         $mod_actions = parseBoardMod(@file_get_contents(BOARDDIR . '/packages/temp/' . $context['base_path'] . $_REQUEST['filename']), true, $reverse, $theme_paths);
     } else {
         $mod_actions = parseModification(@file_get_contents(BOARDDIR . '/packages/temp/' . $context['base_path'] . $_REQUEST['filename']), true, $reverse, $theme_paths);
     }
     // Ok lets get the content of the file.
     $context['operations'] = array('search' => strtr(htmlspecialchars($mod_actions[$_REQUEST['operation_key']]['search_original'], ENT_COMPAT, 'UTF-8'), array('[' => '&#91;', ']' => '&#93;')), 'replace' => strtr(htmlspecialchars($mod_actions[$_REQUEST['operation_key']]['replace_original'], ENT_COMPAT, 'UTF-8'), array('[' => '&#91;', ']' => '&#93;')), 'position' => $mod_actions[$_REQUEST['operation_key']]['position']);
     // Let's do some formatting...
     $operation_text = $context['operations']['position'] == 'replace' ? 'operation_replace' : ($context['operations']['position'] == 'before' ? 'operation_after' : 'operation_before');
     $context['operations']['search'] = parse_bbc('[code=' . $txt['operation_find'] . ']' . ($context['operations']['position'] == 'end' ? '?&gt;' : $context['operations']['search']) . '[/code]');
     $context['operations']['replace'] = parse_bbc('[code=' . $txt[$operation_text] . ']' . $context['operations']['replace'] . '[/code]');
     // No layers
     Template_Layers::getInstance()->removeAll();
     $context['sub_template'] = 'view_operations';
 }
Beispiel #4
0
function ViewOperations()
{
    global $context, $txt, $boarddir, $sourcedir, $modSettings;
    // Can't be in here buddy.
    isAllowedTo('admin_forum');
    // We need to know the operation key for the search and replace, mod file looking at, is it a board mod?
    if (!isset($_REQUEST['operation_key'], $_REQUEST['filename']) && !is_numeric($_REQUEST['operation_key'])) {
        fatal_lang_error('operation_invalid', 'general');
    }
    // Load the required file.
    require_once $sourcedir . '/lib/Subs-Package.php';
    // Uninstalling the mod?
    $reverse = isset($_REQUEST['reverse']) ? true : false;
    // Get the base name.
    $context['filename'] = preg_replace('~[\\.]+~', '.', $_REQUEST['package']);
    // We need to extract this again.
    if (is_file($boarddir . '/Packages/' . $context['filename'])) {
        $context['extracted_files'] = read_tgz_file($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp');
        if ($context['extracted_files'] && !file_exists($boarddir . '/Packages/temp/package-info.xml')) {
            foreach ($context['extracted_files'] as $file) {
                if (basename($file['filename']) == 'package-info.xml') {
                    $context['base_path'] = dirname($file['filename']) . '/';
                    break;
                }
            }
        }
        if (!isset($context['base_path'])) {
            $context['base_path'] = '';
        }
    } elseif (is_dir($boarddir . '/Packages/' . $context['filename'])) {
        copytree($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp');
        $context['extracted_files'] = listtree($boarddir . '/Packages/temp');
        $context['base_path'] = '';
    }
    // Load up any custom themes we may want to install into...
    $request = smf_db_query('
		SELECT id_theme, variable, value
		FROM {db_prefix}themes
		WHERE (id_theme = {int:default_theme} OR id_theme IN ({array_int:known_theme_list}))
			AND variable IN ({string:name}, {string:theme_dir})', array('known_theme_list' => explode(',', $modSettings['knownThemes']), 'default_theme' => 1, 'name' => 'name', 'theme_dir' => 'theme_dir'));
    $theme_paths = array();
    while ($row = mysql_fetch_assoc($request)) {
        $theme_paths[$row['id_theme']][$row['variable']] = $row['value'];
    }
    mysql_free_result($request);
    // Boardmod?
    if (isset($_REQUEST['boardmod'])) {
        $mod_actions = parseBoardMod(@file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $_REQUEST['filename']), true, $reverse, $theme_paths);
    } else {
        $mod_actions = parseModification(@file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $_REQUEST['filename']), true, $reverse, $theme_paths);
    }
    // Ok lets get the content of the file.
    $context['operations'] = array('search' => strtr(htmlspecialchars($mod_actions[$_REQUEST['operation_key']]['search_original']), array('[' => '&#91;', ']' => '&#93;')), 'replace' => strtr(htmlspecialchars($mod_actions[$_REQUEST['operation_key']]['replace_original']), array('[' => '&#91;', ']' => '&#93;')), 'position' => $mod_actions[$_REQUEST['operation_key']]['position']);
    // Let's do some formatting...
    $operation_text = $context['operations']['position'] == 'replace' ? 'operation_replace' : ($context['operations']['position'] == 'before' ? 'operation_after' : 'operation_before');
    $context['operations']['search'] = parse_bbc('[code=' . $txt['operation_find'] . ']' . ($context['operations']['position'] == 'end' ? '?&gt;' : $context['operations']['search']) . '[/code]');
    $context['operations']['replace'] = parse_bbc('[code=' . $txt[$operation_text] . ']' . $context['operations']['replace'] . '[/code]');
    // No layers
    $context['template_layers'] = array();
    $context['sub_template'] = 'view_operations';
}
Beispiel #5
0
function PackageInstall()
{
    global $boarddir, $txt, $context, $boardurl, $scripturl, $sourcedir, $modSettings;
    checkSession('post');
    // If there's no file, what are we installing?
    if (empty($_REQUEST['package']) || preg_match('~[^\\w0-9.\\-_]~', $_REQUEST['package']) === 1 || strpos($_REQUEST['package'], '..') !== false) {
        redirectexit('action=packages');
    }
    $context['filename'] = $_REQUEST['package'];
    require_once $sourcedir . '/Subs-Package.php';
    // !!! TODO: Perhaps do it in steps, if necessary?
    $context['uninstalling'] = $_REQUEST['sa'] == 'uninstall2';
    // Set up the linktree for other.
    $context['linktree'][] = array('url' => $scripturl . '?action=packages;sa=browse', 'name' => $context['uninstalling'] ? $txt['smf198b'] : $txt['package37']);
    $context['page_title'] .= ' - ' . ($context['uninstalling'] ? $txt['smf198b'] : $txt['package37']);
    $context['sub_template'] = 'extract_package';
    if (!file_exists($boarddir . '/Packages/' . $context['filename'])) {
        fatal_lang_error('package_no_file', false);
    }
    // Load up the package FTP information?
    if (isset($_SESSION['pack_ftp'])) {
        packageRequireFTP($scripturl . '?action=packages;sa=' . $_REQUEST['sa'] . ';package=' . $_REQUEST['package']);
    }
    // Make sure temp directory exists and is empty!
    if (file_exists($boarddir . '/Packages/temp')) {
        deltree($boarddir . '/Packages/temp', false);
    } else {
        mktree($boarddir . '/Packages/temp', 0777);
    }
    // Let the unpacker do the work.
    if (is_file($boarddir . '/Packages/' . $context['filename'])) {
        $context['extracted_files'] = read_tgz_file($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp');
        if (!file_exists($boarddir . '/Packages/temp/package-info.xml')) {
            foreach ($context['extracted_files'] as $file) {
                if (basename($file['filename']) == 'package-info.xml') {
                    $context['base_path'] = dirname($file['filename']) . '/';
                    break;
                }
            }
        }
        if (!isset($context['base_path'])) {
            $context['base_path'] = '';
        }
    } elseif (is_dir($boarddir . '/Packages/' . $context['filename'])) {
        copytree($boarddir . '/Packages/' . $context['filename'], $boarddir . '/Packages/temp');
        $context['extracted_files'] = listtree($boarddir . '/Packages/temp');
        $context['base_path'] = '';
    } else {
        fatal_lang_error(1, false);
    }
    // Get the package info...
    $packageInfo = getPackageInfo($context['filename']);
    $packageInfo['filename'] = $context['filename'];
    // Set the type of extraction...
    $context['extract_type'] = isset($packageInfo['type']) ? $packageInfo['type'] : 'modification';
    // Create a backup file to roll back to! (but if they do this more than once, don't run it a zillion times.)
    if (!empty($modSettings['package_make_backups']) && (!isset($_SESSION['last_backup_for']) || $_SESSION['last_backup_for'] != $context['filename'] . ($context['uninstalling'] ? '$$' : '$'))) {
        $_SESSION['last_backup_for'] = $context['filename'] . ($context['uninstalling'] ? '$$' : '$');
        // !!! Internationalize this?
        package_create_backup(($context['uninstalling'] ? 'backup_' : 'before_') . strtok($context['filename'], '.'));
    }
    $instmods = loadInstalledPackages();
    // The mod isn't installed.... unless proven otherwise.
    $context['is_installed'] = false;
    foreach ($instmods as $installed_mod) {
        if ($installed_mod['id'] == $packageInfo['id']) {
            $old_version = $installed_mod['version'];
        }
    }
    // Wait, it's not installed yet!
    // !!! TODO: Replace with a better error message!
    if (!isset($old_version) && $context['uninstalling']) {
        deltree($boarddir . '/Packages/temp');
        fatal_error('Hacker?', false);
    } elseif ($context['uninstalling']) {
        $install_log = parsePackageInfo($packageInfo['xml'], false, 'uninstall');
        // Gadzooks!  There's no uninstaller at all!?
        if (empty($install_log)) {
            fatal_lang_error('package_uninstall_cannot', false);
        }
    } elseif (isset($old_version) && $old_version != $packageInfo['version']) {
        // Look for an upgrade...
        $install_log = parsePackageInfo($packageInfo['xml'], false, 'upgrade', $old_version);
        // There was no upgrade....
        if (empty($install_log)) {
            $context['is_installed'] = true;
        }
    } elseif (isset($old_version) && $old_version == $packageInfo['version']) {
        $context['is_installed'] = true;
    }
    if (!isset($old_version) || $context['is_installed']) {
        $install_log = parsePackageInfo($packageInfo['xml'], false, 'install');
    }
    $context['install_finished'] = false;
    // !!! TODO: Make a log of any errors that occurred and output them?
    if (!empty($install_log)) {
        foreach ($install_log as $action) {
            if ($action['type'] == 'modification' && !empty($action['filename'])) {
                if ($action['boardmod']) {
                    parseBoardMod(file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']), false, $action['reverse']);
                } else {
                    parseModification(file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']), false, $action['reverse']);
                }
            } elseif ($action['type'] == 'code' && !empty($action['filename'])) {
                // This is just here as reference for what is available.
                global $txt, $boarddir, $sourcedir, $modSettings, $context, $settings, $db_prefix, $forum_version;
                // Now include the file and be done with it ;).
                require $boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename'];
            } elseif ($action['type'] == 'redirect' && !empty($action['redirect_url'])) {
                $context['redirect_url'] = $action['redirect_url'];
                $context['redirect_text'] = file_get_contents($boarddir . '/Packages/temp/' . $context['base_path'] . $action['filename']);
                $context['redirect_timeout'] = $action['redirect_timeout'];
                // Parse out a couple of common urls.
                $urls = array('$boardurl' => $boardurl, '$scripturl' => $scripturl, '$session_id' => $context['session_id']);
                $context['redirect_url'] = strtr($context['redirect_url'], $urls);
            }
        }
        package_flush_cache();
        // Check if the mod has been installed.
        $seen = false;
        // Look through the list of installed mods...
        foreach ($instmods as $i => $installed_mod) {
            if ($installed_mod['id'] == $packageInfo['id']) {
                if ($context['uninstalling']) {
                    $instmods[$i] = array();
                } else {
                    $instmods[$i]['version'] = $packageInfo['version'];
                    $seen = true;
                }
                break;
            }
        }
        // Hasn't.... make it show as installed.
        if (!$seen && !$context['uninstalling']) {
            $instmods[] = $packageInfo;
        }
        saveInstalledPackages($instmods);
        $context['install_finished'] = true;
    }
    // Clean house... get rid of the evidence ;).
    if (file_exists($boarddir . '/Packages/temp')) {
        deltree($boarddir . '/Packages/temp');
    }
}
Beispiel #6
0
function CleanupMods()
{
    global $db_prefix, $modSettings, $upcontext, $boarddir, $sourcedir, $settings, $smcFunc, $command_line;
    // Sorry. Not supported for command line users.
    if ($command_line) {
        return true;
    }
    // Skipping first?
    if (!empty($_POST['skip'])) {
        unset($_POST['skip']);
        return true;
    }
    // If we get here withOUT SSI we need to redirect to ensure we get it!
    if (!isset($_GET['ssi']) || !function_exists('mktree')) {
        redirectLocation('&ssi=1');
    }
    $upcontext['sub_template'] = 'clean_mods';
    $upcontext['page_title'] = 'Cleanup Modifications';
    // This can be skipped.
    $upcontext['skip'] = true;
    // If we're on the second redirect continue...
    if (isset($_POST['cleandone2'])) {
        return true;
    }
    // Do we already know about some writable files?
    if (isset($_POST['writable_files'])) {
        $writable_files = unserialize(base64_decode($_POST['writable_files']));
        if (!makeFilesWritable($writable_files)) {
            // What have we left?
            $upcontext['writable_files'] = $writable_files;
            return false;
        }
    }
    // Load all theme paths....
    $request = $smcFunc['db_query']('', '
		SELECT id_theme, variable, value
		FROM {db_prefix}themes
		WHERE id_member = {int:id_member}
			AND variable IN ({string:theme_dir}, {string:images_url})', array('id_member' => 0, 'theme_dir' => 'theme_dir', 'images_url' => 'images_url', 'db_error_skip' => true));
    $theme_paths = array();
    while ($row = $smcFunc['db_fetch_assoc']($request)) {
        if ($row['id_theme'] == 1) {
            $settings['default_' . $row['variable']] = $row['value'];
        } elseif ($row['variable'] == 'theme_dir') {
            $theme_paths[$row['id_theme']][$row['variable']] = $row['value'];
        }
    }
    $smcFunc['db_free_result']($request);
    // Are there are mods installed that may need uninstalling?
    $request = $smcFunc['db_query']('', '
		SELECT id_install, filename, name, themes_installed, version
		FROM {db_prefix}log_packages
		WHERE install_state = {int:installed}
		ORDER BY time_installed DESC', array('installed' => 1, 'db_error_skip' => true));
    $upcontext['packages'] = array();
    while ($row = $smcFunc['db_fetch_assoc']($request)) {
        // Work out the status.
        if (!file_exists($boarddir . '/Packages/' . $row['filename'])) {
            $status = 'Missing';
            $status_color = 'red';
            $result = 'Removed';
        } else {
            $status = 'Installed';
            $status_color = 'green';
            $result = 'No Action Needed';
        }
        $upcontext['packages'][$row['id_install']] = array('id' => $row['id_install'], 'themes' => explode(',', $row['themes_installed']), 'name' => $row['name'], 'filename' => $row['filename'], 'missing_file' => file_exists($boarddir . '/Packages/' . $row['filename']) ? 0 : 1, 'files' => array(), 'file_count' => 0, 'status' => $status, 'result' => $result, 'color' => $status_color, 'version' => $row['version'], 'needs_removing' => false);
    }
    $smcFunc['db_free_result']($request);
    // Don't carry on if there are none.
    if (empty($upcontext['packages'])) {
        return true;
    }
    // Setup some basics.
    if (!empty($upcontext['user']['version'])) {
        $_SESSION['version_emulate'] = $upcontext['user']['version'];
    }
    // Before we get started, don't report notice errors.
    $oldErrorReporting = error_reporting(E_ALL ^ E_NOTICE);
    if (!mktree($boarddir . '/Packages/temp', 0755)) {
        deltree($boarddir . '/Packages/temp', false);
        if (!mktree($boarddir . '/Packages/temp', 0777)) {
            deltree($boarddir . '/Packages/temp', false);
            //!!! Error here - plus chmod!
        }
    }
    // Anything which reinstalled should not have its entry removed.
    $reinstall_worked = array();
    // We're gonna be doing some removin'
    $test = isset($_POST['cleandone']) ? false : true;
    foreach ($upcontext['packages'] as $id => $package) {
        // Can't do anything about this....
        if ($package['missing_file']) {
            continue;
        }
        // Not testing *and* this wasn't checked?
        if (!$test && (!isset($_POST['remove']) || !isset($_POST['remove'][$id]))) {
            continue;
        }
        // What are the themes this was installed into?
        $cur_theme_paths = array();
        foreach ($theme_paths as $tid => $data) {
            if ($tid != 1 && in_array($tid, $package['themes'])) {
                $cur_theme_paths[$tid] = $data;
            }
        }
        // Get the modifications data if applicable.
        $filename = $package['filename'];
        $packageInfo = getPackageInfo($filename);
        if (!is_array($packageInfo)) {
            continue;
        }
        $info = parsePackageInfo($packageInfo['xml'], $test, 'uninstall');
        // Also get the reinstall details...
        if (isset($_POST['remove'])) {
            $infoInstall = parsePackageInfo($packageInfo['xml'], true);
        }
        if (is_file($boarddir . '/Packages/' . $filename)) {
            read_tgz_file($boarddir . '/Packages/' . $filename, $boarddir . '/Packages/temp');
        } else {
            copytree($boarddir . '/Packages/' . $filename, $boarddir . '/Packages/temp');
        }
        // Work out how we uninstall...
        $files = array();
        foreach ($info as $change) {
            // Work out two things:
            // 1) Whether it's installed at the moment - and if so whether its fully installed, and:
            // 2) Whether it could be installed on the new version.
            if ($change['type'] == 'modification') {
                $contents = @file_get_contents($boarddir . '/Packages/temp/' . $upcontext['base_path'] . $change['filename']);
                if ($change['boardmod']) {
                    $results = parseBoardMod($contents, $test, $change['reverse'], $cur_theme_paths);
                } else {
                    $results = parseModification($contents, $test, $change['reverse'], $cur_theme_paths);
                }
                foreach ($results as $action) {
                    // Something we can remove? Probably means it existed!
                    if (($action['type'] == 'replace' || $action['type'] == 'append' || !empty($action['filename']) && $action['type'] == 'failure') && !in_array($action['filename'], $files)) {
                        $files[] = $action['filename'];
                    }
                    if ($action['type'] == 'failure') {
                        $upcontext['packages'][$id]['needs_removing'] = true;
                        $upcontext['packages'][$id]['status'] = 'Reinstall Required';
                        $upcontext['packages'][$id]['color'] = '#FD6435';
                    }
                }
            }
        }
        // Store this info for the template as appropriate.
        $upcontext['packages'][$id]['files'] = $files;
        $upcontext['packages'][$id]['file_count'] = count($files);
        // If we've done something save the changes!
        if (!$test) {
            package_flush_cache();
        }
        // Are we attempting to reinstall this thing?
        if (isset($_POST['remove']) && !$test && isset($infoInstall)) {
            // Need to extract again I'm afraid.
            if (is_file($boarddir . '/Packages/' . $filename)) {
                read_tgz_file($boarddir . '/Packages/' . $filename, $boarddir . '/Packages/temp');
            } else {
                copytree($boarddir . '/Packages/' . $filename, $boarddir . '/Packages/temp');
            }
            $errors = false;
            $upcontext['packages'][$id]['result'] = 'Removed';
            foreach ($infoInstall as $change) {
                if ($change['type'] == 'modification') {
                    $contents = @file_get_contents($boarddir . '/Packages/temp/' . $upcontext['base_path'] . $change['filename']);
                    if ($change['boardmod']) {
                        $results = parseBoardMod($contents, true, $change['reverse'], $cur_theme_paths);
                    } else {
                        $results = parseModification($contents, true, $change['reverse'], $cur_theme_paths);
                    }
                    // Are there any errors?
                    foreach ($results as $action) {
                        if ($action['type'] == 'failure') {
                            $errors = true;
                        }
                    }
                }
            }
            if (!$errors) {
                $reinstall_worked[] = $id;
                $upcontext['packages'][$id]['result'] = 'Reinstalled';
                $upcontext['packages'][$id]['color'] = 'green';
                foreach ($infoInstall as $change) {
                    if ($change['type'] == 'modification') {
                        $contents = @file_get_contents($boarddir . '/Packages/temp/' . $upcontext['base_path'] . $change['filename']);
                        if ($change['boardmod']) {
                            $results = parseBoardMod($contents, false, $change['reverse'], $cur_theme_paths);
                        } else {
                            $results = parseModification($contents, false, $change['reverse'], $cur_theme_paths);
                        }
                    }
                }
                // Save the changes.
                package_flush_cache();
            }
        }
    }
    // Put errors back on a sec.
    error_reporting($oldErrorReporting);
    // Check everything is writable.
    if ($test && !empty($upcontext['packages'])) {
        $writable_files = array();
        foreach ($upcontext['packages'] as $package) {
            if (!empty($package['files'])) {
                foreach ($package['files'] as $file) {
                    $writable_files[] = $file;
                }
            }
        }
        if (!empty($writable_files)) {
            $writable_files = array_unique($writable_files);
            $upcontext['writable_files'] = $writable_files;
            if (!makeFilesWritable($writable_files)) {
                return false;
            }
        }
    }
    if (file_exists($boarddir . '/Packages/temp')) {
        deltree($boarddir . '/Packages/temp');
    }
    // Removing/Reinstalling any packages?
    if (isset($_POST['remove'])) {
        $deletes = array();
        foreach ($_POST['remove'] as $id => $dummy) {
            if (!in_array((int) $id, $reinstall_worked)) {
                $deletes[] = (int) $id;
            }
        }
        if (!empty($deletes)) {
            upgrade_query('
				UPDATE ' . $db_prefix . 'log_packages
				SET install_state = 0
				WHERE id_install IN (' . implode(',', $deletes) . ')');
        }
        // Ensure we don't lose our changes!
        package_put_contents($boarddir . '/Packages/installed.list', time());
        $upcontext['sub_template'] = 'cleanup_done';
        return false;
    } else {
        $allgood = true;
        // Is there actually anything that needs our attention?
        foreach ($upcontext['packages'] as $package) {
            if ($package['color'] != 'green') {
                $allgood = false;
            }
        }
        if ($allgood) {
            return true;
        }
    }
    $_GET['substep'] = 0;
    return isset($_POST['cleandone']) ? true : false;
}
 /**
  * Installs new themes, either from a gzip or copy of the default.
  *
  * What it does:
  * - Puts themes in $boardurl/themes.
  * - Assumes the gzip has a root directory in it. (ie default.)
  * - Requires admin_forum.
  * - Accessed with ?action=admin;area=theme;sa=install.
  *
  * @uses ManageThemes template
  */
 public function action_install()
 {
     global $boardurl, $txt, $context, $settings, $modSettings;
     checkSession('request');
     require_once SUBSDIR . '/Themes.subs.php';
     require_once SUBSDIR . '/Package.subs.php';
     loadTemplate('ManageThemes');
     // Passed an ID, then the install is complete, lets redirect and show them
     if (isset($_GET['theme_id'])) {
         $_GET['theme_id'] = (int) $_GET['theme_id'];
         $context['sub_template'] = 'installed';
         $context['page_title'] = $txt['theme_installed'];
         $context['installed_theme'] = array('id' => $_GET['theme_id'], 'name' => getThemeName($_GET['theme_id']));
         return;
     }
     // How are we going to install this theme, from a dir, zip, copy of default?
     if (!empty($_FILES['theme_gz']) && (!isset($_FILES['theme_gz']['error']) || $_FILES['theme_gz']['error'] != 4) || !empty($_REQUEST['theme_gz'])) {
         $method = 'upload';
     } elseif (isset($_REQUEST['theme_dir']) && rtrim(realpath($_REQUEST['theme_dir']), '/\\') != realpath(BOARDDIR . '/themes') && file_exists($_REQUEST['theme_dir'])) {
         $method = 'path';
     } else {
         $method = 'copy';
     }
     // Copy the default theme?
     if (!empty($_REQUEST['copy']) && $method == 'copy') {
         // Hopefully the themes directory is writable, or we might have a problem.
         if (!is_writable(BOARDDIR . '/themes')) {
             fatal_lang_error('theme_install_write_error', 'critical');
         }
         // Make the new directory, standard characters only
         $theme_dir = BOARDDIR . '/themes/' . preg_replace('~[^A-Za-z0-9_\\- ]~', '', $_REQUEST['copy']);
         umask(0);
         mkdir($theme_dir, 0777);
         // Get some more time if we can
         @set_time_limit(600);
         if (function_exists('apache_reset_timeout')) {
             @apache_reset_timeout();
         }
         // Create the subdirectories for css, javascript and font files.
         mkdir($theme_dir . '/css', 0777);
         mkdir($theme_dir . '/scripts', 0777);
         mkdir($theme_dir . '/webfonts', 0777);
         // Copy over the default non-theme files.
         $to_copy = array('/index.php', '/index.template.php', '/scripts/theme.js');
         foreach ($to_copy as $file) {
             copy($settings['default_theme_dir'] . $file, $theme_dir . $file);
             @chmod($theme_dir . $file, 0777);
         }
         // And now the entire css, images and webfonts directories!
         copytree($settings['default_theme_dir'] . '/css', $theme_dir . '/css');
         copytree($settings['default_theme_dir'] . '/images', $theme_dir . '/images');
         copytree($settings['default_theme_dir'] . '/webfonts', $theme_dir . '/webfonts');
         package_flush_cache();
         $theme_name = $_REQUEST['copy'];
         $images_url = $boardurl . '/themes/' . basename($theme_dir) . '/images';
         $theme_dir = realpath($theme_dir);
         // Lets get some data for the new theme (default theme (1), default settings (0)).
         $theme_values = loadThemeOptionsInto(1, 0, array(), array('theme_templates', 'theme_layers'));
         // Lets add a theme_info.xml to this theme.
         write_theme_info($_REQUEST['copy'], $modSettings['elkVersion'], $theme_dir, $theme_values);
     } elseif (isset($_REQUEST['theme_dir']) && $method == 'path') {
         if (!is_dir($_REQUEST['theme_dir']) || !file_exists($_REQUEST['theme_dir'] . '/theme_info.xml')) {
             fatal_lang_error('theme_install_error', false);
         }
         $theme_name = basename($_REQUEST['theme_dir']);
         $theme_dir = $_REQUEST['theme_dir'];
     } elseif ($method == 'upload') {
         // Hopefully the themes directory is writable, or we might have a problem.
         if (!is_writable(BOARDDIR . '/themes')) {
             fatal_lang_error('theme_install_write_error', 'critical');
         }
         // This happens when the admin session is gone and the user has to login again
         if (empty($_FILES['theme_gz']) && empty($_REQUEST['theme_gz'])) {
             redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']);
         }
         // Set the default settings...
         $theme_name = strtok(basename(isset($_FILES['theme_gz']) ? $_FILES['theme_gz']['name'] : $_REQUEST['theme_gz']), '.');
         $theme_name = preg_replace(array('/\\s/', '/\\.[\\.]+/', '/[^\\w_\\.\\-]/'), array('_', '.', ''), $theme_name);
         $theme_dir = BOARDDIR . '/themes/' . $theme_name;
         if (isset($_FILES['theme_gz']) && is_uploaded_file($_FILES['theme_gz']['tmp_name']) && (ini_get('open_basedir') != '' || file_exists($_FILES['theme_gz']['tmp_name']))) {
             read_tgz_file($_FILES['theme_gz']['tmp_name'], BOARDDIR . '/themes/' . $theme_name, false, true);
         } elseif (isset($_REQUEST['theme_gz'])) {
             if (!isAuthorizedServer($_REQUEST['theme_gz'])) {
                 fatal_lang_error('not_valid_server');
             }
             read_tgz_file($_REQUEST['theme_gz'], BOARDDIR . '/themes/' . $theme_name, false, true);
         } else {
             redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']);
         }
     } else {
         fatal_lang_error('theme_install_general', false);
     }
     // Something go wrong?
     if ($theme_dir != '' && basename($theme_dir) != 'themes') {
         // Defaults.
         $install_info = array('theme_url' => $boardurl . '/themes/' . basename($theme_dir), 'images_url' => isset($images_url) ? $images_url : $boardurl . '/themes/' . basename($theme_dir) . '/images', 'theme_dir' => $theme_dir, 'name' => $theme_name);
         $explicit_images = false;
         if (file_exists($theme_dir . '/theme_info.xml')) {
             $theme_info = file_get_contents($theme_dir . '/theme_info.xml');
             // Parse theme-info.xml into an Xml_Array.
             require_once SUBSDIR . '/XmlArray.class.php';
             $theme_info_xml = new Xml_Array($theme_info);
             // @todo Error message of some sort?
             if (!$theme_info_xml->exists('theme-info[0]')) {
                 return 'package_get_error_packageinfo_corrupt';
             }
             $theme_info_xml = $theme_info_xml->path('theme-info[0]');
             $theme_info_xml = $theme_info_xml->to_array();
             $xml_elements = array('name' => 'name', 'theme_layers' => 'layers', 'theme_templates' => 'templates', 'based_on' => 'based-on');
             foreach ($xml_elements as $var => $name) {
                 if (!empty($theme_info_xml[$name])) {
                     $install_info[$var] = $theme_info_xml[$name];
                 }
             }
             if (!empty($theme_info_xml['images'])) {
                 $install_info['images_url'] = $install_info['theme_url'] . '/' . $theme_info_xml['images'];
                 $explicit_images = true;
             }
             if (!empty($theme_info_xml['extra'])) {
                 $install_info += unserialize($theme_info_xml['extra']);
             }
         }
         if (isset($install_info['based_on'])) {
             if ($install_info['based_on'] == 'default') {
                 $install_info['theme_url'] = $settings['default_theme_url'];
                 $install_info['images_url'] = $settings['default_images_url'];
             } elseif ($install_info['based_on'] != '') {
                 $install_info['based_on'] = preg_replace('~[^A-Za-z0-9\\-_ ]~', '', $install_info['based_on']);
                 $temp = loadBasedOnTheme($install_info['based_on'], $explicit_images);
                 // @todo An error otherwise?
                 if (is_array($temp)) {
                     $install_info = $temp + $install_info;
                     if (empty($explicit_images) && !empty($install_info['base_theme_url'])) {
                         $install_info['theme_url'] = $install_info['base_theme_url'];
                     }
                 }
             }
             unset($install_info['based_on']);
         }
         // Find the newest id_theme.
         $id_theme = nextTheme();
         $inserts = array();
         foreach ($install_info as $var => $val) {
             $inserts[] = array($id_theme, $var, $val);
         }
         if (!empty($inserts)) {
             addTheme($inserts);
         }
         updateSettings(array('knownThemes' => strtr($modSettings['knownThemes'] . ',' . $id_theme, array(',,' => ','))));
     }
     redirectexit('action=admin;area=theme;sa=install;theme_id=' . $id_theme . ';' . $context['session_var'] . '=' . $context['session_id']);
 }
Beispiel #8
0
function ThemeInstall()
{
    global $sourcedir, $boarddir, $boardurl, $db_prefix, $txt, $context, $settings, $modSettings;
    checkSession('request');
    isAllowedTo('admin_forum');
    checkSession('request');
    require_once $sourcedir . '/Subs-Package.php';
    loadTemplate('Themes');
    if (isset($_GET['theme_id'])) {
        adminIndex('manage_themes');
        $result = db_query("\n\t\t\tSELECT value\n\t\t\tFROM {$db_prefix}themes\n\t\t\tWHERE ID_THEME = " . (int) $_GET['theme_id'] . "\n\t\t\t\tAND ID_MEMBER = 0\n\t\t\t\tAND variable = 'name'\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        list($theme_name) = mysql_fetch_row($result);
        mysql_free_result($result);
        $context['sub_template'] = 'installed';
        $context['page_title'] = $txt['theme_installed'];
        $context['installed_theme'] = array('id' => (int) $_GET['theme_id'], 'name' => $theme_name);
        return;
    }
    if (!empty($_FILES['theme_gz']) && (!isset($_FILES['theme_gz']['error']) || $_FILES['theme_gz']['error'] != 4) || !empty($_REQUEST['theme_gz'])) {
        $method = 'upload';
    } elseif (isset($_REQUEST['theme_dir']) && realpath(stripslashes($_REQUEST['theme_dir'])) != realpath($boarddir . '/Themes') && file_exists(stripslashes($_REQUEST['theme_dir']))) {
        $method = 'path';
    } else {
        $method = 'copy';
    }
    if (!empty($_REQUEST['copy']) && $method == 'copy') {
        // Hopefully the themes directory is writable, or we might have a problem.
        if (!is_writable($boarddir . '/Themes')) {
            fatal_lang_error('theme_install_write_error');
        }
        $theme_dir = $boarddir . '/Themes/' . preg_replace('~[^A-Za-z0-9_\\- ]~', '', $_REQUEST['copy']);
        umask(0);
        mkdir($theme_dir, 0777);
        // Copy over the default non-theme files.
        $to_copy = array('/style.css', '/index.php', '/index.template.php');
        foreach ($to_copy as $file) {
            copy($settings['default_theme_dir'] . $file, $theme_dir . $file);
            @chmod($theme_dir . $file, 0777);
        }
        // And now the entire images directory!
        copytree($settings['default_theme_dir'] . '/images', $theme_dir . '/images');
        package_flush_cache();
        $theme_name = $_REQUEST['copy'];
        $images_url = $boardurl . '/Themes/' . basename($theme_dir) . '/images';
        $theme_dir = realpath($theme_dir);
    } elseif (isset($_REQUEST['theme_dir']) && $method == 'path') {
        if (!is_dir(stripslashes($_REQUEST['theme_dir'])) || !file_exists(stripslashes($_REQUEST['theme_dir']) . '/theme_info.xml')) {
            fatal_lang_error('theme_install_error', false);
        }
        $theme_name = basename($_REQUEST['theme_dir']);
        $theme_dir = stripslashes($_REQUEST['theme_dir']);
    } elseif ($method = 'upload') {
        // Hopefully the themes directory is writable, or we might have a problem.
        if (!is_writable($boarddir . '/Themes')) {
            fatal_lang_error('theme_install_write_error');
        }
        require_once $sourcedir . '/Subs-Package.php';
        // Set the default settings...
        $theme_name = strtok(basename(isset($_FILES['theme_gz']) ? $_FILES['theme_gz']['name'] : $_REQUEST['theme_gz']), '.');
        $theme_name = preg_replace(array('/\\s/', '/\\.[\\.]+/', '/[^\\w_\\.\\-]/'), array('_', '.', ''), $theme_name);
        $theme_dir = $boarddir . '/Themes/' . $theme_name;
        if (isset($_FILES['theme_gz']) && is_uploaded_file($_FILES['theme_gz']['tmp_name']) && (@ini_get('open_basedir') != '' || file_exists($_FILES['theme_gz']['tmp_name']))) {
            $extracted = read_tgz_file($_FILES['theme_gz']['tmp_name'], $boarddir . '/Themes/' . $theme_name, false, true);
        } elseif (isset($_REQUEST['theme_gz'])) {
            // Check that the theme is from simplemachines.org, for now... maybe add mirroring later.
            if (preg_match('~^http://[\\w_\\-]+\\.simplemachines\\.org/~', $_REQUEST['theme_gz']) == 0 || strpos($_REQUEST['theme_gz'], 'dlattach') !== false) {
                fatal_lang_error('not_on_simplemachines');
            }
            $extracted = read_tgz_file($_REQUEST['theme_gz'], $boarddir . '/Themes/' . $theme_name, false, true);
        } else {
            redirectexit('action=theme;sa=admin;sesc=' . $context['session_id']);
        }
    }
    // Something go wrong?
    if ($theme_dir != '' && basename($theme_dir) != 'Themes') {
        // Defaults.
        $install_info = array('theme_url' => $boardurl . '/Themes/' . basename($theme_dir), 'images_url' => isset($images_url) ? $images_url : $boardurl . '/Themes/' . basename($theme_dir) . '/images', 'theme_dir' => $theme_dir, 'name' => $theme_name);
        if (file_exists($theme_dir . '/theme_info.xml')) {
            $theme_info = file_get_contents($theme_dir . '/theme_info.xml');
            $xml_elements = array('name' => 'name', 'theme_layers' => 'layers', 'theme_templates' => 'templates', 'based_on' => 'based-on');
            foreach ($xml_elements as $var => $name) {
                if (preg_match('~<' . $name . '>(?:<!\\[CDATA\\[)?(.+?)(?:\\]\\]>)?</' . $name . '>~', $theme_info, $match) == 1) {
                    $install_info[$var] = $match[1];
                }
            }
            if (preg_match('~<images>(?:<!\\[CDATA\\[)?(.+?)(?:\\]\\]>)?</images>~', $theme_info, $match) == 1) {
                $install_info['images_url'] = $install_info['theme_url'] . '/' . $match[1];
                $explicit_images = true;
            }
            if (preg_match('~<extra>(?:<!\\[CDATA\\[)?(.+?)(?:\\]\\]>)?</extra>~', $theme_info, $match) == 1) {
                $install_info += unserialize($match[1]);
            }
        }
        if (isset($install_info['based_on'])) {
            if ($install_info['based_on'] == 'default') {
                $install_info['theme_url'] = $settings['default_theme_url'];
                $install_info['images_url'] = $settings['default_images_url'];
            } elseif ($install_info['based_on'] != '') {
                $install_info['based_on'] = preg_replace('~[^A-Za-z0-9\\-_ ]~', '', $install_info['based_on']);
                $request = db_query("\n\t\t\t\t\tSELECT th.value AS base_theme_dir, th2.value AS base_theme_url" . (!empty($explicit_images) ? '' : ", th3.value AS images_url") . "\n\t\t\t\t\tFROM ({$db_prefix}themes AS th, {$db_prefix}themes AS th2" . (!empty($explicit_images) ? '' : ", {$db_prefix}themes AS th3") . ")\n\t\t\t\t\tWHERE th.ID_MEMBER = 0\n\t\t\t\t\t\tAND (th.value LIKE '%/{$install_info['based_on']}' OR th.value LIKE '%\\{$install_info['based_on']}')\n\t\t\t\t\t\tAND th.variable = 'theme_dir'\n\t\t\t\t\t\tAND th.ID_THEME = th2.ID_THEME\n\t\t\t\t\t\tAND th2.ID_MEMBER = 0\n\t\t\t\t\t\tAND th2.variable = 'theme_url'" . (!empty($explicit_images) ? '' : "\n\t\t\t\t\t\tAND th.ID_THEME = th3.ID_THEME\n\t\t\t\t\t\tAND th3.ID_MEMBER = 0\n\t\t\t\t\t\tAND th3.variable = 'images_url'") . "\n\t\t\t\t\tLIMIT 1", __FILE__, __LINE__);
                $temp = mysql_fetch_assoc($request);
                mysql_free_result($request);
                // !!! An error otherwise?
                if (is_array($temp)) {
                    $install_info = $temp + $install_info;
                    if (empty($explicit_images) && !empty($install_info['base_theme_url'])) {
                        $install_info['theme_url'] = $install_info['base_theme_url'];
                    }
                }
            }
            unset($install_info['based_on']);
        }
        // Find the newest ID_THEME.
        $result = db_query("\n\t\t\tSELECT MAX(ID_THEME)\n\t\t\tFROM {$db_prefix}themes", __FILE__, __LINE__);
        list($ID_THEME) = mysql_fetch_row($result);
        mysql_free_result($result);
        // This will be theme number...
        $ID_THEME++;
        $setString = '';
        foreach ($install_info as $var => $val) {
            $setString .= "\n\t\t\t\t({$ID_THEME}, SUBSTRING('" . addslashes($var) . "', 1, 255), SUBSTRING('" . addslashes($val) . "', 1, 65534)),";
        }
        $setString = substr($setString, 0, -1);
        db_query("\n\t\t\tINSERT INTO {$db_prefix}themes\n\t\t\t\t(ID_THEME, variable, value)\n\t\t\tVALUES{$setString}", __FILE__, __LINE__);
        updateSettings(array('knownThemes' => strtr($modSettings['knownThemes'] . ',' . $ID_THEME, array(',,' => ','))));
    }
    redirectexit('action=theme;sa=install;theme_id=' . $ID_THEME . ';sesc=' . $context['session_id']);
}