/** construct an AreaManager object * * This initialises the AreaManager and also dispatches the chore to do. * * @param object &$output collects the html output * @uses $CFG */ function AreaManager(&$output) { global $CFG; $this->output =& $output; $this->output->set_helptopic('areamanager'); $chore = get_parameter_string('chore', AREAMANAGER_CHORE_VIEW); switch ($chore) { case AREAMANAGER_CHORE_VIEW: $this->area_overview(); break; case AREAMANAGER_CHORE_ADD: $this->area_add(); break; case AREAMANAGER_CHORE_SET_DEFAULT: $this->area_setdefault(); break; case AREAMANAGER_CHORE_DELETE: $this->area_delete(); break; case AREAMANAGER_CHORE_EDIT: $this->area_edit(); break; case AREAMANAGER_CHORE_EDIT_THEME: $this->area_edittheme(); break; case AREAMANAGER_CHORE_RESET_THEME: $this->area_resettheme(); break; case AREAMANAGER_CHORE_SAVE_NEW: $this->area_savenew(); break; case AREAMANAGER_CHORE_SAVE: $this->area_save(); break; default: $s = utf8_strlen($chore) <= 50 ? $chore : utf8_substr($chore, 0, 44) . ' (...)'; $message = t('chore_unknown', 'admin', array('{CHORE}' => htmlspecialchars($s))); $output->add_message($message); logger('areamanager: unknown chore: ' . htmlspecialchars($s)); $this->area_overview(); break; } }
/** main entry point for modulemanager (called from /program/main_admin.php) * * this routine dispatches the tasks, If the specified task * is not recognised, the default task TASK_MODULEMANAGER_INTRO * is executed. * * @param object &$output collects the html output * @return void results are returned as output in $output */ function job_modulemanager(&$output) { $output->set_helptopic('modulemanager'); $task = get_parameter_string('task', TASK_MODULEMANAGER_INTRO); switch ($task) { case TASK_MODULEMANAGER_INTRO: modulemanager_show_intro($output); modulemanager_show_menu($output); break; case TASK_MODULEMANAGER_EDIT: case TASK_MODULEMANAGER_SAVE: modulemanager_process($output, $task); break; default: $s = utf8_strlen($task) <= 50 ? $task : utf8_substr($task, 0, 44) . ' (...)'; $message = t('task_unknown', 'admin', array('{TASK}' => htmlspecialchars($s))); $output->add_message($message); logger('modulemanager: unknown task: ' . htmlspecialchars($s)); modulemanager_show_intro($output); modulemanager_show_menu($output); break; } }
/** main program for visitors * * this routine is called from /index.php. It is the main program for visitors. * * @return void page sent to the browser * @todo cleanup login/logout-code */ function main_index() { global $USER; global $CFG; global $LANGUAGE; /** initialise the program, setup database, read configuration, etc. */ require_once $CFG->progdir . '/init.php'; initialise(); was_version_check(); // this never returns if versions don't match // TODO: cleanup like in main_admin() // handle login/logout/continuation so we quickly find out which user is calling if (isset($_GET['logout'])) { /** loginlib.php contains both login- and logout-routines */ require_once $CFG->progdir . '/lib/loginlib.php'; was_logout(); // may or may not return here } elseif (isset($_GET['login'])) { /** loginlib.php contains both login- and logout-routines */ require_once $CFG->progdir . '/lib/loginlib.php'; was_login(magic_unquote($_GET['login'])); // may or may not return here } elseif (isset($_COOKIE[$CFG->session_name])) { /** dbsessionlib.php contains our own database based session handler */ require_once $CFG->progdir . '/lib/dbsessionlib.php'; dbsession_setup($CFG->session_name); if (dbsession_exists(magic_unquote($_COOKIE[$CFG->session_name]))) { session_start(); } } // At this point we either have a valid session with a logged-in user // (indicated via existence of $_SESSION) or we are dealing with an anonymous // visitor with non-existing $_SESSION. Keep track of the number of calls // this user makes (may be logged lateron on logout). if (isset($_SESSION)) { if (!isset($_SESSION['session_counter'])) { // first time after login, record start time of session $_SESSION['session_counter'] = 1; $_SESSION['session_start'] = strftime("%Y-%m-%d %T"); } else { $_SESSION['session_counter']++; } } // Now is the time to create a USER object, even when the visitor is just a passerby // because we can then determine easily if a visitor is allowed certain things, e.g. // view a protected area or something /** useraccount.class.php is used to define the USER object */ require_once $CFG->progdir . '/lib/useraccount.class.php'; if (isset($_SESSION) && isset($_SESSION['user_id'])) { $USER = new Useraccount($_SESSION['user_id']); $USER->is_logged_in = TRUE; $_SESSION['language_key'] = $LANGUAGE->get_current_language(); // remember language set via _GET or otherwise } else { $USER = new Useraccount(); $USER->is_logged_in = FALSE; } // Check for the special preview-mode // This allows a webmaster to preview a page in the correct environment (theme) // even when the page is under embargo. Note that the node_id and area_id are // retrieved from the session; the user only has a cryptic preview-code. // See pagemanagerlib.php for more information (function task_page_preview()). $in_preview_mode = FALSE; if ($USER->is_logged_in) { $preview_code_from_url = get_parameter_string('preview'); if (!is_null($preview_code_from_url) && isset($_SESSION['preview_salt']) && isset($_SESSION['preview_node'])) { $hash = md5($_SESSION['preview_salt'] . $_SESSION['preview_node']); if ($hash === $preview_code_from_url) { $node_id = intval($_SESSION['preview_node']); $area_id = intval($_SESSION['preview_area']); $area = db_select_single_record('areas', '*', array('area_id' => $area_id)); if ($area === FALSE) { logger("Fatal error 070: cannot preview node '{$node_id}' in area '{$area_id}'"); error_exit('070'); } else { $tree = tree_build($area_id); $in_preview_mode = TRUE; } } } } if ($in_preview_mode == FALSE) { $requested_area = get_requested_area(); $requested_node = get_requested_node(); $req_area_str = is_null($requested_area) ? "NULL" : strval($requested_area); $req_node_str = is_null($requested_node) ? "NULL" : strval($requested_node); if (($area = calculate_area($requested_area, $requested_node)) === FALSE) { logger("Fatal error 080: no valid area (request: area='{$req_area_str}', node='{$req_node_str}')"); error_exit('080'); // no such area } $area_id = intval($area['area_id']); // If $USER has no permission to view area $area_id, we simply bail out. // Rationale: if the user is genuine, she knows about logging in first. // If the user is NOT logged in and tries to view a protected area, I'd consider // it malicious, and in that case I won't even confirm the existence of // the requested area. (If a cracker simply tries areas 0,1,.. and sometimes is greeted // with 'please enter credentials' and sometimes with 'area does not exist', this // provides information to the cracker. I don't want that). Note that the error code // is the same as the one for non-existing area. In other words: for an unauthorised // visitor an existing private area is just as non-existent as a non-existing public area. if (db_bool_is(TRUE, $area['is_private']) && !$USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $area_id)) { logger(sprintf("Fatal error 080: no view permissions for area '%d' (request: area='%s', node='%s')", $area_id, $req_area_str, $req_node_str)); error_exit('080'); // no such area } // still here? // then we've got a valid $area_id and corresponding $area record. // now we need to figure out which $node_id to use $tree = tree_build($area_id); if (($node_id = calculate_node_id($tree, $area_id, $requested_node)) === FALSE) { logger(sprintf("Fatal error 080: no valid node within area '%d' (request: area='%s', node='%s')", $area_id, $req_area_str, $req_node_str)); error_exit('080'); // no such area } } // At this point we have the following in our hands // - a valid $area_id // - a valid $node_id // - the complete tree from area $area_id in $tree // - the area record from database in $area // - the node record from database in $tree[$node_id]['record'] // - a flag that signals preview mode in $in_preview_mode // We are on our way to generate a full page with content and all, // but otoh we MIGHT be in the middle of a redirect, so we may have to // leave without showing anything at all... if (!empty($tree[$node_id]['record']['link_href'])) { update_statistics($node_id); if (isset($_SESSION)) { session_write_close(); } redirect_and_exit(htmlspecialchars($tree[$node_id]['record']['link_href'])); // exit; redirect_and_exit() never returns } /** themelib contains the theme factory */ require_once $CFG->progdir . '/lib/themelib.php'; // And now we know about the $area, we can carry on determining which $theme to use. // $theme = theme_factory($area['theme_id'], $area_id, $node_id); if ($theme === FALSE) { logger("Fatal error 090: cannot setup theme '{$area['theme_id']}' in area '{$area_id}'"); error_exit('090'); } // Tell the theme about the preview mode $theme->set_preview_mode($in_preview_mode); // Now all we need to do is let the module connected to node $node_id generate output $module_id = $tree[$node_id]['record']['module_id']; module_view($theme, $area_id, $node_id, $module_id); // Remember this visitor update_statistics($node_id); // Finally, send output to user $theme->send_output(); if (isset($_SESSION)) { session_write_close(); } // done! exit; }
/** show an introductory text for backup tool OR stream a ZIP-file to the browser * * If we arrive here via the tools menu, the parameter download is not set. * In that case we show an introductory text with a link that yields a ZIP-file * with the backup. * * If the user follows the download link, we arrive here too but with the download * parameter set. We then dump the database in a variable and subsequently * compress it in a ZIP-file which we stream to the browser. We do code some * things in the basename of the backup: * - the hostname * - the database name * - the database prefix * - the date and the time * which should be enough to distinguish nearly all backups if you happen to have a * lot of different ones. Note that the URL is also encoded as a comment in the .ZIP. * * The parameter download is currently set to 'zip'. However, we do attempt to send the * plain uncompressed data if that parameter is set to 'sql' (quick and dirty). Oh well. * hopefully there is enough memory to accomodate backups of moderate sized sites. * * Note that we need space to compress the data; a informal test yielded that we need * about 160% of the uncompressed size of the backup (tested with a small testset). * Rule of the thumb for memory: the more the merrier but at least twice the size of the * uncompressed backup. * * @param object &$output collects output to show to user * @return output displayed via $output OR ZIP-file streamed to the browser */ function task_backuptool(&$output) { global $DB, $CFG, $WAS_SCRIPT_NAME; $download = get_parameter_string('download', NULL); if (is_null($download)) { $output->set_helptopic('backuptool'); $output->add_content("<h2>" . t('backuptool_header', 'admin') . "</h2>"); $params = array('{DATADIRECTORY}' => htmlspecialchars($CFG->datadir)); $output->add_content(t('backuptool_intro', 'admin', $params)); $output->add_content('<p>'); $parameters = array('job' => JOB_TOOLS, 'task' => TASK_BACKUPTOOL, 'download' => 'zip'); $attributes = array('title' => t('backuptool_download_title', 'admin')); $anchor = t('backuptool_download', 'admin'); $output->add_content(html_a($WAS_SCRIPT_NAME, $parameters, $attributes, $anchor)); show_tools_menu($output, TASK_BACKUPTOOL); return; } // Try to construct a suitable hostname as part of the filename. $host = ''; if (($url = parse_url($CFG->www)) !== FALSE) { $host = isset($url['host']) ? trim(ereg_replace('[^a-zA-Z0-9.-]', '', $url['host']), '.') : ''; } if (empty($host) && isset($_SERVER['SERVER_NAME'])) { $host = trim(ereg_replace('[^a-zA-Z0-9.-]', '', $_SERVER['SERVER_NAME']), '.'); } if (empty($host)) { $host = 'localhost'; // last resort } // basename = host "-" database "-" prefix "-" timestamp (only acceptable chars for filename; strip fancy chars) $basename = $host . '-' . trim(ereg_replace('[^a-zA-Z0-9._-]', '', $CFG->db_name), '-_.') . '-' . trim(ereg_replace('[^a-zA-Z0-9._-]', '', $CFG->prefix), '-_.') . '-' . strftime('%Y%m%d-%H%M%S'); $archive = $basename . '.zip'; $backup = $basename . '.sql'; $data = ''; logger(sprintf('%s(): start creating/streaming backup %s', __FUNCTION__, $basename), WLOG_DEBUG); if ($DB->dump($data)) { $data_length = strlen($data); logger(sprintf('%s(): backup file %s is %d bytes', __FUNCTION__, $backup, $data_length), WLOG_DEBUG); if ($download == 'sql') { header('Content-Type: text/x-sql'); header(sprintf('Content-Disposition: attachment; filename="%s"', $backup)); logger(sprintf('%s(): about to stream %d bytes (backup = %s)', __FUNCTION__, $data_length, $backup), WLOG_DEBUG); echo $data; logger(sprintf('%s(): success streaming data %s (%d bytes uncompressed)', __FUNCTION__, $backup, $data_length)); exit; } else { include_once $CFG->progdir . '/lib/zip.class.php'; $zip = new Zip(); $comment = $CFG->www; if ($zip->OpenZipstream($archive, $comment)) { if ($zip->AddData($data, $backup)) { if ($zip->CloseZip()) { logger(sprintf('%s(): success streaming backup %s (%d bytes uncompressed)', __FUNCTION__, $archive, $data_length)); } else { logger(sprintf('%s(): cannot close zipstream %s: %s', __FUNCTION__, $archive, $zip->Error)); } } else { logger(sprintf('%s(): cannot add backup data to zipstream %s: %s', __FUNCTION__, $archive, $zip->Error)); $zip->CloseZip(); } // ZipStream is done, no point in adding garbage at the end of that file, quit completely exit; } else { logger(sprintf('%s(): cannot open zipstream %s for backup: %s', __FUNCTION__, $archive, $zip->Error)); } } } else { logger(sprintf('%s(): cannot open dump data for backup: %s', __FUNCTION__, db_errormessage())); } $output->add_message(t('backuptool_error', 'admin')); show_tools_menu($output); show_tools_intro($output); }
/** main entry point for update wizard (called from /program/main_admin.php) * * This routine takes care of executing update routines for both the core * program and modules, themes, etc. It is called automagically whenever * the core program version in the database is different from the version * in the file {@lnk version.php} (see also {@link main_admin()}). * * It can also be called manually via 'job=update'. When no specific * task is specified, this routine shows the overview of versions for * core, modules, themes, etc. Whenever a component is NOT up to date, * an [Update] button is displayed. If a component IS up to date, we * simply display the word 'OK'. This implies that when everything is up * to date, the overview simply displays a list of OK's and the user * is 'free to go'. * * The actual updates for modules, themes, etc. is done via the various * subsystems themselves, e.g. by calling htmlpage_upgrade() in the file * /program/modules/htmlpage/htmlpage_install.php. The updates for the * core program are actually performed from this file right here, see * {@link update_core_2010120800()} below for an example. * * Note that we give a core update high priority: if the core * is not up to date, nothing will work, except updating the core. * * @param object &$output collects the html output * @return void results are returned as output in $output */ function job_update(&$output) { global $CFG, $WAS_SCRIPT_NAME, $USER; $output->set_helptopic('update'); $task = get_parameter_string('task', TASK_UPDATE_OVERVIEW); if ($task == TASK_UPDATE_OVERVIEW) { update_show_overview($output); } elseif ($task == TASK_UPDATE_CORE) { update_core($output); update_show_overview($output); } elseif (intval($CFG->version) != intval(WAS_VERSION)) { $output->add_message(t('update_core_warnning_core_goes_first', 'admin')); update_show_overview($output); } else { $key = get_parameter_string('key', ''); switch ($task) { case TASK_INSTALL_LANGUAGE: install_language($output, $key); update_show_overview($output); break; case TASK_UPDATE_LANGUAGE: update_language($output, $key); update_show_overview($output); break; case TASK_INSTALL_MODULE: install_module($output, $key); update_show_overview($output); break; case TASK_UPDATE_MODULE: update_module($output, $key); update_show_overview($output); break; case TASK_INSTALL_THEME: install_theme($output, $key); update_show_overview($output); break; case TASK_UPDATE_THEME: update_theme($output, $key); update_show_overview($output); break; default: $s = utf8_strlen($task) <= 50 ? $task : utf8_substr($task, 0, 44) . ' (...)'; $message = t('task_unknown', 'admin', array('{TASK}' => htmlspecialchars($s))); $output->add_message($message); logger('tools: unknown task: ' . htmlspecialchars($s)); update_show_overview($output); break; } } }
/** create a new subdirectory * * This routine either shows a dialog where the user can specify the name of a new * directory to add OR processes the dialog. * * In case of directory name too short, already exists, etc. the user is * returned to the dialog to try again. If all goes well the new directory * is created and at the same time the empty file 'index.html' is created * to "protect" the directory from prying eyes. * * @return void output returned via $this->output */ function task_add_directory() { global $WAS_SCRIPT_NAME, $CFG; // 1A -- bail out if user pressed cancel button if (isset($_POST['button_cancel'])) { $this->output->add_message(t('cancelled', 'admin')); $this->task_list_directory(); return; } // 1B -- Check validity of working directory, maybe bail out $newdir = get_parameter_string(PARAM_PATH, $this->current_directory); if (($path = $this->valid_path($newdir)) === FALSE) { $this->output->add_message(t('invalid_path', 'admin', array('{PATH}' => htmlspecialchars($newdir)))); $this->task_list_directory(); return; } $this->current_directory = $path; // this is where we will create the new subdirectory // 2 -- prepare dialog (either to show it or to validate it) $dialogdef = array('subdirectory' => array('type' => F_ALPHANUMERIC, 'name' => 'subdirectory', 'minlength' => 1, 'maxlength' => 240, 'columns' => 30, 'label' => t('filemanager_add_subdirectory_label', 'admin'), 'title' => t('filemanager_add_subdirectory_title', 'admin'), 'value' => ''), 'button_save' => dialog_buttondef(BUTTON_SAVE), 'button_cancel' => dialog_buttondef(BUTTON_CANCEL)); $a_params = array('job' => $this->job, 'task' => TASK_ADD_DIRECTORY, PARAM_PATH => $path); $href = href($WAS_SCRIPT_NAME, $a_params); // 3 -- show dialog or validate + process? if (!isset($_POST['subdirectory'])) { $this->output->add_content('<h2>' . t('filemanager_add_subdirectory_header', 'admin') . '</h2>'); $this->output->add_content(t('filemanager_add_subdirectory_explanation', 'admin')); $this->output->add_content(dialog_quickform($href, $dialogdef)); $this->show_breadcrumbs($path); $this->show_menu($path); return; } // 4 -- validate user input and maybe create directory // 4A -- check for generic errors $invalid = FALSE; if (!dialog_validate($dialogdef)) { $invalid = TRUE; } // 4B -- check for additional errors: sane filename $subdirectory = $dialogdef['subdirectory']['value']; $sanitised_subdirectory = sanitise_filename($subdirectory); if ($subdirectory != $sanitised_subdirectory || substr($sanitised_subdirectory, 0, strlen(THUMBNAIL_PREFIX)) == THUMBNAIL_PREFIX) { ++$dialogdef['subdirectory']['errors']; $params = array('{FIELD}' => str_replace('~', '', $dialogdef['subdirectory']['label']), '{VALUE}' => htmlspecialchars($subdirectory)); $dialogdef['subdirectory']['error_messages'][] = t('validate_bad_filename', '', $params); $invalid = TRUE; } // 4C -- check for additional errors: directory should not exist already $subdirectory_full_path = $CFG->datadir . $path . '/' . $sanitised_subdirectory; if (file_exists($subdirectory_full_path)) { ++$dialogdef['subdirectory']['errors']; $params = array('{FIELD}' => str_replace('~', '', $dialogdef['subdirectory']['label']), '{VALUE}' => $this->vpath($path) . '/' . $sanitised_subdirectory); $dialogdef['subdirectory']['error_messages'][] = t('validate_already_exists', '', $params); $invalid = TRUE; } // 4D -- redo dialog if there were errors if ($invalid) { // shortcut: only the subdirectory field can (and does) yield errors $this->output->add_message($dialogdef['subdirectory']['error_messages']); $dialogdef['subdirectory']['value'] = $sanitised_subdirectory; $this->output->add_content('<h2>' . t('filemanager_add_subdirectory_header', 'admin') . '</h2>'); $this->output->add_content(t('filemanager_add_subdirectory_explanation', 'admin')); $this->output->add_content(dialog_quickform($href, $dialogdef)); $this->show_breadcrumbs($path); // note that we do NOT display the menu here; let the user concentrate (or press Cancel) this time return; } // 5 -- all set, go create subdir $params = array('{PATH}' => htmlspecialchars($this->vpath($path)), '{DIRECTORY}' => htmlspecialchars($sanitised_subdirectory)); if (@mkdir($subdirectory_full_path, 0700)) { @touch($subdirectory_full_path . '/index.html'); // "protect" the newly created directory from prying eyes $this->output->add_message(t('filemanager_add_subdirectory_success', 'admin', $params)); logger(sprintf('%s.%s(): success with mkdir %s', __CLASS__, __FUNCTION__, $path . '/' . $subdirectory), WLOG_DEBUG); } else { $this->output->add_message(t('filemanager_add_subdirectory_failure', 'admin', $params)); logger(sprintf('%s.%s(): cannot mkdir %s', __CLASS__, __FUNCTION__, $path . '/' . $subdirectory)); } $this->task_list_directory(); }
/** handle the editing/saving of the main configuration information * * this routine handles editing of the main configuration parameters. * It either displays the edit dialog or saves the modified data and * shows the configuration manager introduction screen. * * Note that we do NOT try to redirect the user via a header() after * a succesful save. It would be handy because this particular * save action may have had impact on the global configuration, * which is already read at this point. By redirecting we would * make a fresh start, with the new parameters. * However, we lose the easy ability to tell the user that the data * was saved (via $output->add_message()). So, either no feedback * or obsolete global config in core. Hmmmm. I settle for the feedback * and the 'wrong' settings. * * @param object &$output collects the html output * @return void results are returned as output in $output * @uses ConfigAssistant() */ function process_task_site(&$output) { global $CFG, $WAS_SCRIPT_NAME; // 1 -- prepare include_once $CFG->progdir . '/lib/configassistant.class.php'; $table = 'config'; $keyfield = 'name'; $prefix = 'site_config_'; $domain = 'admin'; $where = ''; $assistant = new ConfigAssistant($table, $keyfield, $prefix, $domain, $where); $href = href($WAS_SCRIPT_NAME, array('job' => JOB_CONFIGURATIONMANAGER, 'task' => TASK_SITE, 'chore' => CHORE_SAVE)); // 2 -- what do we need to do? $chore = get_parameter_string('chore'); if ($chore == CHORE_SAVE) { // save data (or cancel if they want to cancel) if (isset($_POST['button_save'])) { if ($assistant->save_data($output)) { //if (!headers_sent()) { // header('Location: '.href($WAS_SCRIPT_NAME,array('job' => JOB_CONFIGURATIONMANAGER))); // exit; //} else { show_configuration_intro($output); show_configuration_menu($output); //} } else { $output->add_content('<h2>' . t($prefix . 'header', 'admin') . '</h2>'); $output->add_content(t($prefix . 'explanation', 'admin')); $assistant->show_dialog($output, $href); } } else { $output->add_message(t('cancelled', 'admin')); show_configuration_intro($output); show_configuration_menu($output); } } else { // no save yet, simply show dialog $output->add_content('<h2>' . t($prefix . 'header', 'admin') . '</h2>'); $output->add_content(t($prefix . 'explanation', 'admin')); $assistant->show_dialog($output, $href); show_configuration_menu($output, TASK_SITE); } }
/** determine the default skin to use * * This routine determines which skin to use in AdminOutput. * It always returns a valid skin (using 'base' in case of error). * * @uses $USER; * @uses $_SESSION; * @return string a valid skin name */ function get_current_skin() { global $USER; $skins = array('base', 'textonly', 'braille', 'big', 'lowvision'); $skin = get_parameter_string('skin', isset($_SESSION['skin']) ? $_SESSION['skin'] : $USER->skin); return in_array($skin, $skins) ? $skin : 'base'; }
/** construct a PageManager object (called from /program/main_admin.php) * * This initialises the PageManager, checks user permissions and * finally dispatches the tasks. If the specified task is not * recognised, the default task TASK_TREEVIEW is executed. * * Note that allmost all commands act on the area contained in the * SESSION-variable current_area_id. Also, we almost always need * the tree of nodes in that area, so we read it once, _before_ * dispatching the task at hand. This means that the current tree * in the current area is ALWAYS available. This means that none of * the other routines should have to worry about which area or * reading the tree; this information is already available in * $this->area_id and $this->tree. * * * @param object &$output collects the html output * @return void results are returned as output in $this->output */ function PageManager(&$output) { global $USER; $this->output =& $output; $this->output->set_helptopic('pagemanager'); $this->areas = get_area_records(); // Do not maintain a 'current area' if it is no longer there (it might have been deleted by us or another admin) if (isset($_SESSION['current_area_id']) && !isset($this->areas[intval($_SESSION['current_area_id'])])) { unset($_SESSION['current_area_id']); } // Do we have a valid working area? If not, try to calculate one if (!isset($_SESSION['current_area_id']) || !isset($_SESSION['tree_mode']) || !isset($_SESSION['expanded_nodes'])) { // 1 -- Try the specified area aaa from command line (admin.php?area=aaa) $area_id = get_parameter_int('area', FALSE); if ($area_id !== FALSE) { if (!$USER->is_admin_pagemanager($area_id) || !isset($this->areas[$area_id])) { logger(__FUNCTION__ . "(): weird: user '{$USER->username}' tried to access area '{$area_id}'"); $message = t('area_admin_access_denied', 'admin', array('{AREA}' => strval($area_id))); $area_id = FALSE; // sentinel } } else { // 2 -- try use the first available area for which the user has permissions... $message = t('no_areas_available', 'admin'); // ... but assume the worst foreach ($this->areas as $id => $area) { if ($USER->is_admin_pagemanager($id)) { $area_id = $id; break; } } } if ($area_id === FALSE) { $this->output->add_message($message); $this->output->add_content($message); $this->show_area_menu(); return; } else { $_SESSION['current_area_id'] = $area_id; $_SESSION['expanded_nodes'] = array(); $_SESSION['tree_mode'] = TREE_VIEW_MINIMAL; } } else { // Do we (still) have enough permissions for the current area? $area_id = intval($_SESSION['current_area_id']); if (!$USER->is_admin_pagemanager($area_id) || !isset($this->areas[$area_id])) { // this is completely weird: the session has an invalid area? tsk tsk tsk logger(__FUNCTION__ . "(): weird: user '{$USER->username}' can no longer access area '{$area_id}'?"); $message = t('area_admin_access_denied', 'admin', array('{AREA}' => strval($area_id))); $this->output->add_message($message); $this->output->add_content($message); $this->show_area_menu(); return; } } // // At this point we have 3 valid variables in $_SESSION indicating // the current working area and the open/closed state of sections. // We now should read the corresponding tree in core and look which // task we need to perform. // $this->build_cached_tree(intval($_SESSION['current_area_id'])); $task = get_parameter_string('task', TASK_TREEVIEW); switch ($task) { case TASK_TREEVIEW: $this->task_treeview(); break; case TASK_TREEVIEW_SET: $this->task_treeview_set(); break; case TASK_SUBTREE_EXPAND: $this->task_subtree_expand(); break; case TASK_SUBTREE_COLLAPSE: $this->task_subtree_collapse(); break; case TASK_SET_DEFAULT: $this->task_set_default(); break; case TASK_ADD_PAGE: case TASK_ADD_SECTION: $this->task_node_add($task); break; case TASK_NODE_DELETE: $this->task_node_delete(); break; case TASK_NODE_EDIT: case TASK_NODE_EDIT_ADVANCED: $this->task_node_edit($task); break; case TASK_NODE_EDIT_CONTENT: $this->task_node_edit_content(); break; case TASK_SAVE_CONTENT: $this->task_save_content(); break; case TASK_PAGE_PREVIEW: $this->task_page_preview(); break; case TASK_SAVE_NODE: $this->task_save_node(); break; case TASK_SAVE_NEWPAGE: case TASK_SAVE_NEWSECTION: $this->task_save_newnode($task); break; default: $s = utf8_strlen($task) <= 50 ? $task : utf8_substr($task, 0, 44) . ' (...)'; $message = t('task_unknown', 'admin', array('{TASK}' => htmlspecialchars($s))); $this->output->add_message($message); logger(__FUNCTION__ . '(): unknown task: ' . htmlspecialchars($s)); $this->task_treeview(); break; } }
/** construct a GroupManager object * * This initialises the GroupManager and also dispatches the task to do. * * @param object &$output collects the html output */ function GroupManager(&$output) { global $CFG; $this->output =& $output; $this->output->set_helptopic('groupmanager'); $this->groups = array(); $task = get_parameter_string('task', TASK_GROUPS); switch ($task) { case TASK_GROUPS: $this->groups_overview(); break; case TASK_GROUP_ADD: $this->group_add(); break; case TASK_GROUP_SAVE_NEW: $this->group_savenew(); break; case TASK_GROUP_EDIT: $this->group_edit(); break; case TASK_GROUP_SAVE: $this->group_save(); break; case TASK_GROUP_DELETE: $this->group_delete(); break; case TASK_GROUP_CAPACITY_OVERVIEW: $this->capacity_overview(); break; case TASK_GROUP_CAPACITY_INTRANET: $this->capacity_intranet(); break; case TASK_GROUP_CAPACITY_ADMIN: $this->capacity_admin(); break; case TASK_GROUP_CAPACITY_PAGEMANAGER: $this->capacity_pagemanager(); break; case TASK_GROUP_CAPACITY_SAVE: $this->capacity_save(); break; case TASK_GROUP_CAPACITY_MODULE: $this->output->add_message("STUB: task '{$task}' not yet implemented"); $this->output->add_message('group = ' . get_parameter_string('group', '(unset)')); $this->output->add_message('capacity = ' . get_parameter_string('capacity', '(unset)')); $this->output->add_message('module = ' . get_parameter_string('module', '(unset)')); $this->groups_overview(); break; default: $s = utf8_strlen($task) <= 50 ? $task : utf8_substr($task, 0, 44) . ' (...)'; $message = t('task_unknown', 'admin', array('{TASK}' => htmlspecialchars($s))); $output->add_message($message); logger(sprintf('%s.%s(): unknown task: \'%s\'', __CLASS__, __FUNCTION__, htmlspecialchars($s))); $this->groups_overview(); break; } }
/** main entry point for accountmanager (called from admin.php) * * this routing dispatches the tasks. If a specified task is not * recognised, the default task TASK_ACCOUNTS_OVERVIEW is * executed. Note that the User Manager and the Group Manager * are heavily interconnected. Therefore we use 1 common set * of tasks and distinguish between both managers via * sets of tasks, e.g. TASK_USER* point to the user manager * where TASK_GROUP* lead to the group manager. * * @param object &$output collects the html output * @return void results are returned as output in $output */ function job_accountmanager(&$output) { global $CFG; $output->set_helptopic('accountmanager'); $task = get_parameter_string('task', TASK_ACCOUNTS); switch ($task) { case TASK_ACCOUNTS: show_accounts_intro($output); show_accounts_menu($output); break; case TASK_USERS: case TASK_USER_ADD: case TASK_USER_DELETE: case TASK_USER_EDIT: case TASK_USER_ADVANCED: case TASK_USER_GROUPS: case TASK_USER_GROUPADD: case TASK_USER_GROUPDELETE: case TASK_USER_GROUPSAVE: case TASK_USER_INTRANET: case TASK_USER_MODULE: case TASK_USER_ADMIN: case TASK_USER_PAGEMANAGER: case TASK_USER_TREEVIEW: case TASK_USER_SAVE: case TASK_USER_SAVE_NEW: include $CFG->progdir . '/lib/usermanager.class.php'; $mgr = new UserManager($output); if ($mgr->show_parent_menu()) { show_accounts_menu($output, TASK_USERS); } break; case TASK_GROUPS: case TASK_GROUP_ADD: case TASK_GROUP_DELETE: case TASK_GROUP_EDIT: case TASK_GROUP_SAVE: case TASK_GROUP_SAVE_NEW: include $CFG->progdir . '/lib/groupmanager.class.php'; $mgr = new GroupManager($output); if ($mgr->show_parent_menu()) { show_accounts_menu($output, TASK_GROUPS); } break; case TASK_GROUP_CAPACITY_OVERVIEW: case TASK_GROUP_CAPACITY_INTRANET: case TASK_GROUP_CAPACITY_MODULE: case TASK_GROUP_CAPACITY_ADMIN: case TASK_GROUP_CAPACITY_PAGEMANAGER: case TASK_GROUP_CAPACITY_SAVE: include $CFG->progdir . '/lib/groupmanager.class.php'; $mgr = new GroupManager($output); if ($mgr->show_parent_menu()) { show_accounts_menu($output, TASK_GROUPS); } break; default: $s = utf8_strlen($task) <= 50 ? $task : utf8_substr($task, 0, 44) . ' (...)'; $message = t('task_unknown', 'admin', array('{TASK}' => htmlspecialchars($s))); $output->add_message($message); logger('accountmanager: unknown task: ' . htmlspecialchars($s)); show_accounts_intro($output); show_accounts_menu($output); break; } }
/** construct a UserManager object * * This initialises the UserManager and also dispatches the task to do. * This also loads the loginlib: we need that in order to manipulate the user password. * * @param object &$output collects the html output */ function UserManager(&$output) { global $CFG; $this->output =& $output; $this->output->set_helptopic('usermanager'); $this->users = array(); require_once $CFG->progdir . '/lib/loginlib.php'; $task = get_parameter_string('task', TASK_USERS); switch ($task) { case TASK_USERS: $this->users_overview(); break; case TASK_USER_ADD: $this->user_add(); break; case TASK_USER_SAVE_NEW: $this->user_savenew(); break; case TASK_USER_DELETE: $this->user_delete(); break; case TASK_USER_EDIT: $this->user_edit(); break; case TASK_USER_SAVE: $this->user_save(); break; case TASK_USER_GROUPS: $this->user_groups(); break; case TASK_USER_GROUPADD: $this->user_groupadd(); break; case TASK_USER_GROUPSAVE: $this->user_groupsave(); break; case TASK_USER_GROUPDELETE: $this->user_groupdelete(); break; case TASK_USER_INTRANET: $this->user_intranet(); break; case TASK_USER_ADMIN: $this->user_admin(); break; case TASK_USER_PAGEMANAGER: $this->user_pagemanager(); break; case TASK_USER_ADVANCED: case TASK_USER_TREEVIEW: case TASK_USER_MODULE: $this->output->add_message('STUB: not implemented: ' . $task); $this->output->add_message('user = '******'user', '(unset)')); $this->show_parent_menu = TRUE; // STUB break; default: $s = utf8_strlen($task) <= 50 ? $task : utf8_substr($task, 0, 44) . ' (...)'; $message = t('task_unknown', 'admin', array('{TASK}' => htmlspecialchars($s))); $output->add_message($message); logger('usermanager: unknown task: ' . htmlspecialchars($s)); $this->users_overview(); break; } }
/** save the modified translations in a file in the tree CFG->datadir/languages/ * * this routine validates the dialog data and attempts to save the changes in the file * $full_domain in the directory CFG->datadir/languages/$language_key/. Also, we may * need to send a message to the Website@School project with our changes (depending * on the flag _submit). * * @return void data saved and output written to browser via $this->output */ function translation_save() { global $WAS_SCRIPT_NAME, $LANGUAGE; $language_key = get_parameter_string(TRANSLATETOOL_PARAM_LANGUAGE_KEY); // 1A -- basic sanity for language if ($this->languages === FALSE || !isset($this->languages[$language_key])) { logger(sprintf('%s.%s(): weird: user tried to edit translations for non-existing language \'%s\'', __CLASS__, __FUNCTION__, htmlspecialchars($language_key))); $params = array('{LANGUAGE_KEY}' => htmlspecialchars($language_key)); $this->output->add_message(t('invalid_language', 'admin', $params)); $this->languages_overview(); return; } $full_domain = get_parameter_string(TRANSLATETOOL_PARAM_DOMAIN, 'was'); // 1B -- basic sanity for domain if (!isset($this->domains[$full_domain])) { logger(sprintf('%s.%s(): weird: user requested non-existing domain \'%s\'', __CLASS__, __FUNCTION__, htmlspecialchars($full_domain))); $params = array('{FULL_DOMAIN}' => htmlspecialchars($full_domain)); $this->output->add_message(t('invalid_language_domain', 'admin', $params)); $this->languages_overview(); return; } // 2 -- if the user cancelled the operation, there is no point in hanging 'round if (isset($_POST['button_cancel'])) { $this->output->add_message(t('cancelled', 'admin')); $this->languages_overview(); return; } // 3 -- validate the dialog and maybe redo it $dialogdef = $this->get_dialogdef_language_domain($language_key, $full_domain); if (!dialog_validate($dialogdef)) { // there were errors, show them to the user and do it again foreach ($dialogdef as $k => $item) { if (isset($item['errors']) && $item['errors'] > 0) { $this->output->add_message($item['error_messages']); } } $example_html = '<strong>'; $example_variable = '{VALUE}'; $example_tilde = '~'; $examples = array('{EXAMPLE_HTML}' => $this->code_highlight($example_html), '{EXAMPLE_VARIABLE}' => $this->code_highlight($example_variable), '{EXAMPLE_TILDE}' => $this->code_highlight($example_tilde)); $params = array('{LANGUAGE_KEY}' => $language_key, '{LANGUAGE_NAME}' => $this->languages[$language_key]['language_name'], '{FULL_DOMAIN}' => $this->domains[$full_domain]['title']); $this->output->add_content('<h2>' . t('translatetool_edit_language_domain_header', 'admin', $params) . '</h2>'); $this->output->add_content(t('translatetool_edit_language_domain_explanation', 'admin', $examples)); $this->output->add_content('<p>'); $href = href($WAS_SCRIPT_NAME, $this->a_param(TRANSLATETOOL_CHORE_SAVE, $language_key, $full_domain)); $this->output->add_content($this->render_translation_dialog($href, $dialogdef)); // no menu this time, let user concentrate on task at hand ie errorfree data input return; } // 4 -- actually proceed with saving the data // 4A -- construct a diff between the system translation (if any) and the dialogdef values $strings = array(); $dummy = array(); $diff = array(); $this->get_strings_system($language_key, $full_domain, $strings, $dummy); foreach ($dialogdef as $name => $item) { if (!isset($item['key']) || $item['type'] == F_SUBMIT) { // skip buttons and 'meta'-fields continue; } $key = $item['key']; # massage $value and standardise on \n as EOL $value = str_replace("\r\n", "\n", $item['value']); $value = str_replace("\n\r", "\n", $value); $value = str_replace("\r", "\n", $value); if (!isset($strings[$key]) || $strings[$key] != $value) { $diff[$key] = $value; } } // 4B -- if the diff is non-empty, go write and maybe submit it $params = array('{LANGUAGE_KEY}' => $language_key, '{LANGUAGE_NAME}' => $this->languages[$language_key]['language_name'], '{FULL_DOMAIN}' => $this->domains[$full_domain]['title']); $diff_count = sizeof($diff); if ($diff_count == 0) { // No changes need to be saved $this->output->add_message(t('translatetool_no_changes_to_save', 'admin', $params)); } else { $diff['_submit'] = $dialogdef['_submit']['value'] == '1' ? '1' : '0'; $diff['_full_name'] = $dialogdef['_full_name']['value']; $diff['_email'] = $dialogdef['_email']['value']; $diff['_notes'] = $dialogdef['_notes']['value']; $retval = $this->put_strings_userfile($language_key, $full_domain, $diff); if (!$retval) { logger(sprintf('%s.%s(): could not write translation file for %s - %s (%d items)', __CLASS__, __FUNCTION__, $language_key, $full_domain, $diff_count)); } else { logger(sprintf('%s.%s(): success writing translation file for %s - %s: %d items', __CLASS__, __FUNCTION__, $language_key, $full_domain, $diff_count), WLOG_DEBUG); if (db_bool_is(FALSE, $this->languages[$language_key]['dialect_in_file'])) { $table = 'languages'; $fields = array('dialect_in_file' => TRUE); $where = array('language_key' => $language_key); $retval = db_update($table, $fields, $where); if ($retval) { logger(sprintf('%s.%s(): updated language %s: dialect_in_file is now enabled', __CLASS__, __FUNCTION__, $language_key), WLOG_DEBUG); } else { logger(sprintf('%s.%s(): update of language %s failed: %s', __CLASS__, __FUNCTION__, $language_key, db_errormessage())); } } } if ($retval) { $this->output->add_message(t('translatetool_translation_save_success', 'admin', $params)); } else { $this->output->add_message(t('translatetool_translation_save_failure', 'admin', $params)); } if ($diff['_submit'] == '1') { if ($this->submit_diff_to_project($language_key, $full_domain, $diff)) { $this->output->add_message(t('translatetool_translation_submit_success', 'admin', $params)); logger(sprintf('%s.%s(): success submitting translations for %s - %s: %d items', __CLASS__, __FUNCTION__, $language_key, $full_domain, $diff_count), WLOG_DEBUG); } else { logger(sprintf('%s.%s(): could not submit translations for %s - %s (%d items)', __CLASS__, __FUNCTION__, $language_key, $full_domain, $diff_count)); $this->output->add_message(t('translatetool_translation_submit_failure', 'admin', $params)); } } } // 5 -- clear cache and force reread of translation just saved $LANGUAGE->reset_cache($language_key, $full_domain); $this->translation_edit(); }