Dan's fix from MDL-7263
[moodle.git] / lib / adminlib.php
blob9a7cbebc91079ed7186c08507174a92c8fb57b44
1 <?php
3 /**
4 * adminlib.php - Contains functions that only administrators will ever need to use
6 * @author Martin Dougiamas and many others
7 * @version $Id$
8 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
9 * @package moodlecore
12 /**
13 * Upgrade plugins
15 * @uses $db
16 * @uses $CFG
17 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
18 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
19 * @param string $return The url to prompt the user to continue to
21 function upgrade_plugins($type, $dir, $return) {
22 global $CFG, $db;
24 if (!$plugs = get_list_of_plugins($dir) ) {
25 error('No '.$type.' plugins installed!');
28 $updated_plugins = false;
29 $strpluginsetup = get_string('pluginsetup');
31 foreach ($plugs as $plug) {
33 $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
35 unset($plugin);
37 if (is_readable($fullplug .'/version.php')) {
38 include_once($fullplug .'/version.php'); // defines $plugin with version etc
39 } else {
40 continue; // Nothing to do.
43 $oldupgrade = false;
44 $newupgrade = false;
45 if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) {
46 include_once($fullplug . '/db/'. $CFG->dbtype . '.php'); // defines old upgrading function
47 $oldupgrade = true;
49 if (is_readable($fullplug . '/db/upgrade.php')) {
50 include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
51 $newupgrade = true;
54 if (!isset($plugin)) {
55 continue;
58 if (!empty($plugin->requires)) {
59 if ($plugin->requires > $CFG->version) {
60 $info->pluginname = $plug;
61 $info->pluginversion = $plugin->version;
62 $info->currentmoodle = $CFG->version;
63 $info->requiremoodle = $plugin->requires;
64 if (!$updated_plugins) {
65 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
66 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
67 false, '&nbsp;', '&nbsp;');
69 upgrade_log_start();
70 notify(get_string('pluginrequirementsnotmet', 'error', $info));
71 $updated_plugins = true;
72 unset($info);
73 continue;
77 $plugin->name = $plug; // The name MUST match the directory
79 $pluginversion = $type.'_'.$plug.'_version';
81 if (!isset($CFG->$pluginversion)) {
82 set_config($pluginversion, 0);
85 if ($CFG->$pluginversion == $plugin->version) {
86 // do nothing
87 } else if ($CFG->$pluginversion < $plugin->version) {
88 if (!$updated_plugins) {
89 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
90 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
91 false, '&nbsp;', '&nbsp;');
93 $updated_plugins = true;
94 upgrade_log_start();
95 print_heading($plugin->name .' plugin needs upgrading');
96 $db->debug = true;
97 @set_time_limit(0); // To allow slow databases to complete the long SQL
99 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
100 /// Both old .sql files and new install.xml are supported
101 /// but we priorize install.xml (XMLDB) if present
102 $status = false;
103 if (file_exists($fullplug . '/db/install.xml')) {
104 $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
105 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
106 $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
107 } else {
108 $status = true;
111 $db->debug = false;
112 /// Continue with the instalation, roles and other stuff
113 if ($status) {
114 // OK so far, now update the plugins record
115 set_config($pluginversion, $plugin->version);
116 if (!update_capabilities($dir.'/'.$plug)) {
117 error('Could not set up the capabilities for '.$module->name.'!');
119 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
120 } else {
121 notify('Installing '. $plugin->name .' FAILED!');
123 } else { // Upgrade existing install
124 /// Run de old and new upgrade functions for the module
125 $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade';
126 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
128 /// First, the old function if exists
129 $oldupgrade_status = true;
130 if ($oldupgrade && function_exists($oldupgrade_function)) {
131 $db->debug = true;
132 $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
133 } else if ($oldupgrade) {
134 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
135 $fullplug . '/db/' . $CFG->dbtype . '.php');
138 /// Then, the new function if exists and the old one was ok
139 $newupgrade_status = true;
140 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
141 $db->debug = true;
142 $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
143 } else if ($newupgrade) {
144 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
145 $fullplug . '/db/upgrade.php');
148 $db->debug=false;
149 /// Now analyze upgrade results
150 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
151 // OK so far, now update the plugins record
152 set_config($pluginversion, $plugin->version);
153 if (!update_capabilities($dir.'/'.$plug)) {
154 error('Could not update '.$plugin->name.' capabilities!');
156 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
157 } else {
158 notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
161 echo '<hr />';
162 } else {
163 upgrade_log_start();
164 error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
168 upgrade_log_finish();
170 if ($updated_plugins) {
171 print_continue($return);
172 die;
177 * Find and check all modules and load them up or upgrade them if necessary
179 * @uses $db
180 * @uses $CFG
181 * @param string $return The url to prompt the user to continue to
182 * @todo Finish documenting this function
184 function upgrade_activity_modules($return) {
186 global $CFG, $db;
188 if (!$mods = get_list_of_plugins('mod') ) {
189 error('No modules installed!');
192 $updated_modules = false;
193 $strmodulesetup = get_string('modulesetup');
195 foreach ($mods as $mod) {
197 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
198 continue;
201 $fullmod = $CFG->dirroot .'/mod/'. $mod;
203 unset($module);
205 if ( is_readable($fullmod .'/version.php')) {
206 include_once($fullmod .'/version.php'); // defines $module with version etc
207 } else {
208 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
209 continue;
212 $oldupgrade = false;
213 $newupgrade = false;
214 if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
215 include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function
216 $oldupgrade = true;
218 if ( is_readable($fullmod . '/db/upgrade.php')) {
219 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
220 $newupgrade = true;
223 if (!isset($module)) {
224 continue;
227 if (!empty($module->requires)) {
228 if ($module->requires > $CFG->version) {
229 $info->modulename = $mod;
230 $info->moduleversion = $module->version;
231 $info->currentmoodle = $CFG->version;
232 $info->requiremoodle = $module->requires;
233 if (!$updated_modules) {
234 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
235 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
236 false, '&nbsp;', '&nbsp;');
238 upgrade_log_start();
239 notify(get_string('modulerequirementsnotmet', 'error', $info));
240 $updated_modules = true;
241 unset($info);
242 continue;
246 $module->name = $mod; // The name MUST match the directory
248 if ($currmodule = get_record('modules', 'name', $module->name)) {
249 if ($currmodule->version == $module->version) {
250 // do nothing
251 } else if ($currmodule->version < $module->version) {
252 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
253 if (!$oldupgrade && !$newupgrade) {
254 notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' .
255 $fullmod . '/db/upgrade.php were not readable');
256 continue;
258 if (!$updated_modules) {
259 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
260 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
261 false, '&nbsp;', '&nbsp;');
263 upgrade_log_start();
264 print_heading($module->name .' module needs upgrading');
266 /// Run de old and new upgrade functions for the module
267 $oldupgrade_function = $module->name . '_upgrade';
268 $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
270 /// First, the old function if exists
271 $oldupgrade_status = true;
272 if ($oldupgrade && function_exists($oldupgrade_function)) {
273 $db->debug = true;
274 $oldupgrade_status = $oldupgrade_function($currmodule->version, $module);
275 } else if ($oldupgrade) {
276 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
277 $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php');
280 /// Then, the new function if exists and the old one was ok
281 $newupgrade_status = true;
282 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
283 $db->debug = true;
284 $newupgrade_status = $newupgrade_function($currmodule->version, $module);
285 } else if ($newupgrade) {
286 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
287 $mod . ': ' . $fullmod . '/db/upgrade.php');
290 $db->debug=false;
291 /// Now analyze upgrade results
292 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
293 // OK so far, now update the modules record
294 $module->id = $currmodule->id;
295 if (! update_record('modules', $module)) {
296 error('Could not update '. $module->name .' record in modules table!');
298 remove_dir($CFG->dataroot . '/cache', true); // flush cache
299 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
300 echo '<hr />';
301 } else {
302 notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
305 /// Update the capabilities table?
306 if (!update_capabilities('mod/'.$module->name)) {
307 error('Could not update '.$module->name.' capabilities!');
310 $updated_modules = true;
312 } else {
313 upgrade_log_start();
314 error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
317 } else { // module not installed yet, so install it
318 if (!$updated_modules) {
319 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
320 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
321 false, '&nbsp;', '&nbsp;');
323 upgrade_log_start();
324 print_heading($module->name);
325 $updated_modules = true;
326 $db->debug = true;
327 @set_time_limit(0); // To allow slow databases to complete the long SQL
329 /// Both old .sql files and new install.xml are supported
330 /// but we priorize install.xml (XMLDB) if present
331 if (file_exists($fullmod . '/db/install.xml')) {
332 $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
333 } else {
334 $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method
337 $db->debug = false;
338 /// Continue with the instalation, roles and other stuff
339 if ($status) {
340 if ($module->id = insert_record('modules', $module)) {
341 if (!update_capabilities('mod/'.$module->name)) {
342 error('Could not set up the capabilities for '.$module->name.'!');
344 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
345 echo '<hr />';
346 } else {
347 error($module->name .' module could not be added to the module list!');
349 } else {
350 error($module->name .' tables could NOT be set up successfully!');
354 /// Check submodules of this module if necessary
356 include_once($fullmod.'/lib.php'); // defines upgrading function
358 $submoduleupgrade = $module->name.'_upgrade_submodules';
359 if (function_exists($submoduleupgrade)) {
360 $submoduleupgrade();
364 /// Run any defaults or final code that is necessary for this module
366 if ( is_readable($fullmod .'/defaults.php')) {
367 // Insert default values for any important configuration variables
368 unset($defaults);
369 include_once($fullmod .'/defaults.php');
370 if (!empty($defaults)) {
371 foreach ($defaults as $name => $value) {
372 if (!isset($CFG->$name)) {
373 set_config($name, $value);
380 upgrade_log_finish(); // finish logging if started
382 if ($updated_modules) {
383 print_continue($return);
384 die;
389 * This function will return FALSE if the lock fails to be set (ie, if it's already locked)
391 * @param string $name ?
392 * @param bool $value ?
393 * @param int $staleafter ?
394 * @param bool $clobberstale ?
395 * @todo Finish documenting this function
397 function set_cron_lock($name,$value=true,$staleafter=7200,$clobberstale=false) {
399 if (empty($name)) {
400 mtrace("Tried to get a cron lock for a null fieldname");
401 return false;
404 if (empty($value)) {
405 set_config($name,0);
406 return true;
409 if ($config = get_record('config','name',$name)) {
410 if (empty($config->value)) {
411 set_config($name,time());
412 } else {
413 // check for stale.
414 if ((time() - $staleafter) > $config->value) {
415 mtrace("STALE LOCKFILE FOR $name - was $config->value");
416 if (!empty($clobberstale)) {
417 set_config($name,time());
418 return true;
420 } else {
421 return false; // was not stale - ie, we're ok to still be running.
425 else {
426 set_config($name,time());
428 return true;
431 function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
432 static $starttime;
433 static $lasttime;
435 if ($total < 2) { // No need to show anything
436 return;
439 if (empty($starttime)) {
440 $starttime = $lasttime = time();
441 $lasttime = $starttime - $updatetime;
442 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
443 echo '<div id="bar'.$total.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
444 echo '<div id="slider'.$total.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
445 echo '</div>';
446 echo '<div id="text'.$total.'" align="center" style="width:500px;"></div>';
447 echo '</td></tr></table>';
448 echo '</div>';
451 $now = time();
453 if ($done && (($now - $lasttime) >= $updatetime)) {
454 $elapsedtime = $now - $starttime;
455 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
456 $percentage = format_float((float)$done / (float)$total, 2);
457 $width = (int)(500 * $percentage);
459 if ($projectedtime > 10) {
460 $projectedtext = ' Ending: '.format_time($projectedtime);
461 } else {
462 $projectedtext = '';
465 echo '<script>';
466 echo 'document.getElementById("text'.$total.'").innerHTML = "'.addslashes($donetext).' ('.$done.'/'.$total.') '.$projectedtext.'";'."\n";
467 echo 'document.getElementById("slider'.$total.'").style.width = \''.$width.'px\';'."\n";
468 echo '</script>';
470 $lasttime = $now;
471 sleep($sleeptime);
475 ////////////////////////////////////////////////
476 /// upgrade logging functions
477 ////////////////////////////////////////////////
479 $upgradeloghandle = false;
480 $upgradelogbuffer = '';
481 // I did not find out how to use static variable in callback function,
482 // the problem was that I could not flush the static buffer :-(
483 global $upgradeloghandle, $upgradelogbuffer;
486 * Check if upgrade is already running.
488 * If anything goes wrong due to missing call to upgrade_log_finish()
489 * just restart the browser.
491 * @param string warning message indicating upgrade is already running
492 * @param int page reload timeout
494 function upgrade_check_running($message, $timeout) {
495 if (!empty($_SESSION['upgraderunning'])) {
496 print_header();
497 redirect(me(), $message, $timeout);
502 * Start logging of output into file (if not disabled) and
503 * prevent aborting and concurrent execution of upgrade script.
505 * Please note that you can not write into session variables after calling this function!
507 * This function may be called repeatedly.
509 function upgrade_log_start() {
510 global $CFG, $upgradeloghandle;
512 if (!empty($_SESSION['upgraderunning'])) {
513 return; // logging already started
516 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
517 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
518 if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
519 session_write_close(); // from now on user can reload page - will be displayed warning
521 make_upload_directory('upgradelogs');
522 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
523 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
527 * Terminate logging of output, flush all data, allow script aborting
528 * and reopen session for writing. Function error() does terminate the logging too.
530 * Please make sure that each upgrade_log_start() is properly terminated by
531 * this function or error().
533 * This function may be called repeatedly.
535 function upgrade_log_finish() {
536 global $CFG, $upgradeloghandle, $upgradelogbuffer;
538 if (empty($_SESSION['upgraderunning'])) {
539 return; // logging already terminated
542 @ob_end_flush();
543 if ($upgradelogbuffer !== '') {
544 @fwrite($upgradeloghandle, $upgradelogbuffer);
545 $upgradelogbuffer = '';
547 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
548 @fclose($upgradeloghandle);
549 $upgradeloghandle = false;
551 if (empty($CFG->dbsessions)) {
552 @session_start(); // ignore header errors, we only need to reopen session
554 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
555 if (connection_aborted()) {
556 die;
558 @ignore_user_abort(false);
562 * Callback function for logging into files. Not more than one file is created per minute,
563 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
565 * This function must not output any characters or throw warnigns and errors!
567 function upgrade_log_callback($string) {
568 global $CFG, $upgradeloghandle, $upgradelogbuffer;
570 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
571 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
572 $upgradelogbuffer .= $string;
573 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
574 @fwrite($upgradeloghandle, $upgradelogbuffer);
575 $upgradelogbuffer = '';
577 } else {
578 $upgradeloghandle = 'error';
581 return $string;
585 * Try to verify that dataroot is not accessible from web.
586 * It is not 100% correct but might help to reduce number of vulnerable sites.
588 * Protection from httpd.conf and .htaccess is not detected properly.
590 function is_dataroot_insecure() {
591 global $CFG;
593 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
595 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
596 $rp = strrev(trim($rp, '/'));
597 $rp = explode('/', $rp);
598 foreach($rp as $r) {
599 if (strpos($siteroot, '/'.$r.'/') === 0) {
600 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
601 } else {
602 break; // probably alias root
606 $siteroot = strrev($siteroot);
607 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
609 if (strpos($dataroot, $siteroot) === 0) {
610 return true;
612 return false;
615 /// =============================================================================================================
616 /// administration tree classes and functions
619 // n.b. documentation is still in progress for this code
621 /// INTRODUCTION
623 /// This file performs the following tasks:
624 /// -it defines the necessary objects and interfaces to build the Moodle
625 /// admin hierarchy
626 /// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
627 /// and admin_externalpage_print_footer() functions used on admin pages
629 /// ADMIN_SETTING OBJECTS
631 /// Moodle settings are represented by objects that inherit from the admin_setting
632 /// class. These objects encapsulate how to read a setting, how to write a new value
633 /// to a setting, and how to appropriately display the HTML to modify the setting.
635 /// ADMIN_SETTINGPAGE OBJECTS
637 /// The admin_setting objects are then grouped into admin_settingpages. The latter
638 /// appear in the Moodle admin tree block. All interaction with admin_settingpage
639 /// objects is handled by the admin/settings.php file.
641 /// ADMIN_EXTERNALPAGE OBJECTS
643 /// There are some settings in Moodle that are too complex to (efficiently) handle
644 /// with admin_settingpages. (Consider, for example, user management and displaying
645 /// lists of users.) In this case, we use the admin_externalpage object. This object
646 /// places a link to an external PHP file in the admin tree block.
648 /// If you're using an admin_externalpage object for some settings, you can take
649 /// advantage of the admin_externalpage_* functions. For example, suppose you wanted
650 /// to add a foo.php file into admin. First off, you add the following line to
651 /// admin/settings/first.php (at the end of the file) or to some other file in
652 /// admin/settings:
654 /// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
655 /// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
657 /// Next, in foo.php, your file structure would resemble the following:
659 /// require_once('.../config.php');
660 /// require_once($CFG->libdir.'/adminlib.php');
661 /// $adminroot = admin_get_root();
662 /// admin_externalpage_setup('foo', $adminroot);
663 /// // functionality like processing form submissions goes here
664 /// admin_externalpage_print_header($adminroot);
665 /// // your HTML goes here
666 /// admin_externalpage_print_footer($adminroot);
668 /// The admin_externalpage_setup() function call ensures the user is logged in,
669 /// and makes sure that they have the proper role permission to access the page.
671 /// The admin_externalpage_print_header() function prints the header (it figures
672 /// out what category and subcategories the page is classified under) and ensures
673 /// that you're using the admin pagelib (which provides the admin tree block and
674 /// the admin bookmarks block).
676 /// The admin_externalpage_print_footer() function properly closes the tables
677 /// opened up by the admin_externalpage_print_header() function and prints the
678 /// standard Moodle footer.
680 /// ADMIN_CATEGORY OBJECTS
682 /// Above and beyond all this, we have admin_category objects. These objects
683 /// appear as folders in the admin tree block. They contain admin_settingpage's,
684 /// admin_externalpage's, and other admin_category's.
686 /// OTHER NOTES
688 /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
689 /// from part_of_admin_tree (a pseudointerface). This interface insists that
690 /// a class has a check_access method for access permissions, a locate method
691 /// used to find a specific node in the admin tree, and a path method used
692 /// to determine the path to a specific node in the $ADMIN tree.
694 /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
695 /// interface ensures that the class implements a recursive add function which
696 /// accepts a part_of_admin_tree object and searches for the proper place to
697 /// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
699 /// Please note that the $this->name field of any part_of_admin_tree must be
700 /// UNIQUE throughout the ENTIRE admin tree.
702 /// The $this->name field of an admin_setting object (which is *not* part_of_
703 /// admin_tree) must be unique on the respective admin_settingpage where it is
704 /// used.
707 /// MISCELLANEOUS STUFF (used by classes defined below) ///////////////////////
708 include_once($CFG->dirroot . '/backup/lib.php');
710 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
713 * Pseudointerface for anything appearing in the admin tree
715 * The pseudointerface that is implemented by anything that appears in the admin tree
716 * block. It forces inheriting classes to define a method for checking user permissions
717 * and methods for finding something in the admin tree.
719 * @author Vincenzo K. Marcovecchio
720 * @package admin
722 class part_of_admin_tree {
725 * Finds a named part_of_admin_tree.
727 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
728 * and not parentable_part_of_admin_tree, then this function should only check if
729 * $this->name matches $name. If it does, it should return a reference to $this,
730 * otherwise, it should return a reference to NULL.
732 * If a class inherits parentable_part_of_admin_tree, this method should be called
733 * recursively on all child objects (assuming, of course, the parent object's name
734 * doesn't match the search criterion).
736 * @param string $name The internal name of the part_of_admin_tree we're searching for.
737 * @return mixed An object reference or a NULL reference.
739 function &locate($name) {
740 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
741 return;
745 * Removes named part_of_admin_tree.
747 * @param string $name The internal name of the part_of_admin_tree we want to remove.
748 * @return bool success.
750 function prune($name) {
751 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
752 return;
756 * Verifies current user's access to this part_of_admin_tree.
758 * Used to check if the current user has access to this part of the admin tree or
759 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
760 * then this method is usually just a call to has_capability() in the site context.
762 * If a class inherits parentable_part_of_admin_tree, this method should return the
763 * logical OR of the return of check_access() on all child objects.
765 * @return bool True if the user has access, false if she doesn't.
767 function check_access() {
768 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
769 return;
773 * Mostly usefull for removing of some parts of the tree in admin tree block.
775 * @return True is hidden from normal list view
777 function is_hidden() {
778 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
779 return;
783 * Determines the path to $name in the admin tree.
785 * Used to determine the path to $name in the admin tree. If a class inherits only
786 * part_of_admin_tree and not parentable_part_of_admin_tree, then this method should
787 * check if $this->name matches $name. If it does, $name is pushed onto the $path
788 * array (at the end), and $path should be returned. If it doesn't, NULL should be
789 * returned.
791 * If a class inherits parentable_part_of_admin_tree, it should do the above, but not
792 * return NULL on failure. Instead, it pushes $this->name onto $path, and then
793 * recursively calls path() on its child objects. If any are non-NULL, it should
794 * return $path (being certain that the last element of $path is equal to $name).
795 * If they are all NULL, it returns NULL.
797 * @param string $name The internal name of the part_of_admin_tree we're searching for.
798 * @param array $path Not used on external calls. Defaults to empty array.
799 * @return mixed If found, an array containing the internal names of each part_of_admin_tree that leads to $name. If not found, NULL.
801 function path($name, $path = array()) {
802 trigger_error('Admin class does not implement method <strong>path()</strong>', E_USER_WARNING);
803 return;
808 * Pseudointerface implemented by any part_of_admin_tree that has children.
810 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
811 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
812 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
813 * include an add method for adding other part_of_admin_tree objects as children.
815 * @author Vincenzo K. Marcovecchio
816 * @package admin
818 class parentable_part_of_admin_tree extends part_of_admin_tree {
821 * Adds a part_of_admin_tree object to the admin tree.
823 * Used to add a part_of_admin_tree object to this object or a child of this
824 * object. $something should only be added if $destinationname matches
825 * $this->name. If it doesn't, add should be called on child objects that are
826 * also parentable_part_of_admin_tree's.
828 * @param string $destinationname The internal name of the new parent for $something.
829 * @param part_of_admin_tree &$something The object to be added.
830 * @return bool True on success, false on failure.
832 function add($destinationname, &$something) {
833 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
834 return;
840 * The object used to represent folders (a.k.a. categories) in the admin tree block.
842 * Each admin_category object contains a number of part_of_admin_tree objects.
844 * @author Vincenzo K. Marcovecchio
845 * @package admin
847 class admin_category extends parentable_part_of_admin_tree {
850 * @var mixed An array of part_of_admin_tree objects that are this object's children
852 var $children;
855 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
857 var $name;
860 * @var string The displayed name for this category. Usually obtained through get_string()
862 var $visiblename;
865 * @var bool Should this category be hidden in admin tree block?
867 var $hidden;
869 // constructor for an empty admin category
870 // $name is the internal name of the category. it MUST be unique in the entire hierarchy
871 // $visiblename is the displayed name of the category. use a get_string for this
874 * Constructor for an empty admin category
876 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
877 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
878 * @param bool $hidden hide category in admin tree block
879 * @return mixed Returns the new object.
881 function admin_category($name, $visiblename, $hidden = false) {
882 $this->children = array();
883 $this->name = $name;
884 $this->visiblename = $visiblename;
885 $this->hidden = $hidden;
889 * Finds the path to the part_of_admin_tree called $name.
891 * @param string $name The internal name that we're searching for.
892 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
893 * @return mixed An array of internal names that leads to $name, or NULL if not found.
895 function path($name, $path = array()) {
897 $path[count($path)] = $this->name;
899 if ($this->name == $name) {
900 return $path;
903 foreach($this->children as $child) {
904 if ($return = $child->path($name, $path)) {
905 return $return;
909 return NULL;
914 * Returns a reference to the part_of_admin_tree object with internal name $name.
916 * @param string $name The internal name of the object we want.
917 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
919 function &locate($name) {
921 if ($this->name == $name) {
922 return $this;
925 foreach($this->children as $child) {
926 if ($return =& $child->locate($name)) {
927 return $return;
930 $return = NULL;
931 return $return;
935 * Removes part_of_admin_tree object with internal name $name.
937 * @param string $name The internal name of the object we want to remove.
938 * @return bool success
940 function prune($name) {
942 if ($this->name == $name) {
943 return false; //can not remove itself
946 foreach($this->children as $precedence => $child) {
947 if ($child->name == $name) {
948 // found it!
949 unset($this->children[$precedence]);
950 return true;
952 if ($this->children[$precedence]->prune($name)) {
953 return true;
956 return false;
960 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
962 * @param string $destinationame The internal name of the immediate parent that we want for &$something.
963 * @param mixed &$something A part_of_admin_tree object to be added.
964 * @param int $precedence The precedence of &$something when displayed. Smaller numbers mean it'll be displayed higher up in the admin menu. Defaults to '', meaning "next available position".
965 * @return bool True if successfully added, false if &$something is not a part_of_admin_tree or if $name is not found.
967 function add($destinationname, &$something, $precedence = '') {
969 if (!is_a($something, 'part_of_admin_tree')) {
970 return false;
973 if ($destinationname == $this->name) {
974 if ($precedence === '') {
975 $this->children[] = $something;
976 } else {
977 if (isset($this->children[$precedence])) { // this should never, ever be triggered in a release version of moodle.
978 echo ('<font style="color: red;">There is a precedence conflict in the category ' . $this->name . '. The object named ' . $something->name . ' is overwriting the object named ' . $this->children[$precedence]->name . '.</font><br />');
980 $this->children[$precedence] = $something;
982 return true;
985 unset($entries);
987 $entries = array_keys($this->children);
989 foreach($entries as $entry) {
990 $child =& $this->children[$entry];
991 if (is_a($child, 'parentable_part_of_admin_tree')) {
992 if ($child->add($destinationname, $something, $precedence)) {
993 return true;
998 return false;
1003 * Checks if the user has access to anything in this category.
1005 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1007 function check_access() {
1009 $return = false;
1010 foreach ($this->children as $child) {
1011 $return = $return || $child->check_access();
1014 return $return;
1019 * Is this category hidden in admin tree block?
1021 * @return bool True if hidden
1023 function is_hidden() {
1024 return $this->hidden;
1029 * Links external PHP pages into the admin tree.
1031 * See detailed usage example at the top of this document (adminlib.php)
1033 * @author Vincenzo K. Marcovecchio
1034 * @package admin
1036 class admin_externalpage extends part_of_admin_tree {
1039 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1041 var $name;
1044 * @var string The displayed name for this external page. Usually obtained through get_string().
1046 var $visiblename;
1049 * @var string The external URL that we should link to when someone requests this external page.
1051 var $url;
1054 * @var string The role capability/permission a user must have to access this external page.
1056 var $req_capability;
1059 * @var bool hidden in admin tree block.
1061 var $hidden;
1064 * Constructor for adding an external page into the admin tree.
1066 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1067 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1068 * @param string $url The external URL that we should link to when someone requests this external page.
1069 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1071 function admin_externalpage($name, $visiblename, $url, $req_capability = 'moodle/site:config', $hidden=false) {
1072 $this->name = $name;
1073 $this->visiblename = $visiblename;
1074 $this->url = $url;
1075 if (is_array($req_capability)) {
1076 $this->req_capability = $req_capability;
1077 } else {
1078 $this->req_capability = array($req_capability);
1080 $this->hidden = $hidden;
1084 * Finds the path to the part_of_admin_tree called $name.
1086 * @param string $name The internal name that we're searching for.
1087 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
1088 * @return mixed An array of internal names that leads to $name, or NULL if not found.
1090 function path($name, $path = array()) {
1091 if ($name == $this->name) {
1092 array_push($path, $this->name);
1093 return $path;
1094 } else {
1095 return NULL;
1100 * Returns a reference to the part_of_admin_tree object with internal name $name.
1102 * @param string $name The internal name of the object we want.
1103 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1105 function &locate($name) {
1106 $return = ($this->name == $name ? $this : NULL);
1107 return $return;
1110 function prune($name) {
1111 return false;
1115 * Determines if the current user has access to this external page based on $this->req_capability.
1117 * @uses CONTEXT_SYSTEM
1118 * @uses SITEID
1119 * @return bool True if user has access, false otherwise.
1121 function check_access() {
1122 if (!get_site()) {
1123 return true; // no access check before site is fully set up
1125 $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
1126 foreach($this->req_capability as $cap) {
1127 if (has_capability($cap, $context)) {
1128 return true;
1131 return false;
1135 * Is this external page hidden in admin tree block?
1137 * @return bool True if hidden
1139 function is_hidden() {
1140 return $this->hidden;
1146 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1148 * @author Vincenzo K. Marcovecchio
1149 * @package admin
1151 class admin_settingpage extends part_of_admin_tree {
1154 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1156 var $name;
1159 * @var string The displayed name for this external page. Usually obtained through get_string().
1161 var $visiblename;
1163 * @var mixed An array of admin_setting objects that are part of this setting page.
1165 var $settings;
1168 * @var string The role capability/permission a user must have to access this external page.
1170 var $req_capability;
1173 * @var bool hidden in admin tree block.
1175 var $hidden;
1177 // see admin_category
1178 function path($name, $path = array()) {
1179 if ($name == $this->name) {
1180 array_push($path, $this->name);
1181 return $path;
1182 } else {
1183 return NULL;
1187 // see admin_category
1188 function &locate($name) {
1189 $return = ($this->name == $name ? $this : NULL);
1190 return $return;
1193 function prune($name) {
1194 return false;
1197 // see admin_externalpage
1198 function admin_settingpage($name, $visiblename, $req_capability = 'moodle/site:config', $hidden=false) {
1199 global $CFG;
1200 $this->settings = new stdClass();
1201 $this->name = $name;
1202 $this->visiblename = $visiblename;
1203 if (is_array($req_capability)) {
1204 $this->req_capability = $req_capability;
1205 } else {
1206 $this->req_capability = array($req_capability);
1208 $this->hidden = false;
1211 // not the same as add for admin_category. adds an admin_setting to this admin_settingpage. settings appear (on the settingpage) in the order in which they're added
1212 // n.b. each admin_setting in an admin_settingpage must have a unique internal name
1213 // &$setting is the admin_setting object you want to add
1214 // returns true if successful, false if not (will fail if &$setting is an admin_setting or child thereof)
1215 function add(&$setting) {
1216 if (is_a($setting, 'admin_setting')) {
1217 $this->settings->{$setting->name} =& $setting;
1218 return true;
1220 return false;
1223 // see admin_externalpage
1224 function check_access() {
1225 if (!get_site()) {
1226 return true; // no access check before site is fully set up
1228 $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
1229 foreach($this->req_capability as $cap) {
1230 if (has_capability($cap, $context)) {
1231 return true;
1234 return false;
1237 // outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1238 // returns a string of the html
1239 function output_html() {
1240 $return = '<fieldset>' . "\n";
1241 $return .= '<div class="clearer"><!-- --></div>' . "\n";
1242 foreach($this->settings as $setting) {
1243 $return .= $setting->output_html();
1245 $return .= '</fieldset>';
1246 return $return;
1249 // writes settings (the ones that have been added to this admin_settingpage) to the database, or wherever else they're supposed to be written to
1250 // -- calls write_setting() to each child setting, sending it only the data that matches each setting's internal name
1251 // $data should be the result from data_submitted()
1252 // returns an empty string if everything went well, otherwise returns a printable error string (that's language-specific)
1253 function write_settings($data) {
1254 $return = '';
1255 foreach($this->settings as $setting) {
1256 if (isset($data['s_' . $setting->name])) {
1257 $return .= $setting->write_setting($data['s_' . $setting->name]);
1258 } else {
1259 $return .= $setting->write_setting('');
1262 return $return;
1266 * Is this settigns page hidden in admin tree block?
1268 * @return bool True if hidden
1270 function is_hidden() {
1271 return $this->hidden;
1277 // read & write happens at this level; no authentication
1278 class admin_setting {
1280 var $name;
1281 var $visiblename;
1282 var $description;
1283 var $defaultsetting;
1285 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1286 $this->name = $name;
1287 $this->visiblename = $visiblename;
1288 $this->description = $description;
1289 $this->defaultsetting = $defaultsetting;
1292 function get_setting() {
1293 return NULL; // has to be overridden
1296 function write_setting($data) {
1297 return; // has to be overridden
1300 function output_html() {
1301 return; // has to be overridden
1307 class admin_setting_configtext extends admin_setting {
1309 var $paramtype;
1311 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
1312 $this->paramtype = $paramtype;
1313 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1316 // returns a string or NULL
1317 function get_setting() {
1318 global $CFG;
1319 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1322 // $data is a string
1323 function write_setting($data) {
1324 if (!$this->validate($data)) {
1325 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
1327 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1330 function validate($data) {
1331 if (is_string($this->paramtype)) {
1332 return preg_match($this->paramtype, $data);
1333 } else if ($this->paramtype === PARAM_RAW) {
1334 return true;
1335 } else {
1336 $cleaned = clean_param($data, $this->paramtype);
1337 return ("$data" == "$cleaned"); // implicit conversion to string is needed to do exact comparison
1341 function output_html() {
1342 if ($this->get_setting() === NULL) {
1343 $current = $this->defaultsetting;
1344 } else {
1345 $current = $this->get_setting();
1347 return format_admin_setting($this->name, $this->visiblename,
1348 '<input type="text" class="form-text" id="id_s_'.$this->name.'" name="s_'.$this->name.'" value="'.$current.'" />',
1349 $this->description);
1354 class admin_setting_configcheckbox extends admin_setting {
1356 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting) {
1357 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1360 function get_setting() {
1361 global $CFG;
1362 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1365 function write_setting($data) {
1366 if ($data == '1') {
1367 return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1368 } else {
1369 return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1373 function output_html() {
1374 if ($this->get_setting() === NULL) {
1375 $current = $this->defaultsetting;
1376 } else {
1377 $current = $this->get_setting();
1379 return format_admin_setting($this->name, $this->visiblename,
1380 '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($current == true ? 'checked="checked"' : '') . ' />',
1381 $this->description);
1386 class admin_setting_configselect extends admin_setting {
1388 var $choices;
1390 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
1391 $this->choices = $choices;
1392 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1395 function get_setting() {
1396 global $CFG;
1397 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1400 function write_setting($data) {
1401 // check that what we got was in the original choices
1402 // or that the data is the default setting - needed during install when choices can not be constructed yet
1403 if ($data != $this->defaultsetting and ! in_array($data, array_keys($this->choices))) {
1404 return 'Error setting ' . $this->visiblename . '<br />';
1407 return (set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1410 function output_html() {
1411 if ($this->get_setting() === NULL) {
1412 $current = $this->defaultsetting;
1413 } else {
1414 $current = $this->get_setting();
1416 $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'">';
1417 foreach ($this->choices as $key => $value) {
1418 // the string cast is needed because key may be integer - 0 is equal to most strings!
1419 $return .= '<option value="'.$key.'"'.((string)$key==$current ? ' selected="selected"' : '').'>'.$value.'</option>';
1421 $return .= '</select>';
1423 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1428 // this is a liiitle bit messy. we're using two selects, but we're returning them as an array named after $name (so we only use $name2
1429 // internally for the setting)
1430 class admin_setting_configtime extends admin_setting {
1432 var $name2;
1433 var $choices;
1434 var $choices2;
1436 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
1437 $this->name2 = $minutesname;
1438 $this->choices = array();
1439 for ($i = 0; $i < 24; $i++) {
1440 $this->choices[$i] = $i;
1442 $this->choices2 = array();
1443 for ($i = 0; $i < 60; $i += 5) {
1444 $this->choices2[$i] = $i;
1446 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
1449 function get_setting() {
1450 global $CFG;
1451 return (isset($CFG->{$this->name}) && isset($CFG->{$this->name2}) ? array('h' => $CFG->{$this->name}, 'm' => $CFG->{$this->name2}) : NULL);
1454 function write_setting($data) {
1455 // check that what we got was in the original choices
1456 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
1457 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1460 return (set_config($this->name, $data['h']) && set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1463 function output_html() {
1464 if ($this->get_setting() === NULL) {
1465 $currentsetting = $this->defaultsetting;
1466 } else {
1467 $currentsetting = $this->get_setting();
1469 $return = '<div class="form-group">'.
1470 '<select class="form-select" id="id_s_'.$this->name.'h" name="s_' . $this->name .'[h]">';
1471 foreach ($this->choices as $key => $value) {
1472 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['h'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1474 $return .= '</select>:<select class="form-select" id="id_s_'.$this->name.'m" name="s_' . $this->name . '[m]">';
1475 foreach ($this->choices2 as $key => $value) {
1476 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['m'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1478 $return .= '</select></div>';
1479 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1484 class admin_setting_configmultiselect extends admin_setting_configselect {
1486 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
1487 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1490 function get_setting() {
1491 global $CFG;
1492 return (isset($CFG->{$this->name}) ? explode(',', $CFG->{$this->name}) : NULL);;
1495 function write_setting($data) {
1496 foreach ($data as $datum) {
1497 if (! in_array($datum, array_keys($this->choices))) {
1498 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1502 return (set_config($this->name, implode(',',$data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1505 function output_html() {
1506 if ($this->get_setting() === NULL) {
1507 $currentsetting = $this->defaultsetting;
1508 } else {
1509 $currentsetting = $this->get_setting();
1511 $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'[]" size="10" multiple="multiple">';
1512 foreach ($this->choices as $key => $value) {
1513 $return .= '<option value="' . $key . '"' . (in_array($key,$currentsetting) ? ' selected="selected"' : '') . '>' . $value . '</option>';
1515 $return .= '</select>';
1516 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1521 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
1523 function admin_setting_special_adminseesall() {
1524 $name = 'calendar_adminseesall';
1525 $visiblename = get_string('adminseesall', 'admin');
1526 $description = get_string('helpadminseesall', 'admin');
1527 parent::admin_setting($name, $visiblename, $description, 0);
1530 function write_setting($data) {
1531 global $SESSION;
1532 unset($SESSION->cal_courses_shown);
1533 parent::write_setting($data);
1537 class admin_setting_sitesetselect extends admin_setting_configselect {
1539 var $id;
1541 function admin_setting_sitesetselect($name, $visiblename, $description, $defaultsetting, $choices) {
1543 $this->id = SITEID;
1544 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1548 function get_setting() {
1549 $site = get_site();
1550 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1553 function write_setting($data) {
1554 if (!in_array($data, array_keys($this->choices))) {
1555 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1557 $record = new stdClass();
1558 $record->id = $this->id;
1559 $temp = $this->name;
1560 $record->$temp = $data;
1561 $record->timemodified = time();
1562 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1568 class admin_setting_courselist_frontpage extends admin_setting_configselect {
1570 function admin_setting_courselist_frontpage($loggedin) {
1571 global $CFG;
1572 require_once($CFG->dirroot . '/course/lib.php');
1573 $name = 'frontpage' . ($loggedin ? 'loggedin' : '');
1574 $visiblename = get_string('frontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1575 $description = get_string('configfrontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1576 $choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
1577 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
1578 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
1579 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
1580 '' => get_string('none'));
1581 if (count_records("course") > FRONTPAGECOURSELIMIT) {
1582 unset($choices[FRONTPAGECOURSELIST]);
1584 $defaults = FRONTPAGECOURSELIST.',,,';
1585 parent::admin_setting_configselect($name, $visiblename, $description, $defaults, $choices);
1588 function get_setting() {
1589 global $CFG;
1590 return (isset($CFG->{$this->name}) ? explode(',', $CFG->{$this->name}) : ',1,,');
1593 function write_setting($data) {
1594 if (empty($data)) {
1595 $data = array();
1596 } if (!is_array($data)) {
1597 $data = explode(',', $data);
1599 foreach($data as $datum) {
1600 if (! in_array($datum, array_keys($this->choices))) {
1601 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1604 return (set_config($this->name, implode(',', $data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1607 function output_html() {
1608 if ($this->get_setting() === NULL) {
1609 $currentsetting = $this->defaultsetting;
1610 } else {
1611 $currentsetting = $this->get_setting();
1613 for ($i = 0; $i < count($this->choices) - 1; $i++) {
1614 if (!isset($currentsetting[$i])) {
1615 $currentsetting[$i] = 0;
1618 $return = '<div class="form-group">';
1619 for ($i = 0; $i < count($this->choices) - 1; $i++) {
1620 $return .='<select class="form-select" id="id_s_'.$this->name.$i.'" name="s_' . $this->name .'[]">';
1621 foreach ($this->choices as $key => $value) {
1622 $return .= '<option value="' . $key . '"' . ($key == $currentsetting[$i] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1624 $return .= '</select>';
1625 if ($i !== count($this->choices) - 2) {
1626 $return .= '<br />';
1629 $return .= '</div>';
1631 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1635 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
1637 var $id;
1639 function admin_setting_sitesetcheckbox($name, $visiblename, $description, $defaultsetting) {
1641 $this->id = SITEID;
1642 parent::admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting);
1646 function get_setting() {
1647 $site = get_site();
1648 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1651 function write_setting($data) {
1652 $record = new stdClass();
1653 $record->id = $this->id;
1654 $temp = $this->name;
1655 $record->$temp = ($data == '1' ? 1 : 0);
1656 $record->timemodified = time();
1657 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1662 class admin_setting_sitesettext extends admin_setting_configtext {
1664 var $id;
1666 function admin_setting_sitesettext($name, $visiblename, $description, $defaultsetting) {
1668 $this->id = SITEID;
1669 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting);
1673 function get_setting() {
1674 $site = get_site();
1675 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1678 function validate($data) {
1679 $cleaned = clean_param($data, PARAM_NOTAGS);
1680 if ($cleaned == '') {
1681 return false; // can not be empty
1683 return ("$data" == "$cleaned"); // implicit conversion to string is needed to do exact comparison
1686 function write_setting($data) {
1687 $data = trim($data);
1688 if (!$this->validate($data)) {
1689 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
1692 $record = new stdClass();
1693 $record->id = $this->id;
1694 $record->{$this->name} = $data;
1695 $record->timemodified = time();
1696 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1701 class admin_setting_special_frontpagedesc extends admin_setting {
1703 var $id;
1705 function admin_setting_special_frontpagedesc() {
1706 $this->id = SITEID;
1707 $name = 'summary';
1708 $visiblename = get_string('frontpagedescription');
1709 $description = get_string('frontpagedescriptionhelp');
1710 parent::admin_setting($name, $visiblename, $description, '');
1713 function output_html() {
1715 global $CFG;
1717 if ($this->get_setting() === NULL) {
1718 $currentsetting = $this->defaultsetting;
1719 } else {
1720 $currentsetting = $this->get_setting();
1723 $CFG->adminusehtmleditor = can_use_html_editor();
1725 $return = print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, 's_' . $this->name, $currentsetting, 0, true);
1727 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1730 function get_setting() {
1732 $site = get_site();
1733 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1737 function write_setting($data) {
1739 $data = addslashes(clean_param($data, PARAM_CLEANHTML));
1741 $record = new stdClass();
1742 $record->id = $this->id;
1743 $temp = $this->name;
1744 $record->$temp = $data;
1745 $record->timemodified = time();
1747 return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1754 class admin_setting_special_editorfontlist extends admin_setting {
1756 var $items;
1758 function admin_setting_special_editorfontlist() {
1759 global $CFG;
1760 $name = 'editorfontlist';
1761 $visiblename = get_string('editorfontlist', 'admin');
1762 $description = get_string('configeditorfontlist', 'admin');
1763 $defaults = array('k0' => 'Trebuchet',
1764 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
1765 'k1' => 'Arial',
1766 'v1' => 'arial,helvetica,sans-serif',
1767 'k2' => 'Courier New',
1768 'v2' => 'courier new,courier,monospace',
1769 'k3' => 'Georgia',
1770 'v3' => 'georgia,times new roman,times,serif',
1771 'k4' => 'Tahoma',
1772 'v4' => 'tahoma,arial,helvetica,sans-serif',
1773 'k5' => 'Times New Roman',
1774 'v5' => 'times new roman,times,serif',
1775 'k6' => 'Verdana',
1776 'v6' => 'verdana,arial,helvetica,sans-serif',
1777 'k7' => 'Impact',
1778 'v7' => 'impact',
1779 'k8' => 'Wingdings',
1780 'v8' => 'wingdings');
1781 parent::admin_setting($name, $visiblename, $description, $defaults);
1784 function get_setting() {
1785 global $CFG;
1786 if (isset($CFG->editorfontlist)) {
1787 $i = 0;
1788 $currentsetting = array();
1789 $items = explode(';', $CFG->editorfontlist);
1790 foreach ($items as $item) {
1791 $item = explode(':', $item);
1792 $currentsetting['k' . $i] = $item[0];
1793 $currentsetting['v' . $i] = $item[1];
1794 $i++;
1796 return $currentsetting;
1797 } else {
1798 return NULL;
1802 function write_setting($data) {
1804 // there miiight be an easier way to do this :)
1805 // if this is changed, make sure the $defaults array above is modified so that this
1806 // function processes it correctly
1808 $keys = array();
1809 $values = array();
1811 foreach ($data as $key => $value) {
1812 if (substr($key,0,1) == 'k') {
1813 $keys[substr($key,1)] = $value;
1814 } elseif (substr($key,0,1) == 'v') {
1815 $values[substr($key,1)] = $value;
1819 $result = '';
1820 for ($i = 0; $i < count($keys); $i++) {
1821 if (($keys[$i] !== '') && ($values[$i] !== '')) {
1822 $result .= clean_param($keys[$i],PARAM_NOTAGS) . ':' . clean_param($values[$i], PARAM_NOTAGS) . ';';
1826 $result = substr($result, 0, -1); // trim the last semicolon
1828 return (set_config($this->name, $result) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1831 function output_html() {
1833 if ($this->get_setting() === NULL) {
1834 $currentsetting = $this->defaultsetting;
1835 } else {
1836 $currentsetting = $this->get_setting();
1839 $return = '<div class="form-group">';
1840 for ($i = 0; $i < count($currentsetting) / 2; $i++) {
1841 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="' . $currentsetting['k' . $i] . '" />';
1842 $return .= '&nbsp;&nbsp;';
1843 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="' . $currentsetting['v' . $i] . '" /><br />';
1845 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="" />';
1846 $return .= '&nbsp;&nbsp;';
1847 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="" /><br />';
1848 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . ($i + 1) . ']" value="" />';
1849 $return .= '&nbsp;&nbsp;';
1850 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . ($i + 1) . ']" value="" />';
1851 $return .= '</div>';
1853 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1858 class admin_setting_special_editordictionary extends admin_setting_configselect {
1860 function admin_setting_special_editordictionary() {
1861 $name = 'editordictionary';
1862 $visiblename = get_string('editordictionary','admin');
1863 $description = get_string('configeditordictionary', 'admin');
1864 $choices = $this->editor_get_dictionaries();
1865 if (! is_array($choices)) {
1866 $choices = array('');
1869 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
1872 // function borrowed from the old moodle/admin/editor.php, slightly modified
1873 function editor_get_dictionaries () {
1874 /// Get all installed dictionaries in the system
1876 global $CFG;
1878 // error_reporting(E_ALL); // for debug, final version shouldn't have this...
1879 clearstatcache();
1881 // If aspellpath isn't set don't even bother ;-)
1882 if (empty($CFG->aspellpath)) {
1883 return 'Empty aspell path!';
1886 // Do we have access to popen function?
1887 if (!function_exists('popen')) {
1888 return 'Popen function disabled!';
1891 $cmd = $CFG->aspellpath;
1892 $output = '';
1893 $dictionaries = array();
1894 $dicts = array();
1896 if(!($handle = @popen(escapeshellarg($cmd) .' dump dicts', 'r'))) {
1897 return 'Couldn\'t create handle!';
1900 while(!feof($handle)) {
1901 $output .= fread($handle, 1024);
1903 @pclose($handle);
1905 $dictionaries = explode(chr(10), $output);
1907 // Get rid of possible empty values
1908 if (is_array($dictionaries)) {
1910 $cnt = count($dictionaries);
1912 for ($i = 0; $i < $cnt; $i++) {
1913 if (!empty($dictionaries[$i])) {
1914 $dicts[] = $dictionaries[$i];
1919 if (count($dicts) >= 1) {
1920 return $dicts;
1923 return 'Error! Check your aspell installation!';
1931 class admin_setting_special_editorhidebuttons extends admin_setting {
1933 var $name;
1934 var $visiblename;
1935 var $description;
1936 var $items;
1938 function admin_setting_special_editorhidebuttons() {
1939 $this->name = 'editorhidebuttons';
1940 $this->visiblename = get_string('editorhidebuttons', 'admin');
1941 $this->description = get_string('confeditorhidebuttons', 'admin');
1942 $this->defaultsetting = array();
1943 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
1944 $this->items = array('fontname' => '',
1945 'fontsize' => '',
1946 'formatblock' => '',
1947 'bold' => 'ed_format_bold.gif',
1948 'italic' => 'ed_format_italic.gif',
1949 'underline' => 'ed_format_underline.gif',
1950 'strikethrough' => 'ed_format_strike.gif',
1951 'subscript' => 'ed_format_sub.gif',
1952 'superscript' => 'ed_format_sup.gif',
1953 'copy' => 'ed_copy.gif',
1954 'cut' => 'ed_cut.gif',
1955 'paste' => 'ed_paste.gif',
1956 'clean' => 'ed_wordclean.gif',
1957 'undo' => 'ed_undo.gif',
1958 'redo' => 'ed_redo.gif',
1959 'justifyleft' => 'ed_align_left.gif',
1960 'justifycenter' => 'ed_align_center.gif',
1961 'justifyright' => 'ed_align_right.gif',
1962 'justifyfull' => 'ed_align_justify.gif',
1963 'lefttoright' => 'ed_left_to_right.gif',
1964 'righttoleft' => 'ed_right_to_left.gif',
1965 'insertorderedlist' => 'ed_list_num.gif',
1966 'insertunorderedlist' => 'ed_list_bullet.gif',
1967 'outdent' => 'ed_indent_less.gif',
1968 'indent' => 'ed_indent_more.gif',
1969 'forecolor' => 'ed_color_fg.gif',
1970 'hilitecolor' => 'ed_color_bg.gif',
1971 'inserthorizontalrule' => 'ed_hr.gif',
1972 'createanchor' => 'ed_anchor.gif',
1973 'createlink' => 'ed_link.gif',
1974 'unlink' => 'ed_unlink.gif',
1975 'insertimage' => 'ed_image.gif',
1976 'inserttable' => 'insert_table.gif',
1977 'insertsmile' => 'em.icon.smile.gif',
1978 'insertchar' => 'icon_ins_char.gif',
1979 'spellcheck' => 'spell-check.gif',
1980 'htmlmode' => 'ed_html.gif',
1981 'popupeditor' => 'fullscreen_maximize.gif',
1982 'search_replace' => 'ed_replace.gif');
1985 function get_setting() {
1986 global $CFG;
1987 return (isset($CFG->{$this->name}) ? explode(' ', $CFG->{$this->name}) : NULL);
1990 function write_setting($data) {
1991 $result = array();
1992 if (empty($data)) { $data = array(); }
1993 foreach ($data as $key => $value) {
1994 if (!in_array($key, array_keys($this->items))) {
1995 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1997 if ($value == '1') {
1998 $result[] = $key;
2001 return (set_config($this->name, implode(' ',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2004 function output_html() {
2006 global $CFG;
2008 // checkboxes with input name="$this->name[$key]" value="1"
2009 // we do 15 fields per column
2011 if ($this->get_setting() === NULL) {
2012 $currentsetting = $this->defaultsetting;
2013 } else {
2014 $currentsetting = $this->get_setting();
2017 $return = '<div class="form-group">';
2018 $return .= '<table><tr><td valign="top" align="right">';
2020 $count = 0;
2022 foreach($this->items as $key => $value) {
2023 if ($count % 15 == 0) {
2024 $return .= '</div></td><td valign="top" align="right">';
2027 $return .= ($value == '' ? get_string($key,'editor') : '<img width="18" height="18" src="' . $CFG->wwwroot . '/lib/editor/htmlarea/images/' . $value . '" alt="' . get_string($key,'editor') . '" title="' . get_string($key,'editor') . '" />') . '&nbsp;';
2028 $return .= '<input type="checkbox" class="form-checkbox" value="1" id="id_s_'.$this->name.$key.'" name="s_' . $this->name . '[' . $key . ']"' . (in_array($key,$currentsetting) ? ' checked="checked"' : '') . ' />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
2029 $count++;
2030 if ($count % 15 != 0) {
2031 $return .= '<br /><br />';
2035 $return .= '</td></tr>';
2036 $return .= '</table>';
2037 $return .= '</div>';
2039 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2044 class admin_setting_backupselect extends admin_setting_configselect {
2046 function admin_setting_backupselect($name, $visiblename, $description, $default, $choices) {
2047 parent::admin_setting_configselect($name, $visiblename, $description, $default, $choices);
2050 function get_setting() {
2051 $backup_config = backup_get_config();
2052 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2055 function write_setting($data) {
2056 // check that what we got was in the original choices
2057 if (! in_array($data, array_keys($this->choices))) {
2058 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2061 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2066 class admin_setting_special_backupsaveto extends admin_setting_configtext {
2068 function admin_setting_special_backupsaveto() {
2069 $name = 'backup_sche_destination';
2070 $visiblename = get_string('saveto');
2071 $description = get_string('backupsavetohelp');
2072 parent::admin_setting_configtext($name, $visiblename, $description, '', PARAM_PATH);
2075 function get_setting() {
2076 $backup_config = backup_get_config();
2077 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2080 function write_setting($data) {
2081 $data = clean_param($data, PARAM_PATH);
2082 if (!empty($data) and (substr($data,-1) == '/' or substr($data,-1) == '\\')) {
2083 return get_string('pathslasherror') . '<br />';
2084 } else if (!empty($data) and !is_dir($data)) {
2085 return get_string('pathnotexists') . '<br />';
2087 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2092 class admin_setting_backupcheckbox extends admin_setting_configcheckbox {
2094 function admin_setting_backupcheckbox($name, $visiblename, $description, $default) {
2095 parent::admin_setting_configcheckbox($name, $visiblename, $description, $default);
2098 function write_setting($data) {
2099 if ($data == '1') {
2100 return (backup_set_config($this->name, 1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2101 } else {
2102 return (backup_set_config($this->name, 0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2106 function get_setting() {
2107 $backup_config = backup_get_config();
2108 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2113 class admin_setting_special_backuptime extends admin_setting_configtime {
2115 function admin_setting_special_backuptime() {
2116 $name = 'backup_sche_hour';
2117 $name2 = 'backup_sche_minute';
2118 $visiblename = get_string('executeat');
2119 $description = get_string('backupexecuteathelp');
2120 $default = array('h' => 0, 'm' => 0);
2121 parent::admin_setting_configtime($name, $name2, $visiblename, $description, $default);
2124 function get_setting() {
2125 $backup_config = backup_get_config();
2126 return (isset($backup_config->{$this->name}) && isset($backup_config->{$this->name}) ? array('h'=>$backup_config->{$this->name}, 'm'=>$backup_config->{$this->name2}) : NULL);
2129 function write_setting($data) {
2130 // check that what we got was in the original choices
2131 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
2132 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2135 return (backup_set_config($this->name, $data['h']) && backup_set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2140 class admin_setting_special_backupdays extends admin_setting {
2142 function admin_setting_special_backupdays() {
2143 $name = 'backup_sche_weekdays';
2144 $visiblename = get_string('schedule');
2145 $description = get_string('backupschedulehelp');
2146 $default = array('u' => 0, 'm' => 0, 't' => 0, 'w' => 0, 'r' => 0, 'f' => 0, 's' => 0);
2147 parent::admin_setting($name, $visiblename, $description, $default);
2150 function get_setting() {
2151 $backup_config = backup_get_config();
2152 if (isset($backup_config->{$this->name})) {
2153 $currentsetting = $backup_config->{$this->name};
2154 return array('u' => substr($currentsetting, 0, 1),
2155 'm' => substr($currentsetting, 1, 1),
2156 't' => substr($currentsetting, 2, 1),
2157 'w' => substr($currentsetting, 3, 1),
2158 'r' => substr($currentsetting, 4, 1),
2159 'f' => substr($currentsetting, 5, 1),
2160 's' => substr($currentsetting, 6, 1));
2161 } else {
2162 return NULL;
2166 function output_html() {
2168 if ($this->get_setting() === NULL) {
2169 $currentsetting = $this->defaultsetting;
2170 } else {
2171 $currentsetting = $this->get_setting();
2174 // rewrite for simplicity
2175 $currentsetting = $currentsetting['u'] . $currentsetting['m'] . $currentsetting['t'] . $currentsetting['w'] .
2176 $currentsetting['r'] . $currentsetting['f'] . $currentsetting['s'];
2178 $return = '<table><tr><td><div align="center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2179 get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2180 get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2181 get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2182 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'u" name="s_'. $this->name .'[u]" value="1" ' . (substr($currentsetting,0,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2183 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'m" name="s_'. $this->name .'[m]" value="1" ' . (substr($currentsetting,1,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2184 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'t" name="s_'. $this->name .'[t]" value="1" ' . (substr($currentsetting,2,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2185 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'w" name="s_'. $this->name .'[w]" value="1" ' . (substr($currentsetting,3,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2186 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'r" name="s_'. $this->name .'[r]" value="1" ' . (substr($currentsetting,4,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2187 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'f" name="s_'. $this->name .'[f]" value="1" ' . (substr($currentsetting,5,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2188 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'s" name="s_'. $this->name .'[s]" value="1" ' . (substr($currentsetting,6,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2189 '</tr></table>';
2191 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2195 // we're using the array trick (see http://ca.php.net/manual/en/faq.html.php#faq.html.arrays) to get the data passed to use without having to modify
2196 // admin_settingpage (note that admin_settingpage only calls write_setting with the data that matches $this->name... so if we have multiple form fields,
2197 // they MUST go into an array named $this->name, or else we won't receive them here
2198 function write_setting($data) {
2199 $week = 'umtwrfs';
2200 $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
2201 if (!empty($data)) {
2202 foreach($data as $key => $value) {
2203 if ($value == '1') {
2204 $result[strpos($week, $key)] = 1;
2208 return (backup_set_config($this->name, implode('',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2212 class admin_setting_special_debug extends admin_setting_configselect {
2214 function admin_setting_special_debug() {
2215 $name = 'debug';
2216 $visiblename = get_string('debug', 'admin');
2217 $description = get_string('configdebug', 'admin');
2218 $choices = array( DEBUG_NONE => get_string('debugnone', 'admin'),
2219 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
2220 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
2221 DEBUG_ALL => get_string('debugall', 'admin'),
2222 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin')
2224 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
2227 function get_setting() {
2228 global $CFG;
2229 if (isset($CFG->debug)) {
2230 return $CFG->debug;
2231 } else {
2232 return NULL;
2236 function write_setting($data) {
2237 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2243 class admin_setting_special_calendar_weekend extends admin_setting {
2245 function admin_setting_special_calendar_weekend() {
2246 $name = 'calendar_weekend';
2247 $visiblename = get_string('calendar_weekend', 'admin');
2248 $description = get_string('helpweekenddays', 'admin');
2249 parent::admin_setting($name, $visiblename, $description, array('u' => 1, 's' => 1));
2252 function get_setting() {
2253 global $CFG;
2254 if (isset($CFG->{$this->name})) {
2255 $setting = intval($CFG->{$this->name});
2256 return array('u' => $setting & 1, 'm' => $setting & 2, 't' => $setting & 4, 'w' => $setting & 8, 'r' => $setting & 16, 'f' => $setting & 32, 's' => $setting & 64);
2257 } else {
2258 return NULL;
2262 function write_setting($data) {
2263 $week = 'umtwrfs';
2264 $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
2265 foreach($data as $key => $value) {
2266 if ($value == '1') {
2267 $result[strpos($week, $key)] = 1;
2270 return (set_config($this->name, bindec(implode('',$result))) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2273 function output_html() {
2275 if ($this->get_setting() === NULL) {
2276 $currentsetting = $this->defaultsetting;
2277 } else {
2278 $currentsetting = $this->get_setting();
2281 foreach(array('u','m','t','w','r','f','s') as $element) {
2282 if (!isset($currentsetting[$element])) {
2283 $currentsetting[$element] = 0;
2287 $return = '<table><tr><td><div align="center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2288 get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2289 get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2290 get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2291 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'u" name="s_'. $this->name .'[u]" value="1" ' . ($currentsetting['u'] ? 'checked="checked"' : '') . ' /></div></td>' .
2292 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'m" name="s_'. $this->name .'[m]" value="1" ' . ($currentsetting['m'] ? 'checked="checked"' : '') . ' /></div></td>' .
2293 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'t" name="s_'. $this->name .'[t]" value="1" ' . ($currentsetting['t'] ? 'checked="checked"' : '') . ' /></div></td>' .
2294 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'w" name="s_'. $this->name .'[w]" value="1" ' . ($currentsetting['w'] ? 'checked="checked"' : '') . ' /></div></td>' .
2295 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'r" name="s_'. $this->name .'[r]" value="1" ' . ($currentsetting['r'] ? 'checked="checked"' : '') . ' /></div></td>' .
2296 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'f" name="s_'. $this->name .'[f]" value="1" ' . ($currentsetting['f'] ? 'checked="checked"' : '') . ' /></div></td>' .
2297 '<td><div align="center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'s" name="s_'. $this->name .'[s]" value="1" ' . ($currentsetting['s'] ? 'checked="checked"' : '') . ' /></div></td>' .
2298 '</tr></table>';
2300 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2307 * this is used in config->appearance->gradeconfig
2309 class admin_setting_special_gradebookroles extends admin_setting {
2311 function admin_setting_special_gradebookroles() {
2312 $name = 'gradebookroles';
2313 $visiblename = get_string('gradebookroles', 'admin');
2314 $description = get_string('configgradebookroles', 'admin');
2315 $default = array(5=>'1'); // The student role in a default install
2317 parent::admin_setting($name, $visiblename, $description, $default);
2320 function get_setting() {
2321 global $CFG;
2322 if (!empty($CFG->{$this->name})) {
2323 return explode(',', $CFG->{$this->name});
2324 } else {
2325 return null;
2329 function write_setting($data) {
2330 if (!empty($data)) {
2331 $str = '';
2332 foreach ($data as $key => $value) {
2333 if ($value) {
2334 $str .= $key.',';
2337 return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2338 } else {
2339 return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2343 function output_html() {
2345 if ($this->get_setting() === NULL) {
2346 $currentsetting = $this->defaultsetting;
2347 } else {
2348 $currentsetting = $this->get_setting();
2351 // from to process which roles to display
2352 if ($roles = get_records('role')) {
2353 $return = '<div class="form-group">';
2354 $first = true;
2355 foreach ($roles as $roleid=>$role) {
2356 if (is_array($currentsetting) && in_array($roleid, $currentsetting)) {
2357 $checked = 'checked="checked"';
2358 } else {
2359 $checked = '';
2361 if ($first) {
2362 $first = false;
2363 } else {
2364 $return .= '<br />';
2366 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$roleid.']" value="1" '.$checked.'>&nbsp;'.$role->name;
2368 $return .= '</div>';
2371 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2377 class admin_setting_special_perfdebug extends admin_setting_configcheckbox {
2379 function admin_setting_special_perfdebug() {
2380 $name = 'perfdebug';
2381 $visiblename = get_string('perfdebug', 'admin');
2382 $description = get_string('configperfdebug', 'admin');
2383 parent::admin_setting_configcheckbox($name, $visiblename, $description, '');
2386 function write_setting($data) {
2387 if ($data == '1') {
2388 return (set_config($this->name,15) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2389 } else {
2390 return (set_config($this->name,7) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2394 function output_html() {
2395 if ($this->get_setting() === NULL) {
2396 $currentsetting = $this->defaultsetting;
2397 } else {
2398 $currentsetting = $this->get_setting();
2401 $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 15 ? 'checked="checked"' : '') . ' />';
2402 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2407 // Code for a function that helps externalpages print proper headers and footers
2408 // N.B.: THIS FUNCTION HANDLES AUTHENTICATION
2409 function admin_externalpage_setup($section, $adminroot) {
2411 global $CFG, $PAGE, $USER;
2413 require_once($CFG->libdir . '/blocklib.php');
2414 require_once($CFG->dirroot . '/'.$CFG->admin.'/pagelib.php');
2416 page_map_class(PAGE_ADMIN, 'page_admin');
2418 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
2420 $PAGE->init_extra($section); // hack alert!
2422 $root = $adminroot->locate($PAGE->section);
2424 if ($site = get_site()) {
2425 require_login();
2426 } else {
2427 redirect($CFG->wwwroot . '/'.$CFG->admin.'/index.php');
2428 die;
2431 if (!is_a($root, 'admin_externalpage')) {
2432 error(get_string('sectionerror','admin'));
2433 die;
2436 // this eliminates our need to authenticate on the actual pages
2437 if (!($root->check_access())) {
2438 error(get_string('accessdenied', 'admin'));
2439 die;
2442 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
2444 if (!isset($USER->adminediting)) {
2445 $USER->adminediting = false;
2448 if ($PAGE->user_allowed_editing()) {
2449 if ($adminediting == 1) {
2450 $USER->adminediting = true;
2451 } elseif ($adminediting == 0) {
2452 $USER->adminediting = false;
2458 function admin_externalpage_print_header($adminroot) {
2460 global $CFG, $PAGE, $SITE;
2462 if (!empty($SITE->fullname)) {
2463 $pageblocks = blocks_setup($PAGE);
2465 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
2466 BLOCK_L_MAX_WIDTH);
2468 $PAGE->print_header();
2469 echo '<table id="layout-table"><tr>';
2470 echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">';
2471 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
2472 echo '</td>';
2473 echo '<td id="middle-column">';
2474 } else {
2475 print_header();
2480 function admin_externalpage_print_footer($adminroot) {
2482 global $CFG, $PAGE, $SITE;
2484 if (!empty($SITE->fullname)) {
2485 $pageblocks = blocks_setup($PAGE);
2486 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
2487 BLOCK_R_MAX_WIDTH);
2488 echo '</td>';
2489 echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">';
2490 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
2491 echo '</td></tr></table>';
2494 print_footer();
2497 function admin_get_root() {
2498 global $CFG;
2500 static $ADMIN;
2502 if (!isset($ADMIN)) {
2503 // start the admin tree!
2504 $ADMIN = new admin_category('root', get_string("administration"));
2505 // we process this file first to get categories up and running
2506 include($CFG->dirroot . '/'.$CFG->admin.'/settings/top.php');
2508 // now we process all other files in admin/settings to build the
2509 // admin tree
2510 foreach (glob($CFG->dirroot . '/'.$CFG->admin.'/settings/*.php') as $file) {
2511 if ($file != $CFG->dirroot . '/'.$CFG->admin.'/settings/top.php') {
2512 include_once($file);
2517 return $ADMIN;
2520 /// settings utiliti functions
2522 // n.b. this function unconditionally applies default settings
2523 function apply_default_settings(&$node) {
2525 global $CFG;
2527 if (is_a($node, 'admin_category')) {
2528 $entries = array_keys($node->children);
2529 foreach ($entries as $entry) {
2530 apply_default_settings($node->children[$entry]);
2532 return;
2535 if (is_a($node, 'admin_settingpage')) {
2536 foreach ($node->settings as $setting) {
2537 $CFG->{$setting->name} = $setting->defaultsetting;
2538 $setting->write_setting($setting->defaultsetting);
2539 unset($setting); // needed to prevent odd (imho) reference behaviour
2540 // see http://www.php.net/manual/en/language.references.whatdo.php#AEN6399
2542 return;
2545 return;
2549 // n.b. this function unconditionally applies default settings
2550 function apply_default_exception_settings($defaults) {
2552 global $CFG;
2554 foreach($defaults as $key => $value) {
2555 $CFG->$key = $value;
2556 set_config($key, $value);
2561 function format_admin_setting($name, $title='', $form='', $description='') {
2562 return "\n".
2563 '<div class="form-item" id="admin-'.$name.'">'."\n".
2564 '<label for="id_s_'.$name.'">'.$title."\n".
2565 ' <span class="form-shortname">'.$name.'</span>'."\n".
2566 '</label>'."\n".
2567 $form."\n".
2568 '<div class="description">'.$description.'</div>'."\n".
2569 '</div>'.
2570 "\n\n";