コード例 #1
0
 /**
  * Allow the admin to reset permissions on files.
  */
 public function action_perms()
 {
     global $context, $txt, $modSettings, $package_ftp;
     // Let's try and be good, yes?
     checkSession('get');
     // If we're restoring permissions this is just a pass through really.
     if (isset($_GET['restore'])) {
         create_chmod_control(array(), array(), true);
         fatal_lang_error('no_access', false);
     }
     // This is a time and memory eating ...
     setMemoryLimit('128M');
     @set_time_limit(600);
     // Load up some FTP stuff.
     create_chmod_control();
     if (empty($package_ftp) && !isset($_POST['skip_ftp'])) {
         require_once SUBSDIR . '/FtpConnection.class.php';
         $ftp = new Ftp_Connection(null);
         list($username, $detect_path, $found_path) = $ftp->detect_path(BOARDDIR);
         $context['package_ftp'] = array('server' => isset($modSettings['package_server']) ? $modSettings['package_server'] : 'localhost', 'port' => isset($modSettings['package_port']) ? $modSettings['package_port'] : '21', 'username' => empty($username) ? isset($modSettings['package_username']) ? $modSettings['package_username'] : '' : $username, 'path' => $detect_path, 'form_elements_only' => true);
     } else {
         $context['ftp_connected'] = true;
     }
     // Define the template.
     $context['page_title'] = $txt['package_file_perms'];
     $context['sub_template'] = 'file_permissions';
     // Define what files we're interested in, as a tree.
     $context['file_tree'] = array(strtr(BOARDDIR, array('\\' => '/')) => array('type' => 'dir', 'contents' => array('agreement.txt' => array('type' => 'file', 'writable_on' => 'standard'), 'Settings.php' => array('type' => 'file', 'writable_on' => 'restrictive'), 'Settings_bak.php' => array('type' => 'file', 'writable_on' => 'restrictive'), 'attachments' => array('type' => 'dir', 'writable_on' => 'restrictive'), 'avatars' => array('type' => 'dir', 'writable_on' => 'standard'), 'cache' => array('type' => 'dir', 'writable_on' => 'restrictive'), 'custom_avatar_dir' => array('type' => 'dir', 'writable_on' => 'restrictive'), 'smileys' => array('type' => 'dir_recursive', 'writable_on' => 'standard'), 'sources' => array('type' => 'dir', 'list_contents' => true, 'writable_on' => 'standard'), 'themes' => array('type' => 'dir_recursive', 'writable_on' => 'standard', 'contents' => array('default' => array('type' => 'dir_recursive', 'list_contents' => true, 'contents' => array('languages' => array('type' => 'dir', 'list_contents' => true))))), 'packages' => array('type' => 'dir', 'writable_on' => 'standard', 'contents' => array('temp' => array('type' => 'dir'), 'backup' => array('type' => 'dir'), 'installed.list' => array('type' => 'file', 'writable_on' => 'standard'))))));
     // Directories that can move.
     if (substr(SOURCEDIR, 0, strlen(BOARDDIR)) != BOARDDIR) {
         unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['sources']);
         $context['file_tree'][strtr(SOURCEDIR, array('\\' => '/'))] = array('type' => 'dir', 'list_contents' => true, 'writable_on' => 'standard');
     }
     // Moved the cache?
     if (substr(CACHEDIR, 0, strlen(BOARDDIR)) != BOARDDIR) {
         unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['cache']);
         $context['file_tree'][strtr(CACHEDIR, array('\\' => '/'))] = array('type' => 'dir', 'list_contents' => false, 'writable_on' => 'restrictive');
     }
     // Are we using multiple attachment directories?
     if (!empty($modSettings['currentAttachmentUploadDir'])) {
         unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['attachments']);
         if (!is_array($modSettings['attachmentUploadDir'])) {
             $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
         }
         // @todo Should we suggest non-current directories be read only?
         foreach ($modSettings['attachmentUploadDir'] as $dir) {
             $context['file_tree'][strtr($dir, array('\\' => '/'))] = array('type' => 'dir', 'writable_on' => 'restrictive');
         }
     } elseif (substr($modSettings['attachmentUploadDir'], 0, strlen(BOARDDIR)) != BOARDDIR) {
         unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['attachments']);
         $context['file_tree'][strtr($modSettings['attachmentUploadDir'], array('\\' => '/'))] = array('type' => 'dir', 'writable_on' => 'restrictive');
     }
     if (substr($modSettings['smileys_dir'], 0, strlen(BOARDDIR)) != BOARDDIR) {
         unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['smileys']);
         $context['file_tree'][strtr($modSettings['smileys_dir'], array('\\' => '/'))] = array('type' => 'dir_recursive', 'writable_on' => 'standard');
     }
     if (substr($modSettings['avatar_directory'], 0, strlen(BOARDDIR)) != BOARDDIR) {
         unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['avatars']);
         $context['file_tree'][strtr($modSettings['avatar_directory'], array('\\' => '/'))] = array('type' => 'dir', 'writable_on' => 'standard');
     }
     if (isset($modSettings['custom_avatar_dir']) && substr($modSettings['custom_avatar_dir'], 0, strlen(BOARDDIR)) != BOARDDIR) {
         unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['custom_avatar_dir']);
         $context['file_tree'][strtr($modSettings['custom_avatar_dir'], array('\\' => '/'))] = array('type' => 'dir', 'writable_on' => 'restrictive');
     }
     // Load up any custom themes.
     require_once SUBSDIR . '/Themes.subs.php';
     $themes = getCustomThemes();
     foreach ($themes as $id => $theme) {
         // Skip the default
         if ($id == 1) {
             continue;
         }
         if (substr(strtolower(strtr($theme['theme_dir'], array('\\' => '/'))), 0, strlen(BOARDDIR) + 7) === strtolower(strtr(BOARDDIR, array('\\' => '/')) . '/themes')) {
             $context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['themes']['contents'][substr($theme['theme_dir'], strlen(BOARDDIR) + 8)] = array('type' => 'dir_recursive', 'list_contents' => true, 'contents' => array('languages' => array('type' => 'dir', 'list_contents' => true)));
         } else {
             $context['file_tree'][strtr($theme['theme_dir'], array('\\' => '/'))] = array('type' => 'dir_recursive', 'list_contents' => true, 'contents' => array('languages' => array('type' => 'dir', 'list_contents' => true)));
         }
     }
     // If we're submitting then let's move on to another function to keep things cleaner..
     if (isset($_POST['action_changes'])) {
         return $this->action_perms_save();
     }
     $context['look_for'] = array();
     // Are we looking for a particular tree - normally an expansion?
     if (!empty($_REQUEST['find'])) {
         $context['look_for'][] = base64_decode($_REQUEST['find']);
     }
     // Only that tree?
     $context['only_find'] = isset($_GET['xml']) && !empty($_REQUEST['onlyfind']) ? $_REQUEST['onlyfind'] : '';
     if ($context['only_find']) {
         $context['look_for'][] = $context['only_find'];
     }
     // Have we got a load of back-catalogue trees to expand from a submit etc?
     if (!empty($_GET['back_look'])) {
         $potententialTrees = unserialize(base64_decode($_GET['back_look']));
         foreach ($potententialTrees as $tree) {
             $context['look_for'][] = $tree;
         }
     }
     // ... maybe posted?
     if (!empty($_POST['back_look'])) {
         $context['only_find'] = array_merge($context['only_find'], $_POST['back_look']);
     }
     $context['back_look_data'] = base64_encode(serialize(array_slice($context['look_for'], 0, 15)));
     // Are we finding more files than first thought?
     $context['file_offset'] = !empty($_REQUEST['fileoffset']) ? (int) $_REQUEST['fileoffset'] : 0;
     // Don't list more than this many files in a directory.
     $context['file_limit'] = 150;
     // How many levels shall we show?
     $context['default_level'] = empty($context['only_find']) ? 2 : 25;
     // This will be used if we end up catching XML data.
     $context['xml_data'] = array('roots' => array('identifier' => 'root', 'children' => array(array('value' => preg_replace('~[^A-Za-z0-9_\\-=:]~', ':-:', $context['only_find'])))), 'folders' => array('identifier' => 'folder', 'children' => array()));
     foreach ($context['file_tree'] as $path => $data) {
         // Run this directory.
         if (file_exists($path) && (empty($context['only_find']) || substr($context['only_find'], 0, strlen($path)) == $path)) {
             // Get the first level down only.
             fetchPerms__recursive($path, $context['file_tree'][$path], 1);
             $context['file_tree'][$path]['perms'] = array('chmod' => @is_writable($path), 'perms' => @fileperms($path));
         } else {
             unset($context['file_tree'][$path]);
         }
     }
     // Is this actually xml?
     if (isset($_GET['xml'])) {
         loadTemplate('Xml');
         $context['sub_template'] = 'generic_xml';
         Template_Layers::getInstance()->removeAll();
     }
 }
