/** * 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']); }
/** * Install a smiley set. */ public function action_install() { global $modSettings, $scripturl, $context, $txt, $user_info; isAllowedTo('manage_smileys'); checkSession('request'); // One of these two may be necessary loadLanguage('Errors'); loadLanguage('Packages'); require_once SUBSDIR . '/Smileys.subs.php'; require_once SUBSDIR . '/Package.subs.php'; // Installing unless proven otherwise $testing = false; $destination = ''; $name = ''; if (isset($_REQUEST['set_gz'])) { $base_name = strtr(basename($_REQUEST['set_gz']), ':/', '-_'); $name = Util::htmlspecialchars(strtok(basename($_REQUEST['set_gz']), '.')); $name_pr = preg_replace(array('/\\s/', '/\\.[\\.]+/', '/[^\\w_\\.\\-]/'), array('_', '.', ''), $name); $context['filename'] = $base_name; // Check that the smiley is from simplemachines.org, for now... maybe add mirroring later. if (!isAuthorizedServer($_REQUEST['set_gz']) == 0) { fatal_lang_error('not_valid_server'); } $destination = BOARDDIR . '/packages/' . $base_name; if (file_exists($destination)) { fatal_lang_error('package_upload_error_exists'); } // Let's copy it to the packages directory file_put_contents($destination, fetch_web_data($_REQUEST['set_gz'])); $testing = true; } elseif (isset($_REQUEST['package'])) { $base_name = basename($_REQUEST['package']); $name = Util::htmlspecialchars(strtok(basename($_REQUEST['package']), '.')); $name_pr = preg_replace(array('/\\s/', '/\\.[\\.]+/', '/[^\\w_\\.\\-]/'), array('_', '.', ''), $name); $context['filename'] = $base_name; $destination = BOARDDIR . '/packages/' . basename($_REQUEST['package']); } if (!file_exists($destination)) { fatal_lang_error('package_no_file', false); } // Make sure temp directory exists and is empty. if (file_exists(BOARDDIR . '/packages/temp')) { deltree(BOARDDIR . '/packages/temp', false); } if (!mktree(BOARDDIR . '/packages/temp', 0755)) { deltree(BOARDDIR . '/packages/temp', false); if (!mktree(BOARDDIR . '/packages/temp', 0777)) { deltree(BOARDDIR . '/packages/temp', false); // @todo not sure about url in destination_url create_chmod_control(array(BOARDDIR . '/packages/temp/delme.tmp'), array('destination_url' => $scripturl . '?action=admin;area=smileys;sa=install;set_gz=' . $_REQUEST['set_gz'], 'crash_on_error' => true)); deltree(BOARDDIR . '/packages/temp', false); if (!mktree(BOARDDIR . '/packages/temp', 0777)) { fatal_lang_error('package_cant_download', false); } } } $extracted = read_tgz_file($destination, BOARDDIR . '/packages/temp'); // @todo needs to change the URL in the next line ;) if (!$extracted) { fatal_lang_error('packageget_unable', false, array('http://custom.elkarte.net/index.php?action=search;type=12;basic_search=' . $name)); } if ($extracted && !file_exists(BOARDDIR . '/packages/temp/package-info.xml')) { foreach ($extracted as $file) { if (basename($file['filename']) == 'package-info.xml') { $base_path = dirname($file['filename']) . '/'; break; } } } if (!isset($base_path)) { $base_path = ''; } if (!file_exists(BOARDDIR . '/packages/temp/' . $base_path . 'package-info.xml')) { fatal_lang_error('package_get_error_missing_xml', false); } $smileyInfo = getPackageInfo($context['filename']); if (!is_array($smileyInfo)) { fatal_lang_error($smileyInfo); } // See if it is installed? if (isSmileySetInstalled($smileyInfo['id'])) { fata_lang_error('package_installed_warning1'); } // Everything is fine, now it's time to do something, first we test $actions = parsePackageInfo($smileyInfo['xml'], true, 'install'); $context['post_url'] = $scripturl . '?action=admin;area=smileys;sa=install;package=' . $base_name; $context['has_failure'] = false; $context['actions'] = array(); $context['ftp_needed'] = false; foreach ($actions as $action) { if ($action['type'] == 'readme' || $action['type'] == 'license') { $type = 'package_' . $action['type']; if (file_exists(BOARDDIR . '/packages/temp/' . $base_path . $action['filename'])) { $context[$type] = htmlspecialchars(trim(file_get_contents(BOARDDIR . '/packages/temp/' . $base_path . $action['filename']), "\n\r"), ENT_COMPAT, 'UTF-8'); } elseif (file_exists($action['filename'])) { $context[$type] = htmlspecialchars(trim(file_get_contents($action['filename']), "\n\r"), ENT_COMPAT, 'UTF-8'); } if (!empty($action['parse_bbc'])) { require_once SUBSDIR . '/Post.subs.php'; preparsecode($context[$type]); $context[$type] = parse_bbc($context[$type]); } else { $context[$type] = nl2br($context[$type]); } continue; } elseif ($action['type'] == 'require-dir') { // Do this one... $thisAction = array('type' => $txt['package_extract'] . ' ' . ($action['type'] == 'require-dir' ? $txt['package_tree'] : $txt['package_file']), 'action' => Util::htmlspecialchars(strtr($action['destination'], array(BOARDDIR => '.')))); $file = BOARDDIR . '/packages/temp/' . $base_path . $action['filename']; if (isset($action['filename']) && (!file_exists($file) || !is_writable(dirname($action['destination'])))) { $context['has_failure'] = true; $thisAction += array('description' => $txt['package_action_error'], 'failed' => true); } // Show a description for the action if one is provided if (empty($thisAction['description'])) { $thisAction['description'] = isset($action['description']) ? $action['description'] : ''; } $context['actions'][] = $thisAction; } elseif ($action['type'] == 'credits') { // Time to build the billboard $credits_tag = array('url' => $action['url'], 'license' => $action['license'], 'copyright' => $action['copyright'], 'title' => $action['title']); } } if ($testing) { $context['sub_template'] = 'view_package'; $context['uninstalling'] = false; $context['is_installed'] = false; $context['package_name'] = $smileyInfo['name']; loadTemplate('Packages'); } else { $actions = parsePackageInfo($smileyInfo['xml'], false, 'install'); foreach ($context['actions'] as $action) { updateSettings(array('smiley_sets_known' => $modSettings['smiley_sets_known'] . ',' . basename($action['action']), 'smiley_sets_names' => $modSettings['smiley_sets_names'] . "\n" . $smileyInfo['name'] . (count($context['actions']) > 1 ? ' ' . (!empty($action['description']) ? Util::htmlspecialchars($action['description']) : basename($action['action'])) : ''))); } package_flush_cache(); // Time to tell pacman we have a new package installed! package_put_contents(BOARDDIR . '/packages/installed.list', time()); // Credits tag? $credits_tag = empty($credits_tag) ? '' : serialize($credits_tag); $installed = array('filename' => $smileyInfo['filename'], 'name' => $smileyInfo['name'], 'package_id' => $smileyInfo['id'], 'version' => $smileyInfo['filename'], 'id_member' => $user_info['id'], 'member_name' => $user_info['name'], 'credits_tag' => $credits_tag); logPackageInstall($installed); logAction('install_package', array('package' => Util::htmlspecialchars($smileyInfo['name']), 'version' => Util::htmlspecialchars($smileyInfo['version'])), 'admin'); cache_put_data('parsing_smileys', null, 480); cache_put_data('posting_smileys', null, 480); } if (file_exists(BOARDDIR . '/packages/temp')) { deltree(BOARDDIR . '/packages/temp'); } if (!$testing) { redirectexit('action=admin;area=smileys'); } }