/** validate and check values that were submitted via a user dialog * * this steps through the definition of a dialog and retrieves the values submitted by * the user via $_POST[]. The values are checked against the constraints (e.g. minimum string length, * date range, etc.). If the submitted value is considered valid, it is stored in the corresponding * value of the dialogdef element, maybe properly reformatted (in case of dates/times/datetimes). * If there were errors, these are recorded in the dialog definition element, in the form of one or * more readable error messages. Also the error count (per element) is incremented. This makes it * easy to * - inform the user about what was wrong with the input data * - determine whether there was an error at all (if $dialogdef[$k]['errors'] > 0). * * Note that this routine has the side effect of filling the dialog array with the data that * was submitted by the user via $_POST. If the validation is successful, the data is ready * to be saved into the database. If it is not, the data entered is still available in the * dialogdef which makes it easy to return to the user and let the user correct the errors without * losing all the data input because of a silly mistake in some input field. * * Update 2009-03-17: We no longer validate the view-only fields because these fields are not POST'ed * by the browser and hence cannot be validated. This also means that there is no value set from $_POST * for those fields. * * Update 2011-09-29: added UTF-8 validation, replace with U+FFFD (Unicode replacement character) on fail * * @param array &$dialogdef the complete dialog definition; contains detailed errors and/or reformatted values * @return bool TRUE if all submitted values are considered valid, FALSE otherwise * @todo add an error message to */ function dialog_validate(&$dialogdef) { $total_errors = 0; foreach ($dialogdef as $k => $item) { if (isset($item['name'])) { if (isset($item['viewonly']) && $item['viewonly']) { continue; } $name = $item['name']; $fname = isset($item['label']) ? str_replace('~', '', $item['label']) : $name; $dialogdef[$k]['errors'] = 0; $dialogdef[$k]['error_messages'] = array(); $f_type = isset($item['type']) ? $item['type'] : ''; $value = isset($item['value']) ? $item['value'] : ''; if (isset($_POST[$name])) { if (utf8_validate($_POST[$name])) { $posted_value = magic_unquote($_POST[$name]); } else { $posted_value = "�"; // UTF-8 encoded substitution character U+FFFD ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_invalid', '', array('{FIELD}' => $fname)); } } else { $posted_value = ''; // should be NULL but empty string is more convenient here } switch ($f_type) { case F_DATE: case F_TIME: case F_DATETIME: case F_ALPHANUMERIC: case F_INTEGER: case F_REAL: case F_PASSWORD: case F_RICHTEXT: if ($f_type == F_DATE || $f_type == F_TIME || $f_type == F_DATETIME) { $datetime_value = ''; $is_valid_datetime = valid_datetime($f_type, $posted_value, $datetime_value); if (!$is_valid_datetime) { ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_invalid_datetime', '', array('{FIELD}' => $fname)); } // else we have a valid date/time, and a properly reformatted copy for comparisons too } if (isset($item['minlength'])) { $minlength = intval($item['minlength']); if (strlen($posted_value) < $minlength) { ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_too_short', '', array('{FIELD}' => $fname, '{MIN}' => strval($minlength))); } } if (isset($item['maxlength'])) { $maxlength = intval($item['maxlength']); if ($maxlength < strlen($posted_value)) { ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_too_long', '', array('{FIELD}' => $fname, '{MAX}' => strval($maxlength))); } } if (isset($item['minvalue'])) { switch ($f_type) { case F_INTEGER: if (intval($posted_value) < intval($item['minvalue'])) { ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_too_small', '', array('{FIELD}' => $fname, '{MIN}' => $item['minvalue'])); } break; case F_REAL: if (floatval($posted_value) < floatval($item['minvalue'])) { ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_too_small', '', array('{FIELD}' => $fname, '{MIN}' => $item['minvalue'])); } break; case F_DATE: case F_TIME: case F_DATETIME: if ($is_valid_datetime) { // there's no point in checking a value if the value itself is invalid if ($datetime_value < $item['minvalue']) { ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_too_small', '', array('{FIELD}' => $fname, '{MIN}' => $item['minvalue'])); } } break; } } if (isset($item['maxvalue'])) { switch ($f_type) { case F_INTEGER: if (intval($item['maxvalue']) < intval($posted_value)) { ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_too_large', '', array('{FIELD}' => $fname, '{MAX}' => $item['maxvalue'])); } break; case F_REAL: if (floatval($item['maxvalue']) < floatval($posted_value)) { ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_too_large', '', array('{FIELD}' => $fname, '{MAX}' => $item['maxvalue'])); } break; case F_DATE: case F_TIME: case F_DATETIME: if ($is_valid_datetime) { // there's no point in checking a value if the value itself is invalid if ($item['maxvalue'] < $datetime_value) { ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_too_large', '', array('{FIELD}' => $fname, '{MAX}' => $item['maxvalue'])); } } break; } } // finally format the data switch ($f_type) { case F_INTEGER: $dialogdef[$k]['value'] = strval(intval($posted_value)); break; case F_REAL: $decimals = isset($item['decimals']) ? abs(intval($item['decimals'])) : 2; $dialogdef[$k]['value'] = sprintf("%1." . $decimals . "f", floatval($posted_value)); break; case F_DATE: case F_TIME: case F_DATETIME: $dialogdef[$k]['value'] = $is_valid_datetime ? $datetime_value : $posted_value; break; default: $dialogdef[$k]['value'] = $posted_value; break; } break; case F_CHECKBOX: // there are two options: // either $posted_value equals the value in the options list // OR it does't. (well duh). However, it it doesn't match AND // it is not an empty string (see above, should be NULL), it // is an error nonetheless. OK. Here we go. if (!empty($posted_value)) { if (!isset($item['options'][$posted_value])) { // oops, something rottenin the state of Denmark... ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_invalid', '', array('{FIELD}' => $fname)); $dialogdef[$k]['value'] = ''; } else { $dialogdef[$k]['value'] = $posted_value; } } else { $dialogdef[$k]['value'] = ''; } break; case F_RADIO: case F_LISTBOX: // the value should exist in the options array if (!isset($item['options'][$posted_value])) { // oops, something rotten in the state of Denmark... ++$total_errors; ++$dialogdef[$k]['errors']; $dialogdef[$k]['error_messages'][] = t('validate_invalid', '', array('{FIELD}' => $fname)); $dialogdef[$k]['value'] = ''; } else { $dialogdef[$k]['value'] = $posted_value; } break; case F_FILE: // any value is OK, because // 1. checking is done separately in the filemanager (including virusscan etc.) // 2. if there is an error in 1 file, the other uploaded files could be perfectly // OK. Sending the user back to the upload dialog would be counter-productive // because the 'good' files would have to be uploaded again and she would have // to type in/browse the files again (and again and again...) break; case F_SUBMIT: // any value is OK, no check needed break; default: ++$total_errors; $dialogdef[$k]['errors'] = 1; $dialogdef[$k]['error_messages'] = $item['name'] . ' - INTERNAL ERROR: unknown type'; break; } } } return $total_errors == 0; }
/** 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; }
/** display the content of the mailpage linked to node $node_id * * @param object &$theme collects the (html) output * @param int $area_id identifies the area where $node_id lives * @param int $node_id the node to which this module is connected * @param array $module the module record straight from the database * @return bool TRUE on success + output via $theme, FALSE otherwise */ function mailpage_view(&$theme, $area_id, $node_id, $module) { // // 0 -- basic sanity checks // if (($config = mailpage_view_get_config($node_id)) === FALSE) { $theme->add_message(t('error_retrieving_config', 'm_mailpage')); return FALSE; } elseif (sizeof($config['addresses']) <= 0) { logger(sprintf('%s(): no addresses at node %d: is mailpage unconfigured?', __FUNCTION__, $node_id)); $msg = t('error_retrieving_addresses', 'm_mailpage', array('{NODE}' => strval($node_id))); $theme->add_message($msg); $theme->add_content($msg); return FALSE; } // // 1 -- do we have a token already? // $t0 = $t1 = 0; $ip_addr = ''; $data = FALSE; $token_id = FALSE; if (isset($_POST['token'])) { // lookup valid UTF8 key (or fail with substitute U+FFFD instead) $token_key = utf8_validate($_POST['token']) ? magic_unquote($_POST['token']) : "�"; $token_id = token_lookup(MAILPAGE_REFERENCE, $token_key, $t0, $t1, $ip_addr, $data); } // // 2 -- handle cases of expired tokens and Cancel first // $now = time(); if ($token_id !== FALSE && isset($_POST['button_cancel'])) { // visitor pressed [Cancel] $theme->add_message(t('cancelled', 'admin')); token_destroy($token_id); $token_id = FALSE; } if ($token_id !== FALSE && $t1 < $now) { // token expired $theme->add_message(t('error_token_expired', 'm_mailpage')); token_destroy($token_id); $token_id = FALSE; } // // 3 -- handle the three remaining buttons from the two dialogs // if ($token_id !== FALSE) { if (isset($_POST['button_preview'])) { // // 3A -- Preview button // $dialogdef = mailpage_view_get_dialogdef($config, $token_key); if (!mailpage_view_dialog_validate($dialogdef)) { foreach ($dialogdef as $k => $item) { if (isset($item['errors']) && $item['errors'] > 0) { $theme->add_message($item['error_messages']); } } mailpage_show_form($theme, $config, $dialogdef); } else { if (!token_store($token_id, $dialogdef)) { $theme->add_message(t('error_storing_data', 'm_mailpage')); logger(sprintf('%s(): token store error in page %d: %s', __FUNCTION__, $node_id, db_errormessage())); return FALSE; } mailpage_show_preview($theme, $config, $dialogdef, $ip_addr); } } elseif (isset($_POST['button_edit'])) { // // 3B -- Edit button // if ($data === FALSE) { $theme->add_message(t('error_retrieving_data', 'm_mailpage')); logger(sprintf('%s(): no data after token_lookup()? (page=%d)', __FUNCTION__, $node_id)); $data = mailpage_view_get_dialogdef($config, $token_key); } mailpage_show_form($theme, $config, $data); } elseif (isset($_POST['button_send'])) { // // 3C -- Send button // if ($data === FALSE) { $theme->add_message(t('error_retrieving_data', 'm_mailpage')); logger(sprintf('%s(): no data after token_lookup()? (page=%d)', __FUNCTION__, $node_id)); $data = mailpage_view_get_dialogdef($config, $token_key); } if ($now < $t0) { // the window of opportunity is still closed; go back to form a la Edit $msg = t('error_too_fast', 'm_mailpage'); $theme->add_message($msg); $theme->add_popup_top($msg); mailpage_show_form($theme, $config, $data); logger(sprintf('%s(): reply too fast (%ds) from %s', __FUNCTION__, $t0 - $now, $ip_addr)); } elseif (!mailpage_send_message($config, $data, $ip_addr, $now - $t0)) { $theme->add_message(t('error_sending_message')); mailpage_show_form($theme, $config, $data); } else { token_destroy($token_id); mailpage_show_thankyou($theme, $config, $data, $ip_addr); } } else { // // 3D -- catch all: initiate a new round (shouldn't happen) // token_destroy($token_id); $token_id = FALSE; } } // // 4 -- Start with a clean slate // if ($token_id === FALSE) { $token_key = ''; if (($token_id = token_create(MAILPAGE_REFERENCE, $token_key, 20)) === FALSE) { // 20s delay $msg = t('error_creating_token', 'm_mailpage', array('{NODE}' => strval($node_id))); $theme->add_message($msg); $theme->add_content($msg); return FALSE; } $dialogdef = mailpage_view_get_dialogdef($config, $token_key); mailpage_show_form($theme, $config, $dialogdef); } return TRUE; }
$manuals = get_available_manuals(dirname(__FILE__) . '/manuals'); if (sizeof($manuals) == 1) { list($language, $manual) = each($manuals); } else { if (sizeof($manuals) <= 0) { show_screen_download(); } else { show_screen_choose_language($manuals); } exit; } } else { $language = magic_unquote($_GET['language']); } $topic = isset($_GET['topic']) ? magic_unquote($_GET['topic']) : 'toc'; $subtopic = isset($_GET['subtopic']) ? magic_unquote($_GET['subtopic']) : ''; show_manual($language, $topic, $subtopic); exit; // ================================================================== // =========================== WORKHORSES =========================== // ================================================================== /** redirect the user to a specific place in the manual OR show helpful message about downloading the manual * * There is a Website@School Users' Guide available, in English. This is * a separate download from the project's website. That means that it is * optional to have the (English) manual installed. If it is installed, * it is installed under /program/manuals/en/. There might also be translations * available, say the Dutch version of the manual. That one would be * installed in /program/manuals/nl/ which allows for peaceful co-existence of * multiple translations of the manual. This script manual.php is designed to: *
/** show confirmation dialog for multiple file delete OR perform actual file delete * * this routine either shows a list of files to be deleted, asking the user for confirmation * or actually deletes the specified files if the user did confirm the delete. * We bail out if the user pressed the cancel button in the confirmation dialog. * The real work is done in workhorse routines in order to combine the single-file-delete * and the batch-delete into a single confirmation routine. For actual deletion, however, * we always return here and not in the single file delete (see {$link task_remove_file()}). * * @uses show_dialog_confirm_delete_files() * @return void output sent to browser via $this->output and perhaps files deleted */ function task_remove_multiple_files() { // 0 -- essential sanity check alias change directory $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->sort = get_parameter_int(PARAM_SORT, SORTBY_FILE_ASC); // 1 -- do they want to bail out? if (isset($_POST['button_cancel'])) { $this->output->add_message(t('cancelled', 'admin')); $this->task_list_directory(); return; } // 2 -- construct a list of files to delete $entries = $this->get_entries($path); $n = isset($_POST[PARAM_FILENAMES]) ? intval($_POST[PARAM_FILENAMES]) : 0; $entries_to_delete = array(); for ($i = 0; $i < $n; ++$i) { $fieldname = sprintf('%s%d', PARAM_FILENAME, $i); if (isset($_POST[$fieldname])) { $filename = magic_unquote($_POST[$fieldname]); if (isset($entries[$filename]) && $entries[$filename]['is_file']) { $entries_to_delete[$filename] = $entries[$filename]; } else { logger(sprintf('%s.%s(): weird attempt to delete %s/%s', __CLASS__, __FUNCTION__, $path, $filename)); } } } // 3 -- what needs to be done? $n = count($entries_to_delete); // 3A -- nothing to do if ($n <= 0) { $this->output->add_message(t('filemanager_nothing_to_delete', 'admin')); $this->task_list_directory(); return; } if ($n == 1) { $entry = reset($entries_to_delete); $params = array('{FILENAME}' => $entry['vpath']); } else { $params = array('{COUNT}' => strval($n)); } // 3B -- confirmation dialog or actual deletion? if (isset($_POST['confirm']) && intval($_POST['confirm']) != 0) { if ($this->delete_files($path, $entries_to_delete) === FALSE) { $this->output->add_message(t($n == 1 ? 'filemanager_failure_delete_file' : 'filemanager_failure_delete_files', 'admin', $params)); } else { $this->output->add_message(t($n == 1 ? 'filemanager_success_delete_file' : 'filemanager_success_delete_files', 'admin', $params)); } $this->task_list_directory(); } else { $this->show_dialog_confirm_delete_files($path, $entries_to_delete); } }
/** determine the default language to use for translation of phrases * * This routine determines which language to use for prompts * and messages if not specified explicitly in calls to $this->get_phrase(). * There are various ways in which a language can * be determined. Here's the list, in order of significance: * * - $_GET['language'] * - $_SESSION['language_key'] * - $USER->language_key * - $CFG->language_key * - constant value 'en' (the native language) * * Note that all languages are validated agains the list of * valid and active languages as collected in $this->languages. * If a language is NOT valid, the next test is tried. * If all else fails we return 'en' for English, which * is the native language and which should always be valid. * * @uses $CFG * @uses $USER; * @return string a valid language code for an active language */ function get_current_language() { global $CFG; global $USER; if (isset($_GET['language'])) { $lang = magic_unquote($_GET['language']); if (isset($this->languages[$lang]) && db_bool_is(TRUE, $this->languages[$lang]['is_active'])) { return $lang; } } if (isset($_SESSION['language_key'])) { $lang = $_SESSION['language_key']; if (isset($this->languages[$lang]) && db_bool_is(TRUE, $this->languages[$lang]['is_active'])) { return $lang; } } if (isset($USER->language_key)) { $lang = $USER->language_key; if (isset($this->languages[$lang]) && db_bool_is(TRUE, $this->languages[$lang]['is_active'])) { return $lang; } } if (isset($CFG->language_key)) { $lang = $CFG->language_key; if (isset($this->languages[$lang]) && db_bool_is(TRUE, $this->languages[$lang]['is_active'])) { return $lang; } } return 'en'; // if all else fails, return the 'native' language }
/** main program for serving files * * this routine is called from /file.php. * * This routine is responsible for serving files to the visitor. * These files are stored in a (virtual) file hierarchy that looks * like this. * * <pre> * /areas/areaname * /another * /stillmore * ... * /users/username * /another * /stillmore * ... * /groups/groupname * /another * /stillmore * ... * /websiteatschool/program * /manual * /languages * </pre> * * This structure maps to the real file system as follows. The (virtual) * directories /areas, /users and /groups correspond to the fysical * directories {$CFG->datadir}/areas, {$CFG->datadir}/users and * {$CFG->datadir}/groups respectively. The subdirectories correspond to * a (unique) area, user or group and serve as a file repository for that * area, user or group. * * The (virtual) top-level directory /websiteatschool is a special case. * It is used to serve the currently running website program code and the * user-defined translations of active languages. * * Before any file is transmitted to the visitor the access privileges * are checked. The following rules apply. * * Access control for the /areas subdirectory * * - an area must be active before any files are served * - the visitor must have access to the private area if files are to be served * - non-existing files yield a 404 Not Found error * - non-existing areas also yield a 404 Not Found error * - if the visitor has no access to the private area, also a 404 Not Found error is returned * * Access control for /users and /groups * * - a user/group must be active before any files are served * - non-existing users/groups yield 404 Not Found * - non-existing files in existing directories also yield 404 Not Found * * Access control for /websiteatschool * * - there is no limit on downloading the currently active program code or user-defined translations of active languages * * Note: * The check on '..' in the requested filename would be inconclusive if the $path * is encoded in invalid UTF-8: the overlong sequence 2F C0 AE 2E 2F eventually * yields 2F 2E 2E 2F or '/../'. Reference: RFC3629 section 10. However, we use * the filename processed with get_requested_filename() which already checks for * utf8 validity, which rules out the trick with overlong sequences. * * @return void file sent to the browser OR 404 not found on error */ function main_file() { global $USER; global $CFG; global $WAS_SCRIPT_NAME; 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 /** utility routines for manipulating files */ require_once $CFG->progdir . '/lib/filelib.php'; $filename = get_requested_filename(); if (is_null($filename)) { error_exit404(); } // 0 -- is the visitor logged in if (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(); 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']++; } } } /** 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 session_write_close(); // we no longer need this here, everything relevant is now in $USER } else { $USER = new Useraccount(); $USER->is_logged_in = FALSE; } // // 1 -- does the visitor want to download the source code // $path_components = explode('/', trim(strtr($filename, '\\', '/'), '/')); if (strtolower($path_components[0]) == 'websiteatschool') { $source = isset($path_components[1]) ? strtolower($path_components[1]) : 'program'; download_source($source); exit; } // // 2 -- no source code requested. check out regular files // $path = '/' . implode('/', $path_components); // 2A -- always disallow attempts to escape from tree via parent directory tricks if (in_array('..', $path_components)) { logger(sprintf("%s(): access denied for file '%s': no tricks with '/../': return 404 Not Found", __FUNCTION__, $path), WLOG_DEBUG); error_exit404($path); } // 2B -- check the 1st and 2nd component of the requested file switch ($path_components[0]) { case 'areas': $area_path = isset($path_components[1]) ? $path_components[1] : ''; $fields = array('area_id', 'is_private'); $where = array('is_active' => TRUE, 'path' => $area_path); $table = 'areas'; if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf("%s(): access denied for file '%s': non-existing or inactive area: return 404 Not Found", __FUNCTION__, $path), WLOG_DEBUG); error_exit404($path); } $area_id = intval($record['area_id']); if (db_bool_is(TRUE, $record['is_private']) && !$USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $area_id)) { logger(sprintf("%s(): access denied for file '%s' in private area '%d': return 404 Not Found", __FUNCTION__, $path, $area_id), WLOG_DEBUG); error_exit404($path); } break; case 'users': $user_path = isset($path_components[1]) ? $path_components[1] : ''; $fields = array('user_id'); $where = array('path' => $user_path, 'is_active' => TRUE); $table = 'users'; if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf("%s(): access denied for file '%s': non-existing or inactive user: return 404 Not Found", __FUNCTION__, $path), WLOG_DEBUG); error_exit404($path); } break; case 'groups': $group_path = isset($path_components[1]) ? $path_components[1] : ''; $fields = array('group_id'); $where = array('path' => $group_path, 'is_active' => TRUE); $table = 'groups'; if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf("%s(): access denied for file '%s': non-existing or inactive group: return 404 Not Found", __FUNCTION__, $path), WLOG_DEBUG); error_exit404($path); } break; default: logger(sprintf("%s(): access denied for file '%s': subdirectory '%s' not recognised: return 404 Not Found", __FUNCTION__, $path, $path_components[0]), WLOG_DEBUG); error_exit404($path); break; } // 2C -- still here? 1st and 2nd components are good but does the file exist? if (!is_file($CFG->datadir . $path)) { logger(sprintf("%s(): access denied for file '%s': file does not exist: return 404 Not Found", __FUNCTION__, $path), WLOG_DEBUG); error_exit404($path); } // // At this point we confident that the file exists within the data directory and also that // the visitor is allowed access to the file. Now send the file to the visitor. // $name = basename($path); if (($bytes_sent = send_file_from_datadir($path, $name)) === FALSE) { logger(sprintf("Failed to send '%s' using filename '%s'", $path, $name)); $retval = FALSE; } else { logger(sprintf("Success sending '%s' using filename '%s', size = %d bytes", $path, $name, $bytes_sent), WLOG_DEBUG); $retval = TRUE; } exit; }
/** execute the selected login procedure * * The login process is controlled via the parameter 'login' * provided by the user via 'index.php?login=N or via the * 'action' property in a HTML-form. These numbers correspond to the * LOGIN_PROCEDURE_* constants defined near the top of this file. * Here's a reminder: * * 1. LOGIN_PROCEDURE_NORMAL this is the usual procedure for logging in * 2. LOGIN_PROCEDURE_CHANGE_PASSWORD this is the procedure to change the user's password * 3. LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER this is phase 1 of the 'forgot password' procedure * 4. LOGIN_PROCEDURE_SEND_BYPASS this is phase 2 of the 'forgot password' procedure * * Note that this routine only returns to the caller after either a succesful * regular login (i.e. after completing LOGIN_PROCEDURE_NORMAL). All the * other variants and error conditions yield another screen and an immediate exit and * hence no return to caller. If this routine returns, it returns the user_id * of the authenticated user (the primary key into the users table). It is up to the caller to * retrieve additional information about this user; any information read from the database * during login is discarded. This prevents password hashes still lying around. * * Note that a successful login has the side effect of garbage collection: * whenever we experience a successful login any obsolete sessions are removed. * This makes sure that locked records eventually will be unlocked, once the corresponding * session no longer exists. The garbage collection routine is also called from * the PHP session handler every once in a while, but here we make 100% sure that * garbage is collected at least at every login. (Note: obsolete sessions should not * be a problem for visitors that are not logged in, because you have to be logged in * to be able to lock a record.) * * @param int $procedure the login procedure to execute * @param string $message the message to display when showing the login dialog * @return void|int no return on error, otherwise the user_id of the authenticated user * @uses $CFG * @uses dbsession_setup() * @uses dbsession_garbage_collection() */ function was_login($procedure = LOGIN_PROCEDURE_SHOWLOGIN, $message = '') { global $CFG; // get rid of the cookie (if we received one) and the corresponding session; // the user's browser should NOT present us with a cookie during the login procedures. if (isset($_COOKIE[$CFG->session_name])) { was_logout(); exit; } // If this IP-address is currently blacklisted, tell the visitor access is denied if (login_is_blacklisted($_SERVER['REMOTE_ADDR'])) { show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('access_denied', 'loginlib')); exit; } switch (intval($procedure)) { case LOGIN_PROCEDURE_NORMAL: if (isset($_POST['login_username']) && isset($_POST['login_password'])) { $username = magic_unquote($_POST['login_username']); $password = magic_unquote($_POST['login_password']); $user = authenticate_user(BY_PASSWORD, $username, $password); if ($user !== FALSE) { login_failure_reset($_SERVER['REMOTE_ADDR']); if (db_bool_is(FALSE, $user['bypass_mode'])) { // valid credentials and not in a bypass mode: start session and return user_id require_once $CFG->progdir . '/lib/dbsessionlib.php'; dbsession_setup($CFG->session_name); $session_key = dbsession_create($user['user_id'], $_SERVER['REMOTE_ADDR']); session_id($session_key); session_start(); $_SESSION['session_id'] = dbsession_get_session_id($session_key); $user_id = intval($user['user_id']); $_SESSION['user_id'] = $user_id; $_SESSION['redirect'] = $user['redirect']; $_SESSION['language_key'] = $user['language_key']; $_SESSION['remote_addr'] = $_SERVER['REMOTE_ADDR']; $_SESSION['salt'] = $CFG->salt; // allow for extra check on rogue sessions $_SESSION['username'] = $username; logger('login: \'' . $username . '\' (' . $user_id . '): success', WLOG_INFO, $user_id); // now that we logged on successfully, make sure that obsolete sessions // will not bother us (or other logged in users). Note the 900 seconds minimum duration; // $time_out = max(900,intval(ini_get('session.gc_maxlifetime'))); global $CFG; $time_out = max(900, intval($CFG->session_expiry)); dbsession_garbage_collection($time_out); return $user_id; // SUCCESS! User is logged in, tell caller! } else { show_login(LOGIN_PROCEDURE_CHANGE_PASSWORD, t('must_change_password', 'loginlib')); exit; } } // Invalid credentials; pretend we're busy (slow user down), increment failure count... $failure_count = login_failure_increment($_SERVER['REMOTE_ADDR'], LOGIN_PROCEDURE_NORMAL, $username); login_failure_delay($_SERVER['REMOTE_ADDR']); if ($failure_count < intval($CFG->login_max_failures)) { show_login(LOGIN_PROCEDURE_NORMAL, t('invalid_credentials_please_retry', 'loginlib')); } elseif ($failure_count == intval($CFG->login_max_failures)) { show_login(LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER, t('do_you_want_to_try_forgot_password_procedure', 'loginlib')); } else { login_failure_blacklist_address($_SERVER['REMOTE_ADDR'], 60 * intval($CFG->login_blacklist_interval), $username); show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('contact_webmaster_for_new_password', 'loginlib')); } } else { show_login(LOGIN_PROCEDURE_NORMAL); } exit; break; case LOGIN_PROCEDURE_CHANGE_PASSWORD: if (isset($_POST['login_username']) && isset($_POST['login_password']) && isset($_POST['login_new_password1']) && isset($_POST['login_new_password2'])) { $username = magic_unquote($_POST['login_username']); $password = magic_unquote($_POST['login_password']); $new_password1 = magic_unquote($_POST['login_new_password1']); $new_password2 = magic_unquote($_POST['login_new_password2']); $user = authenticate_user(BY_PASSWORD, $username, $password); // // step 1 - perform some checks on the proposed new passwords // if ($user !== FALSE) { // user authenticated: we can now also check re-use of existing passwords $salt = $user['salt']; $password_hash = $user['password_hash']; $bypass_hash = $user['bypass_hash']; } else { // user not authenticated so we cannot check for re-use of existing passwords $salt = ''; $password_hash = ''; $bypass_hash = ''; } if (!acceptable_new_password($new_password1, $new_password2, $salt, $password_hash, $bypass_hash)) { show_login(LOGIN_PROCEDURE_CHANGE_PASSWORD, t('invalid_new_passwords', 'loginlib', array('{MIN_LENGTH}' => MINIMUM_PASSWORD_LENGTH, '{MIN_LOWER}' => MINIMUM_PASSWORD_LOWERCASE, '{MIN_UPPER}' => MINIMUM_PASSWORD_UPPERCASE, '{MIN_DIGIT}' => MINIMUM_PASSWORD_DIGITS))); exit; } // // step 2 - if authenticated, actually change password and reset failure counters/blacklists // if ($user !== FALSE) { // allow the user in: // - start new session, // - immediately write/close it, // - send user an email about success with changing password, // - and finally leave the user with message box on screen // login_change_password($user['user_id'], $new_password1); login_failure_reset($_SERVER['REMOTE_ADDR']); require_once $CFG->progdir . '/lib/dbsessionlib.php'; dbsession_setup($CFG->session_name); $session_key = dbsession_create($user['user_id'], $_SERVER['REMOTE_ADDR']); session_id($session_key); session_start(); $_SESSION['session_id'] = dbsession_get_session_id($session_key); $user_id = intval($user['user_id']); $_SESSION['user_id'] = $user_id; $_SESSION['redirect'] = $user['redirect']; $_SESSION['language_key'] = $user['language_key']; $_SESSION['remote_addr'] = $_SERVER['REMOTE_ADDR']; $_SESSION['salt'] = $CFG->salt; // allow for extra check on rogue sessions $_SESSION['username'] = $username; session_write_close(); // save the session login_send_confirmation($user); logger('login: \'' . $username . '\' (' . $user_id . '), change password: success', WLOG_INFO, $user_id); show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('password_changed', 'loginlib')); exit; } // Invalid credentials; pretend we're busy (slow user down), increment failure count... $failure_count = login_failure_increment($_SERVER['REMOTE_ADDR'], LOGIN_PROCEDURE_CHANGE_PASSWORD, $username); login_failure_delay($_SERVER['REMOTE_ADDR']); if ($failure_count < intval($CFG->login_max_failures)) { show_login(LOGIN_PROCEDURE_CHANGE_PASSWORD, t('invalid_credentials_please_retry', 'loginlib')); } elseif ($failure_count == intval($CFG->login_max_failures)) { show_login(LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER, t('too_many_login_attempts', 'loginlib')); } else { login_failure_blacklist_address($_SERVER['REMOTE_ADDR'], 60 * intval($CFG->login_blacklist_interval), $username); show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('too_many_change_password_attempts', 'loginlib')); } } else { show_login(LOGIN_PROCEDURE_CHANGE_PASSWORD); } exit; break; case LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER: if (isset($_POST['login_username']) && isset($_POST['login_email'])) { $username = magic_unquote($_POST['login_username']); $email = magic_unquote($_POST['login_email']); $user = authenticate_user(BY_EMAIL, $username, $email); if ($user !== FALSE) { if (login_send_laissez_passer($user)) { show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('see_mail_for_further_instructions', 'loginlib')); } else { show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('failure_sending_laissez_passer_mail', 'loginlib')); } exit; } else { // Not authenticated; pretend we're busy (slow user down), increment failure count... $failure_count = login_failure_increment($_SERVER['REMOTE_ADDR'], LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER, $username); login_failure_delay($_SERVER['REMOTE_ADDR']); if ($failure_count < intval($CFG->login_max_failures)) { show_login(LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER, t('invalid_username_email_please_retry', 'loginlib')); } elseif ($failure_count == intval($CFG->login_max_failures)) { show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('too_many_login_attempts', 'loginlib')); } else { login_failure_blacklist_address($_SERVER['REMOTE_ADDR'], 60 * intval($CFG->login_blacklist_interval), $username); show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('too_many_login_attempts', 'loginlib')); } exit; } } else { show_login(LOGIN_PROCEDURE_SEND_LAISSEZ_PASSER); } exit; break; case LOGIN_PROCEDURE_SEND_BYPASS: if (isset($_GET['code']) && isset($_GET['username'])) { $laissez_passer = magic_unquote($_GET['code']); $username = magic_unquote($_GET['username']); } elseif (isset($_POST['login_username']) && isset($_POST['login_laissez_passer'])) { $laissez_passer = magic_unquote($_POST['login_laissez_passer']); $username = magic_unquote($_POST['login_username']); } else { show_login(LOGIN_PROCEDURE_SEND_BYPASS); exit; } // still here? Then we check the laissez_passer and send a second email to the user $user = authenticate_user(BY_LAISSEZ_PASSER, $username, $laissez_passer); if ($user !== FALSE) { login_failure_reset($_SERVER['REMOTE_ADDR']); if (login_send_bypass($user)) { show_login(LOGIN_PROCEDURE_NORMAL, t('see_mail_for_new_temporary_password', 'loginlib')); } else { show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('failure_sending_temporary_password', 'loginlib')); } } else { $failure_count = login_failure_increment($_SERVER['REMOTE_ADDR'], LOGIN_PROCEDURE_SEND_BYPASS, $username); login_failure_delay($_SERVER['REMOTE_ADDR']); if ($failure_count < intval($CFG->login_max_failures)) { show_login(LOGIN_PROCEDURE_SEND_BYPASS, t('invalid_laissez_passer_please_retry', 'loginlib')); } elseif ($failure_count == intval($CFG->login_max_failures)) { show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('too_many_login_attempts', 'loginlib')); } else { login_failure_blacklist_address($_SERVER['REMOTE_ADDR'], 60 * intval($CFG->login_blacklist_interval), $username); show_login(LOGIN_PROCEDURE_MESSAGE_BOX, t('too_many_login_attempts', 'loginlib')); } } exit; break; case LOGIN_PROCEDURE_SHOWLOGIN: show_login(LOGIN_PROCEDURE_NORMAL, $message); exit; break; default: show_login(LOGIN_PROCEDURE_NORMAL); exit; break; } }
/** return an (unquoted) string value specified in the page request or default value if none * * First check out the friendly url for the named parameter. If it exists, we use that, * otherwise we have the $default_value. After that the valid UTF-8 value may overwrite the * value found in the friendly url (or the default value). * * It is the responsability of the caller to provide a workable default value. * * Note that invalid UTF-8 is silently discarded. * * @param string $name the name of the parameter to retrieve the value of * @param mixed $default_value the value to return if parameter was not specified * @return mixed the value of the parameter or the default value if not specified */ function get_parameter_string($name, $default_value = NULL) { $value = get_friendly_parameter($name, $default_value); // first check out friendly URL... if (isset($_GET[$name]) && utf8_validate($_GET[$name])) { $value = magic_unquote($_GET[$name]); // ...but let valid UTF-8 GET[] value prevail (if any) } return $value; }
/** save the modified content data of this module linked to node $node_id * * this validates and saves the data that was submitted by the user. * If validation fails, or storing the data doesn't work, the flag $edit_again * is set to TRUE and the return value is FALSE. * * If the user has cancelled the operation, the flag $edit_again is set to FALSE * and the return value is also FALSE. * * If the modified data is stored successfully, the return value is TRUE (and * the value of $edit_again is a don't care). * * Here is a summary of return values. * * - retval = TRUE ==> data saved successfully * - retval = FALSE && edit_again = TRUE ==> re-edit the data, show the edit dialog again * - retval = FALSE && edit_again = FALSE ==> cancelled, do nothing * * @param object &$output collects the html output (if any) * @param int $area_id the area in which $node_id resides * @param int $node_id the node to which the content is connected * @param array $module the module record straight from the database * @param bool $viewonly if TRUE, editing and hence saving is not allowed * @param bool &$edit_again set to TRUE if we need to edit the content again, FALSE otherwise * @return bool TRUE on success + output stored via $output, FALSE otherwise */ function htmlpage_save(&$output, $area_id, $node_id, $module, $viewonly, &$edit_again) { global $USER; if (isset($_POST['button_cancel']) || $viewonly) { $edit_again = FALSE; $retval = FALSE; } else { $edit_again = TRUE; if (!$viewonly) { $where = array('node_id' => intval($node_id)); $order = array('version DESC'); $record = db_select_single_record('htmlpages', '*', $where, $order); if ($record !== FALSE) { $now = strftime('%Y-%m-%d %T'); $fields = array('version' => intval($record['version']) + 1, 'page_data' => magic_unquote($_POST['htmlpage_content']), 'mtime' => $now, 'muser_id' => $USER->user_id); $where = array('htmlpage_id' => $record['htmlpage_id']); $retval = db_update('htmlpages', $fields, $where); } else { $retval = FALSE; } } else { $retval = FALSE; } } return $retval; }
/** main program for site maintenance * * This is the main administrator program. * First step is to deal with users logging in or out. * If a user is not logged in, a login dialog is displayed. * If a user is logged in but has no admin privileges, she * is redirected to the public site (ie. index.php). * * Once we have established that the user is an administrator, * we setup an output collecting object and see what the user * wants us to do by interpreting the parameter 'job'. * If the user has access to the specified job, the corresponding * code is included and the main routine of that handler is called. * It is then the responsability of that handler to further decide * what needs to be done. * After the handler returns, the collected output is sent to the user. * This includes the main navigation (i.e. links to the various * 'managers') and also the menu and the content generated by the * handler. * * If the user has no privilege to access a particular manager, * an error messate is displayed in both the message area and the content * area. This makes it clear to the user that access is denied. * Note that the inaccessible items are displayed in the main navigation * via 'dimmed' (light-grey) links or black/white images. * By showing these 'dimmed' links, the user will be aware that there * is more that just what she is allowed to see. This is more transparent * than suppressing items and keeping them secret. * * @return void generated page sent to user's browser * @uses $CFG; * @uses $LANGUAGE; * @uses $USER; * @todo should we cater for a special 'print' button + * support for a special style sheet for media="print"? */ function main_admin() { global $CFG; global $LANGUAGE; global $USER; /** initialise, setup database, read configuration, etc. */ require_once $CFG->progdir . '/init.php'; initialise(); // user must be logged in to perform any admin tasks at all if (isset($_GET['logout'])) { admin_logout_and_exit(); } elseif (isset($_GET['login'])) { $user_id = admin_login(magic_unquote($_GET['login'])); } elseif (isset($_COOKIE[$CFG->session_name])) { $user_id = admin_continue_session(); } else { admin_show_login_and_exit(); } /** useraccount.class.php is used to define the USER object */ require_once $CFG->progdir . '/lib/useraccount.class.php'; $USER = new Useraccount($user_id); $USER->is_logged_in = TRUE; $_SESSION['language_key'] = $LANGUAGE->get_current_language(); // remember language set via _GET or otherwise // Only admins are allowed, others are redirected to index.php if (!$USER->is_admin()) { logger("admin.php: '{$USER->username}' ({$USER->user_id}) is no admin and was redirected to index.php or login"); session_write_close(); non_admin_redirect_and_exit(); } // We now know that this user is an admin, but // is she allowed to perform upgrades if any? Check it out in 2 steps // 1--we do NOT want exit on error if the user has enough privileges // 2--we check the version and stay here if the user has enough privileges $exit_on_error = $USER->has_job_permissions(JOB_PERMISSION_UPDATE) ? FALSE : TRUE; $need_to_update = was_version_check($exit_on_error) ? FALSE : TRUE; // We are still here if versions are OK _or_ versions mismatch but user has UPDATE privilege. // Now we know we _will_ be generating output => setup output object // using the specified skin OR the user's prefererred skin OR the one // stored before in $_SESSION $_SESSION['skin'] = get_current_skin(); // echo "DDD: {$_SESSION['skin']}"; $output = new AdminOutput($_SESSION['skin'], $CFG->title); // Display a 'welcome message' if this is the first page after logging in. if ($_SESSION['session_counter'] == 1) { $output->add_message(t('login_user_success', 'admin', array('{USERNAME}' => $USER->username))); } // Let's see what what job needs to be done $job = $need_to_update ? JOB_UPDATE : get_parameter_string('job', JOB_STARTCENTER); // main dispatcher switch ($job) { case JOB_STARTCENTER: job_start($output); break; case JOB_PAGEMANAGER: add_javascript_popup_function($output, ' '); if ($USER->has_job_permissions(JOB_PERMISSION_PAGEMANAGER)) { include $CFG->progdir . '/lib/pagemanager.class.php'; $manager = new PageManager($output); } else { $output->add_content("<h2>" . t('access_denied', 'admin') . "</h2>"); $output->add_content(t('job_access_denied', 'admin')); $output->add_message(t('job_access_denied', 'admin')); } break; case JOB_FILEMANAGER: case JOB_FILEBROWSER: case JOB_IMAGEBROWSER: case JOB_FLASHBROWSER: add_javascript_popup_function($output, ' '); add_javascript_select_url_function($output, ' '); if ($USER->has_job_permissions(JOB_PERMISSION_FILEMANAGER)) { include $CFG->progdir . '/lib/filemanager.class.php'; $manager = new FileManager($output, $job); } else { $output->add_content("<h2>" . t('access_denied', 'admin') . "</h2>"); $output->add_content(t('job_access_denied', 'admin')); $output->add_message(t('job_access_denied', 'admin')); } break; case JOB_MODULEMANAGER: if ($USER->has_job_permissions(JOB_PERMISSION_MODULEMANAGER)) { include $CFG->progdir . '/lib/modulemanagerlib.php'; job_modulemanager($output); } else { $output->add_content("<h2>" . t('access_denied', 'admin') . "</h2>"); $output->add_content(t('job_access_denied', 'admin')); $output->add_message(t('job_access_denied', 'admin')); } break; case JOB_ACCOUNTMANAGER: if ($USER->has_job_permissions(JOB_PERMISSION_ACCOUNTMANAGER)) { include $CFG->progdir . '/lib/accountmanagerlib.php'; job_accountmanager($output); } else { $output->add_content("<h2>" . t('access_denied', 'admin') . "</h2>"); $output->add_content(t('job_access_denied', 'admin')); $output->add_message(t('job_access_denied', 'admin')); } break; case JOB_CONFIGURATIONMANAGER: if ($USER->has_job_permissions(JOB_PERMISSION_CONFIGURATIONMANAGER)) { include $CFG->progdir . '/lib/configurationmanagerlib.php'; job_configurationmanager($output); } else { $output->add_content("<h2>" . t('access_denied', 'admin') . "</h2>"); $output->add_content(t('job_access_denied', 'admin')); $output->add_message(t('job_access_denied', 'admin')); } break; case JOB_STATISTICS: if ($USER->has_job_permissions(JOB_PERMISSION_STATISTICS)) { include $CFG->progdir . '/lib/statisticslib.php'; job_statistics($output); } else { $output->add_content("<h2>" . t('access_denied', 'admin') . "</h2>"); $output->add_content(t('job_access_denied', 'admin')); $output->add_message(t('job_access_denied', 'admin')); } break; case JOB_TOOLS: if ($USER->has_job_permissions(JOB_PERMISSION_TOOLS)) { // user has permission to access at least one of the tools include $CFG->progdir . '/lib/toolslib.php'; job_tools($output); } else { $output->add_content("<h2>" . t('access_denied', 'admin') . "</h2>"); $output->add_content(t('job_access_denied', 'admin')); $output->add_message(t('job_access_denied', 'admin')); } break; case JOB_UPDATE: if ($USER->has_job_permissions(JOB_PERMISSION_UPDATE)) { // user has permission to access the update routine(s) include $CFG->progdir . '/lib/updatelib.php'; job_update($output); } else { $output->add_content("<h2>" . t('access_denied', 'admin') . "</h2>"); $output->add_content(t('job_access_denied', 'admin')); $output->add_message(t('job_access_denied', 'admin')); } break; default: if (!empty($job)) { $output->add_content("<h2>" . t('access_denied', 'admin') . "</h2>"); $output->add_content(t('unknown_job', 'admin', array('{JOB}' => htmlspecialchars($job)))); $output->add_message(t('unknown_job', 'admin', array('{JOB}' => htmlspecialchars($job)))); logger("'" . $USER->username . "': unknown job '" . htmlspecialchars($job) . "'"); } else { job_start($output); } break; } // the various functions job_*() will have put their output in $output // Now it is time to actually output the output to the user's browser. $output->send_output(); // make sure that any changes in $_SESSION are properly stored // note that we close the session only after all processing is done, // allowing the various job_*()'s to manipulate the session variables session_write_close(); // at this point we have sent the page to the user, // we can now use the remaining time in this run to process // a few alerts (if any). cron_send_queued_alerts(25); // if there are more than 25, do them later or let cron do it. return; }