コード例 #2
0
 /**
  * Edit a particular set of language entries.
  */
 public function action_editlang()
 {
     global $settings, $context, $txt, $modSettings, $language, $scripturl;
     require_once SUBSDIR . '/Language.subs.php';
     loadLanguage('ManageSettings');
     // Select the languages tab.
     $context['menu_data_' . $context['admin_menu_id']]['current_subsection'] = 'edit';
     $context['page_title'] = $txt['edit_languages'];
     $context['sub_template'] = 'modify_language_entries';
     $context['lang_id'] = $_GET['lid'];
     list($theme_id, $file_id) = empty($_REQUEST['tfid']) || strpos($_REQUEST['tfid'], '+') === false ? array(1, '') : explode('+', $_REQUEST['tfid']);
     // Clean the ID - just in case.
     preg_match('~([A-Za-z0-9_-]+)~', $context['lang_id'], $matches);
     $context['lang_id'] = $matches[1];
     // Get all the theme data.
     require_once SUBSDIR . '/Themes.subs.php';
     $themes = getCustomThemes();
     // This will be where we look
     $lang_dirs = array();
     $images_dirs = array();
     // Check we have themes with a path and a name - just in case - and add the path.
     foreach ($themes as $id => $data) {
         if (count($data) != 2) {
             unset($themes[$id]);
         } elseif (is_dir($data['theme_dir'] . '/languages/' . $context['lang_id'])) {
             $lang_dirs[$id] = $data['theme_dir'] . '/languages/' . $context['lang_id'];
         }
         // How about image directories?
         if (is_dir($data['theme_dir'] . '/images/' . $context['lang_id'])) {
             $images_dirs[$id] = $data['theme_dir'] . '/images/' . $context['lang_id'];
         }
     }
     $current_file = $file_id ? $lang_dirs[$theme_id] . '/' . $file_id . '.' . $context['lang_id'] . '.php' : '';
     // Now for every theme get all the files and stick them in context!
     $context['possible_files'] = array();
     foreach ($lang_dirs as $theme => $theme_dir) {
         // Open it up.
         $dir = dir($theme_dir);
         while ($entry = $dir->read()) {
             // We're only after the files for this language.
             if (preg_match('~^([A-Za-z]+)\\.' . $context['lang_id'] . '\\.php$~', $entry, $matches) == 0) {
                 continue;
             }
             if (!isset($context['possible_files'][$theme])) {
                 $context['possible_files'][$theme] = array('id' => $theme, 'name' => $themes[$theme]['name'], 'files' => array());
             }
             $context['possible_files'][$theme]['files'][] = array('id' => $matches[1], 'name' => isset($txt['lang_file_desc_' . $matches[1]]) ? $txt['lang_file_desc_' . $matches[1]] : $matches[1], 'selected' => $theme_id == $theme && $file_id == $matches[1]);
         }
         $dir->close();
         usort($context['possible_files'][$theme]['files'], create_function('$val1, $val2', 'return strcmp($val1[\'name\'], $val2[\'name\']);'));
     }
     if ($context['lang_id'] != 'english') {
         $possiblePackage = findPossiblePackages($context['lang_id']);
         if ($possiblePackage !== false) {
             $context['langpack_uninstall_link'] = $scripturl . '?action=admin;area=packages;sa=uninstall;package=' . $possiblePackage[1] . ';pid=' . $possiblePackage[0];
         }
     }
     // We no longer wish to speak this language.
     // @todo - languages have been moved to packages
     // this may or may not be used in the future, for now it's not used at all
     // @deprecated since 1.0
     if (!empty($_POST['delete_main']) && $context['lang_id'] != 'english') {
         checkSession();
         validateToken('admin-mlang');
         // @todo FTP Controls?
         require_once SUBSDIR . '/Package.subs.php';
         // First, Make a backup?
         if (!empty($modSettings['package_make_backups']) && (!isset($_SESSION['last_backup_for']) || $_SESSION['last_backup_for'] != $context['lang_id'] . '$$$')) {
             $_SESSION['last_backup_for'] = $context['lang_id'] . '$$$';
             package_create_backup('backup_lang_' . $context['lang_id']);
         }
         // Second, loop through the array to remove the files.
         foreach ($lang_dirs as $curPath) {
             foreach ($context['possible_files'][1]['files'] as $lang) {
                 if (file_exists($curPath . '/' . $lang['id'] . '.' . $context['lang_id'] . '.php')) {
                     unlink($curPath . '/' . $lang['id'] . '.' . $context['lang_id'] . '.php');
                 }
             }
             // Check for the email template.
             if (file_exists($curPath . '/EmailTemplates.' . $context['lang_id'] . '.php')) {
                 unlink($curPath . '/EmailTemplates.' . $context['lang_id'] . '.php');
             }
         }
         // Third, the agreement file.
         if (file_exists(BOARDDIR . '/agreement.' . $context['lang_id'] . '.txt')) {
             unlink(BOARDDIR . '/agreement.' . $context['lang_id'] . '.txt');
         }
         // Fourth, a related images folder?
         if (!empty($images_dirs)) {
             foreach ($images_dirs as $curPath) {
                 if (is_dir($curPath)) {
                     deltree($curPath);
                 }
             }
         }
         // Members can no longer use this language.
         removeLanguageFromMember($context['lang_id']);
         // Fifth, update getLanguages() cache.
         if (!empty($modSettings['cache_enable'])) {
             cache_put_data('known_languages', null, !empty($modSettings['cache_enable']) && $modSettings['cache_enable'] < 1 ? 86400 : 3600);
         }
         // Sixth, if we deleted the default language, set us back to english?
         if ($context['lang_id'] == $language) {
             require_once SUBSDIR . '/SettingsForm.class.php';
             $language = 'english';
             Settings_Form::save_file(array('language' => '\'' . $language . '\''));
         }
         // Seventh, get out of here.
         redirectexit('action=admin;area=languages;sa=edit;' . $context['session_var'] . '=' . $context['session_id']);
     }
     // Saving primary settings?
     $madeSave = false;
     if (!empty($_POST['save_main']) && !$current_file) {
         checkSession();
         validateToken('admin-mlang');
         // Read in the current file.
         $current_data = implode('', file($settings['default_theme_dir'] . '/languages/' . $context['lang_id'] . '/index.' . $context['lang_id'] . '.php'));
         // These are the replacements. old => new
         $replace_array = array('~\\$txt\\[\'lang_locale\'\\]\\s=\\s(\'|")[^\\r\\n]+~' => '$txt[\'lang_locale\'] = \'' . addslashes($_POST['locale']) . '\';', '~\\$txt\\[\'lang_dictionary\'\\]\\s=\\s(\'|")[^\\r\\n]+~' => '$txt[\'lang_dictionary\'] = \'' . addslashes($_POST['dictionary']) . '\';', '~\\$txt\\[\'lang_spelling\'\\]\\s=\\s(\'|")[^\\r\\n]+~' => '$txt[\'lang_spelling\'] = \'' . addslashes($_POST['spelling']) . '\';', '~\\$txt\\[\'lang_rtl\'\\]\\s=\\s[A-Za-z0-9]+;~' => '$txt[\'lang_rtl\'] = ' . (!empty($_POST['rtl']) ? 'true' : 'false') . ';');
         $current_data = preg_replace(array_keys($replace_array), array_values($replace_array), $current_data);
         $fp = fopen($settings['default_theme_dir'] . '/languages/' . $context['lang_id'] . '/index.' . $context['lang_id'] . '.php', 'w+');
         fwrite($fp, $current_data);
         fclose($fp);
         $madeSave = true;
     }
     // Quickly load index language entries.
     $old_txt = $txt;
     require $settings['default_theme_dir'] . '/languages/' . $context['lang_id'] . '/index.' . $context['lang_id'] . '.php';
     $context['lang_file_not_writable_message'] = is_writable($settings['default_theme_dir'] . '/languages/' . $context['lang_id'] . '/index.' . $context['lang_id'] . '.php') ? '' : sprintf($txt['lang_file_not_writable'], $settings['default_theme_dir'] . '/languages/' . $context['lang_id'] . '/index.' . $context['lang_id'] . '.php');
     // Setup the primary settings context.
     $context['primary_settings'] = array('name' => Util::ucwords(strtr($context['lang_id'], array('_' => ' ', '-utf8' => ''))), 'locale' => $txt['lang_locale'], 'dictionary' => $txt['lang_dictionary'], 'spelling' => $txt['lang_spelling'], 'rtl' => $txt['lang_rtl']);
     // Restore normal service.
     $txt = $old_txt;
     // Are we saving?
     $save_strings = array();
     if (isset($_POST['save_entries']) && !empty($_POST['entry'])) {
         checkSession();
         validateToken('admin-mlang');
         // Clean each entry!
         foreach ($_POST['entry'] as $k => $v) {
             // Only try to save if it's changed!
             if ($_POST['entry'][$k] != $_POST['comp'][$k]) {
                 $save_strings[$k] = cleanLangString($v, false);
             }
         }
     }
     // If we are editing a file work away at that.
     if ($current_file) {
         $context['entries_not_writable_message'] = is_writable($current_file) ? '' : sprintf($txt['lang_entries_not_writable'], $current_file);
         $entries = array();
         // We can't just require it I'm afraid - otherwise we pass in all kinds of variables!
         $multiline_cache = '';
         foreach (file($current_file) as $line) {
             // Got a new entry?
             if ($line[0] == '$' && !empty($multiline_cache)) {
                 preg_match('~\\$(helptxt|txt|editortxt)\\[\'(.+)\'\\]\\s?=\\s?(.+);~ms', strtr($multiline_cache, array("\r" => '')), $matches);
                 if (!empty($matches[3])) {
                     $entries[$matches[2]] = array('type' => $matches[1], 'full' => $matches[0], 'entry' => $matches[3]);
                     $multiline_cache = '';
                 }
             }
             $multiline_cache .= $line;
         }
         // Last entry to add?
         if ($multiline_cache) {
             preg_match('~\\$(helptxt|txt|editortxt)\\[\'(.+)\'\\]\\s?=\\s?(.+);~ms', strtr($multiline_cache, array("\r" => '')), $matches);
             if (!empty($matches[3])) {
                 $entries[$matches[2]] = array('type' => $matches[1], 'full' => $matches[0], 'entry' => $matches[3]);
             }
         }
         // These are the entries we can definitely save.
         $final_saves = array();
         $context['file_entries'] = array();
         foreach ($entries as $entryKey => $entryValue) {
             // Nowadays some entries have fancy keys, so better use something "portable" for the form
             $md5EntryKey = md5($entryKey);
             // Ignore some things we set separately.
             $ignore_files = array('lang_character_set', 'lang_locale', 'lang_dictionary', 'lang_spelling', 'lang_rtl');
             if (in_array($entryKey, $ignore_files)) {
                 continue;
             }
             // These are arrays that need breaking out.
             $arrays = array('days', 'days_short', 'months', 'months_titles', 'months_short', 'happy_birthday_author', 'karlbenson1_author', 'nite0859_author', 'zwaldowski_author', 'geezmo_author', 'karlbenson2_author');
             if (in_array($entryKey, $arrays)) {
                 // Get off the first bits.
                 $entryValue['entry'] = substr($entryValue['entry'], strpos($entryValue['entry'], '(') + 1, strrpos($entryValue['entry'], ')') - strpos($entryValue['entry'], '('));
                 $entryValue['entry'] = explode(',', strtr($entryValue['entry'], array(' ' => '')));
                 // Now create an entry for each item.
                 $cur_index = 0;
                 $save_cache = array('enabled' => false, 'entries' => array());
                 foreach ($entryValue['entry'] as $id => $subValue) {
                     // Is this a new index?
                     if (preg_match('~^(\\d+)~', $subValue, $matches)) {
                         $cur_index = $matches[1];
                         $subValue = substr($subValue, strpos($subValue, '\''));
                     }
                     // Clean up some bits.
                     $subValue = strtr($subValue, array('"' => '', '\'' => '', ')' => ''));
                     // Can we save?
                     if (isset($save_strings[$md5EntryKey . '-+- ' . $cur_index])) {
                         $save_cache['entries'][$cur_index] = strtr($save_strings[$md5EntryKey . '-+- ' . $cur_index], array('\'' => ''));
                         $save_cache['enabled'] = true;
                     } else {
                         $save_cache['entries'][$cur_index] = $subValue;
                     }
                     $context['file_entries'][] = array('key' => $entryKey . '-+- ' . $cur_index, 'display_key' => $entryKey . '-+- ' . $cur_index, 'value' => $subValue, 'rows' => 1);
                     $cur_index++;
                 }
                 // Do we need to save?
                 if ($save_cache['enabled']) {
                     // Format the string, checking the indexes first.
                     $items = array();
                     $cur_index = 0;
                     foreach ($save_cache['entries'] as $k2 => $v2) {
                         // Manually show the custom index.
                         if ($k2 != $cur_index) {
                             $items[] = $k2 . ' => \'' . $v2 . '\'';
                             $cur_index = $k2;
                         } else {
                             $items[] = '\'' . $v2 . '\'';
                         }
                         $cur_index++;
                     }
                     // Now create the string!
                     $final_saves[$entryKey] = array('find' => $entryValue['full'], 'replace' => '$' . $entryValue['type'] . '[\'' . $entryKey . '\'] = array(' . implode(', ', $items) . ');');
                 }
             } else {
                 // Saving?
                 if (isset($save_strings[$md5EntryKey]) && $save_strings[$md5EntryKey] != $entryValue['entry']) {
                     // @todo Fix this properly.
                     if ($save_strings[$md5EntryKey] == '') {
                         $save_strings[$md5EntryKey] = '\'\'';
                     }
                     // Set the new value.
                     $entryValue['entry'] = $save_strings[$md5EntryKey];
                     // And we know what to save now!
                     $final_saves[$entryKey] = array('find' => $entryValue['full'], 'replace' => '$' . $entryValue['type'] . '[\'' . $entryKey . '\'] = ' . $save_strings[$md5EntryKey] . ';');
                 }
                 $editing_string = cleanLangString($entryValue['entry'], true);
                 $context['file_entries'][] = array('key' => $md5EntryKey, 'display_key' => $entryKey, 'value' => $editing_string, 'rows' => (int) (strlen($editing_string) / 38) + substr_count($editing_string, "\n") + 1);
             }
         }
         // Any saves to make?
         if (!empty($final_saves)) {
             checkSession();
             $file_contents = implode('', file($current_file));
             foreach ($final_saves as $save) {
                 $file_contents = strtr($file_contents, array($save['find'] => $save['replace']));
             }
             // Save the actual changes.
             $fp = fopen($current_file, 'w+');
             fwrite($fp, strtr($file_contents, array("\r" => '')));
             fclose($fp);
             $madeSave = true;
         }
         // Another restore.
         $txt = $old_txt;
     }
     // If we saved, redirect.
     if ($madeSave) {
         redirectexit('action=admin;area=languages;sa=editlang;lid=' . $context['lang_id']);
     }
     createToken('admin-mlang');
 }