MDL-11082 Improved groups upgrade performance 1.8x -> 1.9; thanks Eloy for telling...
[moodle-pu.git] / lib / adminlib.php
blobd0c876b52c1913479a96eec399873b67a9544e8d
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 $plugs = get_list_of_plugins($dir);
25 $updated_plugins = false;
26 $strpluginsetup = get_string('pluginsetup');
28 foreach ($plugs as $plug) {
30 $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
32 unset($plugin);
34 if (is_readable($fullplug .'/version.php')) {
35 include_once($fullplug .'/version.php'); // defines $plugin with version etc
36 } else {
37 continue; // Nothing to do.
40 $oldupgrade = false;
41 $newupgrade = false;
42 if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) {
43 include_once($fullplug . '/db/'. $CFG->dbtype . '.php'); // defines old upgrading function
44 $oldupgrade = true;
46 if (is_readable($fullplug . '/db/upgrade.php')) {
47 include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
48 $newupgrade = true;
51 if (!isset($plugin)) {
52 continue;
55 if (!empty($plugin->requires)) {
56 if ($plugin->requires > $CFG->version) {
57 $info = new object();
58 $info->pluginname = $plug;
59 $info->pluginversion = $plugin->version;
60 $info->currentmoodle = $CFG->version;
61 $info->requiremoodle = $plugin->requires;
62 if (!$updated_plugins) {
63 print_header($strpluginsetup, $strpluginsetup,
64 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
65 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
67 upgrade_log_start();
68 notify(get_string('pluginrequirementsnotmet', 'error', $info));
69 $updated_plugins = true;
70 continue;
74 $plugin->name = $plug; // The name MUST match the directory
76 $pluginversion = $type.'_'.$plug.'_version';
78 if (!isset($CFG->$pluginversion)) {
79 set_config($pluginversion, 0);
82 if ($CFG->$pluginversion == $plugin->version) {
83 // do nothing
84 } else if ($CFG->$pluginversion < $plugin->version) {
85 if (!$updated_plugins) {
86 print_header($strpluginsetup, $strpluginsetup,
87 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
88 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
90 $updated_plugins = true;
91 upgrade_log_start();
92 print_heading($dir.'/'. $plugin->name .' plugin needs upgrading');
93 $db->debug = true;
94 @set_time_limit(0); // To allow slow databases to complete the long SQL
96 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
97 /// Both old .sql files and new install.xml are supported
98 /// but we priorize install.xml (XMLDB) if present
99 $status = false;
100 if (file_exists($fullplug . '/db/install.xml')) {
101 $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
102 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
103 $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
104 } else {
105 $status = true;
108 $db->debug = false;
109 /// Continue with the instalation, roles and other stuff
110 if ($status) {
111 /// OK so far, now update the plugins record
112 set_config($pluginversion, $plugin->version);
114 /// Install capabilities
115 if (!update_capabilities($type.'/'.$plug)) {
116 error('Could not set up the capabilities for '.$plugin->name.'!');
118 /// Install events
119 events_update_definition($type.'/'.$plug);
121 /// Run local install function if there is one
122 if (is_readable($fullplug .'/lib.php')) {
123 include_once($fullplug .'/lib.php');
124 $installfunction = $plugin->name.'_install';
125 if (function_exists($installfunction)) {
126 if (! $installfunction() ) {
127 notify('Encountered a problem running install function for '.$module->name.'!');
132 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
133 } else {
134 notify('Installing '. $plugin->name .' FAILED!');
136 } else { // Upgrade existing install
137 /// Run de old and new upgrade functions for the module
138 $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade';
139 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
141 /// First, the old function if exists
142 $oldupgrade_status = true;
143 if ($oldupgrade && function_exists($oldupgrade_function)) {
144 $db->debug = true;
145 $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
146 } else if ($oldupgrade) {
147 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
148 $fullplug . '/db/' . $CFG->dbtype . '.php');
151 /// Then, the new function if exists and the old one was ok
152 $newupgrade_status = true;
153 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
154 $db->debug = true;
155 $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
156 } else if ($newupgrade) {
157 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
158 $fullplug . '/db/upgrade.php');
161 $db->debug=false;
162 /// Now analyze upgrade results
163 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
164 // OK so far, now update the plugins record
165 set_config($pluginversion, $plugin->version);
166 if (!update_capabilities($type.'/'.$plug)) {
167 error('Could not update '.$plugin->name.' capabilities!');
169 events_update_definition($type.'/'.$plug);
170 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
171 } else {
172 notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
175 echo '<hr />';
176 } else {
177 upgrade_log_start();
178 error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
182 upgrade_log_finish();
184 if ($updated_plugins) {
185 print_continue($return);
186 print_footer('none');
187 die;
192 * Find and check all modules and load them up or upgrade them if necessary
194 * @uses $db
195 * @uses $CFG
196 * @param string $return The url to prompt the user to continue to
197 * @todo Finish documenting this function
199 function upgrade_activity_modules($return) {
201 global $CFG, $db;
203 if (!$mods = get_list_of_plugins('mod') ) {
204 error('No modules installed!');
207 $updated_modules = false;
208 $strmodulesetup = get_string('modulesetup');
210 foreach ($mods as $mod) {
212 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
213 continue;
216 $fullmod = $CFG->dirroot .'/mod/'. $mod;
218 unset($module);
220 if ( is_readable($fullmod .'/version.php')) {
221 include_once($fullmod .'/version.php'); // defines $module with version etc
222 } else {
223 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
224 continue;
227 $oldupgrade = false;
228 $newupgrade = false;
229 if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
230 include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function
231 $oldupgrade = true;
233 if ( is_readable($fullmod . '/db/upgrade.php')) {
234 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
235 $newupgrade = true;
238 if (!isset($module)) {
239 continue;
242 if (!empty($module->requires)) {
243 if ($module->requires > $CFG->version) {
244 $info = new object();
245 $info->modulename = $mod;
246 $info->moduleversion = $module->version;
247 $info->currentmoodle = $CFG->version;
248 $info->requiremoodle = $module->requires;
249 if (!$updated_modules) {
250 print_header($strmodulesetup, $strmodulesetup,
251 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
252 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
254 upgrade_log_start();
255 notify(get_string('modulerequirementsnotmet', 'error', $info));
256 $updated_modules = true;
257 continue;
261 $module->name = $mod; // The name MUST match the directory
263 include_once($fullmod.'/lib.php'); // defines upgrading and/or installing functions
265 if ($currmodule = get_record('modules', 'name', $module->name)) {
266 if ($currmodule->version == $module->version) {
267 // do nothing
268 } else if ($currmodule->version < $module->version) {
269 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
270 if (!$oldupgrade && !$newupgrade) {
271 notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' .
272 $fullmod . '/db/upgrade.php were not readable');
273 continue;
275 if (!$updated_modules) {
276 print_header($strmodulesetup, $strmodulesetup,
277 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
278 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
280 upgrade_log_start();
281 print_heading($module->name .' module needs upgrading');
283 /// Run de old and new upgrade functions for the module
284 $oldupgrade_function = $module->name . '_upgrade';
285 $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
287 /// First, the old function if exists
288 $oldupgrade_status = true;
289 if ($oldupgrade && function_exists($oldupgrade_function)) {
290 $db->debug = true;
291 $oldupgrade_status = $oldupgrade_function($currmodule->version, $module);
292 } else if ($oldupgrade) {
293 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
294 $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php');
297 /// Then, the new function if exists and the old one was ok
298 $newupgrade_status = true;
299 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
300 $db->debug = true;
301 $newupgrade_status = $newupgrade_function($currmodule->version, $module);
302 } else if ($newupgrade) {
303 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
304 $mod . ': ' . $fullmod . '/db/upgrade.php');
307 $db->debug=false;
308 /// Now analyze upgrade results
309 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
310 // OK so far, now update the modules record
311 $module->id = $currmodule->id;
312 if (! update_record('modules', $module)) {
313 error('Could not update '. $module->name .' record in modules table!');
315 remove_dir($CFG->dataroot . '/cache', true); // flush cache
316 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
317 echo '<hr />';
318 } else {
319 notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
322 /// Update the capabilities table?
323 if (!update_capabilities('mod/'.$module->name)) {
324 error('Could not update '.$module->name.' capabilities!');
326 events_update_definition('mod/'.$module->name);
328 $updated_modules = true;
330 } else {
331 upgrade_log_start();
332 error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
335 } else { // module not installed yet, so install it
336 if (!$updated_modules) {
337 print_header($strmodulesetup, $strmodulesetup,
338 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
339 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
341 upgrade_log_start();
342 print_heading($module->name);
343 $updated_modules = true;
344 $db->debug = true;
345 @set_time_limit(0); // To allow slow databases to complete the long SQL
347 /// Both old .sql files and new install.xml are supported
348 /// but we priorize install.xml (XMLDB) if present
349 if (file_exists($fullmod . '/db/install.xml')) {
350 $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
351 } else {
352 $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method
355 $db->debug = false;
357 /// Continue with the installation, roles and other stuff
358 if ($status) {
359 if ($module->id = insert_record('modules', $module)) {
361 /// Capabilities
362 if (!update_capabilities('mod/'.$module->name)) {
363 error('Could not set up the capabilities for '.$module->name.'!');
366 /// Events
367 events_update_definition('mod/'.$module->name);
369 /// Run local install function if there is one
370 $installfunction = $module->name.'_install';
371 if (function_exists($installfunction)) {
372 if (! $installfunction() ) {
373 notify('Encountered a problem running install function for '.$module->name.'!');
377 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
378 echo '<hr />';
379 } else {
380 error($module->name .' module could not be added to the module list!');
382 } else {
383 error($module->name .' tables could NOT be set up successfully!');
387 /// Check submodules of this module if necessary
389 $submoduleupgrade = $module->name.'_upgrade_submodules';
390 if (function_exists($submoduleupgrade)) {
391 $submoduleupgrade();
395 /// Run any defaults or final code that is necessary for this module
397 if ( is_readable($fullmod .'/defaults.php')) {
398 // Insert default values for any important configuration variables
399 unset($defaults);
400 include_once($fullmod .'/defaults.php');
401 if (!empty($defaults)) {
402 foreach ($defaults as $name => $value) {
403 if (!isset($CFG->$name)) {
404 set_config($name, $value);
411 upgrade_log_finish(); // finish logging if started
413 if ($updated_modules) {
414 print_continue($return);
415 print_footer('none');
416 die;
421 * This function will return FALSE if the lock fails to be set (ie, if it's already locked)
423 * @param string $name ?
424 * @param bool $value ?
425 * @param int $staleafter ?
426 * @param bool $clobberstale ?
427 * @todo Finish documenting this function
429 function set_cron_lock($name,$value=true,$staleafter=7200,$clobberstale=false) {
431 if (empty($name)) {
432 mtrace("Tried to get a cron lock for a null fieldname");
433 return false;
436 if (empty($value)) {
437 set_config($name,0);
438 return true;
441 if ($config = get_record('config','name',$name)) {
442 if (empty($config->value)) {
443 set_config($name,time());
444 } else {
445 // check for stale.
446 if ((time() - $staleafter) > $config->value) {
447 mtrace("STALE LOCKFILE FOR $name - was $config->value");
448 if (!empty($clobberstale)) {
449 set_config($name,time());
450 return true;
452 } else {
453 return false; // was not stale - ie, we're ok to still be running.
457 else {
458 set_config($name,time());
460 return true;
463 function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
464 static $starttime;
465 static $lasttime;
467 if ($total < 2) { // No need to show anything
468 return;
471 if (empty($starttime)) {
472 $starttime = $lasttime = time();
473 $lasttime = $starttime - $updatetime;
474 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
475 echo '<div id="bar'.$total.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
476 echo '<div id="slider'.$total.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
477 echo '</div>';
478 echo '<div id="text'.$total.'" align="center" style="width:500px;"></div>';
479 echo '</td></tr></table>';
480 echo '</div>';
483 $now = time();
485 if ($done && (($now - $lasttime) >= $updatetime)) {
486 $elapsedtime = $now - $starttime;
487 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
488 $percentage = round((float)$done / (float)$total, 2);
489 $width = (int)(500 * $percentage);
491 if ($projectedtime > 10) {
492 $projectedtext = ' Ending: '.format_time($projectedtime);
493 } else {
494 $projectedtext = '';
497 echo '<script>';
498 echo 'document.getElementById("text'.$total.'").innerHTML = "'.addslashes($donetext).' ('.$done.'/'.$total.') '.$projectedtext.'";'."\n";
499 echo 'document.getElementById("slider'.$total.'").style.width = \''.$width.'px\';'."\n";
500 echo '</script>';
502 $lasttime = $now;
503 sleep($sleeptime);
507 function upgrade_get_javascript() {
508 global $CFG;
510 if (!empty($_SESSION['installautopilot'])) {
511 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
512 } else {
513 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
515 $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>';
517 return $linktoscrolltoerrors;
520 function create_admin_user() {
521 global $CFG, $USER;
523 if (empty($CFG->rolesactive)) { // No admin user yet.
525 $user = new object();
526 $user->auth = 'manual';
527 $user->firstname = get_string('admin');
528 $user->lastname = get_string('user');
529 $user->username = 'admin';
530 $user->password = hash_internal_user_password('admin');
531 $user->email = 'root@localhost';
532 $user->confirmed = 1;
533 $user->mnethostid = $CFG->mnet_localhost_id;
534 $user->lang = $CFG->lang;
535 $user->maildisplay = 1;
536 $user->timemodified = time();
538 if (!$user->id = insert_record('user', $user)) {
539 error('SERIOUS ERROR: Could not create admin user record !!!');
542 if (!$user = get_record('user', 'id', $user->id)) { // Double check.
543 error('User ID was incorrect (can\'t find it)');
546 // Assign the default admin roles to the new user.
547 if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW)) {
548 error('No admin role could be found');
550 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
551 foreach ($adminroles as $adminrole) {
552 role_assign($adminrole->id, $user->id, 0, $sitecontext->id);
555 set_config('rolesactive', 1);
557 // Log the user in.
558 $USER = get_complete_user_data('username', 'admin');
559 $USER->newadminuser = 1;
560 load_all_capabilities();
562 redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id"); // Edit thyself
563 } else {
564 error('Can not create admin!');
568 ////////////////////////////////////////////////
569 /// upgrade logging functions
570 ////////////////////////////////////////////////
572 $upgradeloghandle = false;
573 $upgradelogbuffer = '';
574 // I did not find out how to use static variable in callback function,
575 // the problem was that I could not flush the static buffer :-(
576 global $upgradeloghandle, $upgradelogbuffer;
579 * Check if upgrade is already running.
581 * If anything goes wrong due to missing call to upgrade_log_finish()
582 * just restart the browser.
584 * @param string warning message indicating upgrade is already running
585 * @param int page reload timeout
587 function upgrade_check_running($message, $timeout) {
588 if (!empty($_SESSION['upgraderunning'])) {
589 print_header();
590 redirect(me(), $message, $timeout);
595 * Start logging of output into file (if not disabled) and
596 * prevent aborting and concurrent execution of upgrade script.
598 * Please note that you can not write into session variables after calling this function!
600 * This function may be called repeatedly.
602 function upgrade_log_start() {
603 global $CFG, $upgradeloghandle;
605 if (!empty($_SESSION['upgraderunning'])) {
606 return; // logging already started
609 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
610 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
611 if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
612 session_write_close(); // from now on user can reload page - will be displayed warning
614 make_upload_directory('upgradelogs');
615 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
616 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
620 * Terminate logging of output, flush all data, allow script aborting
621 * and reopen session for writing. Function error() does terminate the logging too.
623 * Please make sure that each upgrade_log_start() is properly terminated by
624 * this function or error().
626 * This function may be called repeatedly.
628 function upgrade_log_finish() {
629 global $CFG, $upgradeloghandle, $upgradelogbuffer;
631 if (empty($_SESSION['upgraderunning'])) {
632 return; // logging already terminated
635 @ob_end_flush();
636 if ($upgradelogbuffer !== '') {
637 @fwrite($upgradeloghandle, $upgradelogbuffer);
638 $upgradelogbuffer = '';
640 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
641 @fclose($upgradeloghandle);
642 $upgradeloghandle = false;
644 if (empty($CFG->dbsessions)) {
645 @session_start(); // ignore header errors, we only need to reopen session
647 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
648 if (connection_aborted()) {
649 die;
651 @ignore_user_abort(false);
655 * Callback function for logging into files. Not more than one file is created per minute,
656 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
658 * This function must not output any characters or throw warnigns and errors!
660 function upgrade_log_callback($string) {
661 global $CFG, $upgradeloghandle, $upgradelogbuffer;
663 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
664 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
665 $upgradelogbuffer .= $string;
666 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
667 @fwrite($upgradeloghandle, $upgradelogbuffer);
668 $upgradelogbuffer = '';
670 } else {
671 $upgradeloghandle = 'error';
674 return $string;
678 * Try to verify that dataroot is not accessible from web.
679 * It is not 100% correct but might help to reduce number of vulnerable sites.
681 * Protection from httpd.conf and .htaccess is not detected properly.
683 function is_dataroot_insecure() {
684 global $CFG;
686 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
688 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
689 $rp = strrev(trim($rp, '/'));
690 $rp = explode('/', $rp);
691 foreach($rp as $r) {
692 if (strpos($siteroot, '/'.$r.'/') === 0) {
693 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
694 } else {
695 break; // probably alias root
699 $siteroot = strrev($siteroot);
700 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
702 if (strpos($dataroot, $siteroot) === 0) {
703 return true;
705 return false;
708 /// =============================================================================================================
709 /// administration tree classes and functions
712 // n.b. documentation is still in progress for this code
714 /// INTRODUCTION
716 /// This file performs the following tasks:
717 /// -it defines the necessary objects and interfaces to build the Moodle
718 /// admin hierarchy
719 /// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
720 /// and admin_externalpage_print_footer() functions used on admin pages
722 /// ADMIN_SETTING OBJECTS
724 /// Moodle settings are represented by objects that inherit from the admin_setting
725 /// class. These objects encapsulate how to read a setting, how to write a new value
726 /// to a setting, and how to appropriately display the HTML to modify the setting.
728 /// ADMIN_SETTINGPAGE OBJECTS
730 /// The admin_setting objects are then grouped into admin_settingpages. The latter
731 /// appear in the Moodle admin tree block. All interaction with admin_settingpage
732 /// objects is handled by the admin/settings.php file.
734 /// ADMIN_EXTERNALPAGE OBJECTS
736 /// There are some settings in Moodle that are too complex to (efficiently) handle
737 /// with admin_settingpages. (Consider, for example, user management and displaying
738 /// lists of users.) In this case, we use the admin_externalpage object. This object
739 /// places a link to an external PHP file in the admin tree block.
741 /// If you're using an admin_externalpage object for some settings, you can take
742 /// advantage of the admin_externalpage_* functions. For example, suppose you wanted
743 /// to add a foo.php file into admin. First off, you add the following line to
744 /// admin/settings/first.php (at the end of the file) or to some other file in
745 /// admin/settings:
747 /// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
748 /// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
750 /// Next, in foo.php, your file structure would resemble the following:
752 /// require_once('.../config.php');
753 /// require_once($CFG->libdir.'/adminlib.php');
754 /// admin_externalpage_setup('foo');
755 /// // functionality like processing form submissions goes here
756 /// admin_externalpage_print_header();
757 /// // your HTML goes here
758 /// admin_externalpage_print_footer();
760 /// The admin_externalpage_setup() function call ensures the user is logged in,
761 /// and makes sure that they have the proper role permission to access the page.
763 /// The admin_externalpage_print_header() function prints the header (it figures
764 /// out what category and subcategories the page is classified under) and ensures
765 /// that you're using the admin pagelib (which provides the admin tree block and
766 /// the admin bookmarks block).
768 /// The admin_externalpage_print_footer() function properly closes the tables
769 /// opened up by the admin_externalpage_print_header() function and prints the
770 /// standard Moodle footer.
772 /// ADMIN_CATEGORY OBJECTS
774 /// Above and beyond all this, we have admin_category objects. These objects
775 /// appear as folders in the admin tree block. They contain admin_settingpage's,
776 /// admin_externalpage's, and other admin_category's.
778 /// OTHER NOTES
780 /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
781 /// from part_of_admin_tree (a pseudointerface). This interface insists that
782 /// a class has a check_access method for access permissions, a locate method
783 /// used to find a specific node in the admin tree, and a path method used
784 /// to determine the path to a specific node in the $ADMIN tree.
786 /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
787 /// interface ensures that the class implements a recursive add function which
788 /// accepts a part_of_admin_tree object and searches for the proper place to
789 /// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
791 /// Please note that the $this->name field of any part_of_admin_tree must be
792 /// UNIQUE throughout the ENTIRE admin tree.
794 /// The $this->name field of an admin_setting object (which is *not* part_of_
795 /// admin_tree) must be unique on the respective admin_settingpage where it is
796 /// used.
799 /// MISCELLANEOUS STUFF (used by classes defined below) ///////////////////////
800 include_once($CFG->dirroot . '/backup/lib.php');
802 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
805 * Pseudointerface for anything appearing in the admin tree
807 * The pseudointerface that is implemented by anything that appears in the admin tree
808 * block. It forces inheriting classes to define a method for checking user permissions
809 * and methods for finding something in the admin tree.
811 * @author Vincenzo K. Marcovecchio
812 * @package admin
814 class part_of_admin_tree {
817 * Finds a named part_of_admin_tree.
819 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
820 * and not parentable_part_of_admin_tree, then this function should only check if
821 * $this->name matches $name. If it does, it should return a reference to $this,
822 * otherwise, it should return a reference to NULL.
824 * If a class inherits parentable_part_of_admin_tree, this method should be called
825 * recursively on all child objects (assuming, of course, the parent object's name
826 * doesn't match the search criterion).
828 * @param string $name The internal name of the part_of_admin_tree we're searching for.
829 * @return mixed An object reference or a NULL reference.
831 function &locate($name) {
832 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
833 return;
837 * Removes named part_of_admin_tree.
839 * @param string $name The internal name of the part_of_admin_tree we want to remove.
840 * @return bool success.
842 function prune($name) {
843 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
844 return;
848 * Verifies current user's access to this part_of_admin_tree.
850 * Used to check if the current user has access to this part of the admin tree or
851 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
852 * then this method is usually just a call to has_capability() in the site context.
854 * If a class inherits parentable_part_of_admin_tree, this method should return the
855 * logical OR of the return of check_access() on all child objects.
857 * @return bool True if the user has access, false if she doesn't.
859 function check_access() {
860 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
861 return;
865 * Mostly usefull for removing of some parts of the tree in admin tree block.
867 * @return True is hidden from normal list view
869 function is_hidden() {
870 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
871 return;
875 * Determines the path to $name in the admin tree.
877 * Used to determine the path to $name in the admin tree. If a class inherits only
878 * part_of_admin_tree and not parentable_part_of_admin_tree, then this method should
879 * check if $this->name matches $name. If it does, $name is pushed onto the $path
880 * array (at the end), and $path should be returned. If it doesn't, NULL should be
881 * returned.
883 * If a class inherits parentable_part_of_admin_tree, it should do the above, but not
884 * return NULL on failure. Instead, it pushes $this->name onto $path, and then
885 * recursively calls path() on its child objects. If any are non-NULL, it should
886 * return $path (being certain that the last element of $path is equal to $name).
887 * If they are all NULL, it returns NULL.
889 * @param string $name The internal name of the part_of_admin_tree we're searching for.
890 * @param array $path Not used on external calls. Defaults to empty array.
891 * @return mixed If found, an array containing the internal names of each part_of_admin_tree that leads to $name. If not found, NULL.
893 function path($name, $path = array()) {
894 trigger_error('Admin class does not implement method <strong>path()</strong>', E_USER_WARNING);
895 return;
900 * Pseudointerface implemented by any part_of_admin_tree that has children.
902 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
903 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
904 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
905 * include an add method for adding other part_of_admin_tree objects as children.
907 * @author Vincenzo K. Marcovecchio
908 * @package admin
910 class parentable_part_of_admin_tree extends part_of_admin_tree {
913 * Adds a part_of_admin_tree object to the admin tree.
915 * Used to add a part_of_admin_tree object to this object or a child of this
916 * object. $something should only be added if $destinationname matches
917 * $this->name. If it doesn't, add should be called on child objects that are
918 * also parentable_part_of_admin_tree's.
920 * @param string $destinationname The internal name of the new parent for $something.
921 * @param part_of_admin_tree &$something The object to be added.
922 * @return bool True on success, false on failure.
924 function add($destinationname, &$something) {
925 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
926 return;
932 * The object used to represent folders (a.k.a. categories) in the admin tree block.
934 * Each admin_category object contains a number of part_of_admin_tree objects.
936 * @author Vincenzo K. Marcovecchio
937 * @package admin
939 class admin_category extends parentable_part_of_admin_tree {
942 * @var mixed An array of part_of_admin_tree objects that are this object's children
944 var $children;
947 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
949 var $name;
952 * @var string The displayed name for this category. Usually obtained through get_string()
954 var $visiblename;
957 * @var bool Should this category be hidden in admin tree block?
959 var $hidden;
961 // constructor for an empty admin category
962 // $name is the internal name of the category. it MUST be unique in the entire hierarchy
963 // $visiblename is the displayed name of the category. use a get_string for this
966 * Constructor for an empty admin category
968 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
969 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
970 * @param bool $hidden hide category in admin tree block
971 * @return mixed Returns the new object.
973 function admin_category($name, $visiblename, $hidden = false) {
974 $this->children = array();
975 $this->name = $name;
976 $this->visiblename = $visiblename;
977 $this->hidden = $hidden;
981 * Finds the path to the part_of_admin_tree called $name.
983 * @param string $name The internal name that we're searching for.
984 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
985 * @return mixed An array of internal names that leads to $name, or NULL if not found.
987 function path($name, $path = array()) {
989 $path[count($path)] = $this->name;
991 if ($this->name == $name) {
992 return $path;
995 foreach($this->children as $child) {
996 if ($return = $child->path($name, $path)) {
997 return $return;
1001 return NULL;
1006 * Returns a reference to the part_of_admin_tree object with internal name $name.
1008 * @param string $name The internal name of the object we want.
1009 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1011 function &locate($name) {
1013 if ($this->name == $name) {
1014 return $this;
1017 foreach($this->children as $child) {
1018 if ($return =& $child->locate($name)) {
1019 return $return;
1022 $return = NULL;
1023 return $return;
1027 * Removes part_of_admin_tree object with internal name $name.
1029 * @param string $name The internal name of the object we want to remove.
1030 * @return bool success
1032 function prune($name) {
1034 if ($this->name == $name) {
1035 return false; //can not remove itself
1038 foreach($this->children as $precedence => $child) {
1039 if ($child->name == $name) {
1040 // found it!
1041 unset($this->children[$precedence]);
1042 return true;
1044 if ($this->children[$precedence]->prune($name)) {
1045 return true;
1048 return false;
1052 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1054 * @param string $destinationame The internal name of the immediate parent that we want for &$something.
1055 * @param mixed &$something A part_of_admin_tree object to be added.
1056 * @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".
1057 * @return bool True if successfully added, false if &$something is not a part_of_admin_tree or if $name is not found.
1059 function add($destinationname, &$something, $precedence = '') {
1061 if (!is_a($something, 'part_of_admin_tree')) {
1062 return false;
1065 if ($destinationname == $this->name) {
1066 if ($precedence === '') {
1067 $this->children[] = $something;
1068 } else {
1069 if (isset($this->children[$precedence])) { // this should never, ever be triggered in a release version of moodle.
1070 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 />');
1072 $this->children[$precedence] = $something;
1074 return true;
1077 unset($entries);
1079 $entries = array_keys($this->children);
1081 foreach($entries as $entry) {
1082 $child =& $this->children[$entry];
1083 if (is_a($child, 'parentable_part_of_admin_tree')) {
1084 if ($child->add($destinationname, $something, $precedence)) {
1085 return true;
1090 return false;
1095 * Checks if the user has access to anything in this category.
1097 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1099 function check_access() {
1101 $return = false;
1102 foreach ($this->children as $child) {
1103 $return = $return || $child->check_access();
1106 return $return;
1111 * Is this category hidden in admin tree block?
1113 * @return bool True if hidden
1115 function is_hidden() {
1116 return $this->hidden;
1121 * Links external PHP pages into the admin tree.
1123 * See detailed usage example at the top of this document (adminlib.php)
1125 * @author Vincenzo K. Marcovecchio
1126 * @package admin
1128 class admin_externalpage extends part_of_admin_tree {
1131 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1133 var $name;
1136 * @var string The displayed name for this external page. Usually obtained through get_string().
1138 var $visiblename;
1141 * @var string The external URL that we should link to when someone requests this external page.
1143 var $url;
1146 * @var string The role capability/permission a user must have to access this external page.
1148 var $req_capability;
1151 * @var object The context in which capability/permission should be checked, default is site context.
1153 var $context;
1156 * @var bool hidden in admin tree block.
1158 var $hidden;
1161 * Constructor for adding an external page into the admin tree.
1163 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1164 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1165 * @param string $url The external URL that we should link to when someone requests this external page.
1166 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1168 function admin_externalpage($name, $visiblename, $url, $req_capability = 'moodle/site:config', $hidden=false, $context=NULL) {
1169 $this->name = $name;
1170 $this->visiblename = $visiblename;
1171 $this->url = $url;
1172 if (is_array($req_capability)) {
1173 $this->req_capability = $req_capability;
1174 } else {
1175 $this->req_capability = array($req_capability);
1177 $this->hidden = $hidden;
1178 $this->context = $context;
1182 * Finds the path to the part_of_admin_tree called $name.
1184 * @param string $name The internal name that we're searching for.
1185 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
1186 * @return mixed An array of internal names that leads to $name, or NULL if not found.
1188 function path($name, $path = array()) {
1189 if ($name == $this->name) {
1190 array_push($path, $this->name);
1191 return $path;
1192 } else {
1193 return NULL;
1198 * Returns a reference to the part_of_admin_tree object with internal name $name.
1200 * @param string $name The internal name of the object we want.
1201 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1203 function &locate($name) {
1204 $return = ($this->name == $name ? $this : NULL);
1205 return $return;
1208 function prune($name) {
1209 return false;
1213 * Determines if the current user has access to this external page based on $this->req_capability.
1215 * @uses CONTEXT_SYSTEM
1216 * @uses SITEID
1217 * @return bool True if user has access, false otherwise.
1219 function check_access() {
1220 if (!get_site()) {
1221 return true; // no access check before site is fully set up
1223 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1224 foreach($this->req_capability as $cap) {
1225 if (has_capability($cap, $context)) {
1226 return true;
1229 return false;
1233 * Is this external page hidden in admin tree block?
1235 * @return bool True if hidden
1237 function is_hidden() {
1238 return $this->hidden;
1244 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1246 * @author Vincenzo K. Marcovecchio
1247 * @package admin
1249 class admin_settingpage extends part_of_admin_tree {
1252 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1254 var $name;
1257 * @var string The displayed name for this external page. Usually obtained through get_string().
1259 var $visiblename;
1261 * @var mixed An array of admin_setting objects that are part of this setting page.
1263 var $settings;
1266 * @var string The role capability/permission a user must have to access this external page.
1268 var $req_capability;
1271 * @var object The context in which capability/permission should be checked, default is site context.
1273 var $context;
1276 * @var bool hidden in admin tree block.
1278 var $hidden;
1280 // see admin_category
1281 function path($name, $path = array()) {
1282 if ($name == $this->name) {
1283 array_push($path, $this->name);
1284 return $path;
1285 } else {
1286 return NULL;
1290 // see admin_category
1291 function &locate($name) {
1292 $return = ($this->name == $name ? $this : NULL);
1293 return $return;
1296 function prune($name) {
1297 return false;
1300 // see admin_externalpage
1301 function admin_settingpage($name, $visiblename, $req_capability = 'moodle/site:config', $hidden=false, $context=NULL) {
1302 global $CFG;
1303 $this->settings = new stdClass();
1304 $this->name = $name;
1305 $this->visiblename = $visiblename;
1306 if (is_array($req_capability)) {
1307 $this->req_capability = $req_capability;
1308 } else {
1309 $this->req_capability = array($req_capability);
1311 $this->hidden = false;
1312 $this->context = $context;
1315 // 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
1316 // n.b. each admin_setting in an admin_settingpage must have a unique internal name
1317 // &$setting is the admin_setting object you want to add
1318 // returns true if successful, false if not (will fail if &$setting is an admin_setting or child thereof)
1319 function add(&$setting) {
1320 if (is_a($setting, 'admin_setting')) {
1321 $this->settings->{$setting->name} =& $setting;
1322 return true;
1324 return false;
1327 // see admin_externalpage
1328 function check_access() {
1329 if (!get_site()) {
1330 return true; // no access check before site is fully set up
1332 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1333 foreach($this->req_capability as $cap) {
1334 if (has_capability($cap, $context)) {
1335 return true;
1338 return false;
1341 // outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1342 // returns a string of the html
1343 function output_html() {
1344 $return = '<fieldset>' . "\n";
1345 $return .= '<div class="clearer"><!-- --></div>' . "\n";
1346 foreach($this->settings as $setting) {
1347 $return .= $setting->output_html();
1349 $return .= '</fieldset>';
1350 return $return;
1353 // 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
1354 // -- calls write_setting() to each child setting, sending it only the data that matches each setting's internal name
1355 // $data should be the result from data_submitted()
1356 // returns an empty string if everything went well, otherwise returns a printable error string (that's language-specific)
1357 function write_settings($data) {
1358 $return = '';
1359 foreach($this->settings as $setting) {
1360 if (isset($data['s_' . $setting->name])) {
1361 $return .= $setting->write_setting($data['s_' . $setting->name]);
1362 } else {
1363 $return .= $setting->write_setting('');
1366 return $return;
1370 * Is this settigns page hidden in admin tree block?
1372 * @return bool True if hidden
1374 function is_hidden() {
1375 return $this->hidden;
1381 // read & write happens at this level; no authentication
1382 class admin_setting {
1384 var $name;
1385 var $visiblename;
1386 var $description;
1387 var $defaultsetting;
1389 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1390 $this->name = $name;
1391 $this->visiblename = $visiblename;
1392 $this->description = $description;
1393 $this->defaultsetting = $defaultsetting;
1396 function get_setting() {
1397 return NULL; // has to be overridden
1400 function write_setting($data) {
1401 return; // has to be overridden
1404 function output_html() {
1405 return; // has to be overridden
1411 class admin_setting_configtext extends admin_setting {
1413 var $paramtype;
1415 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
1416 $this->paramtype = $paramtype;
1417 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1420 // returns a string or NULL
1421 function get_setting() {
1422 global $CFG;
1423 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1426 // $data is a string
1427 function write_setting($data) {
1428 if (!$this->validate($data)) {
1429 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
1431 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1434 function validate($data) {
1435 if (is_string($this->paramtype)) {
1436 return preg_match($this->paramtype, $data);
1437 } else if ($this->paramtype === PARAM_RAW) {
1438 return true;
1439 } else {
1440 $cleaned = clean_param($data, $this->paramtype);
1441 return ("$data" == "$cleaned"); // implicit conversion to string is needed to do exact comparison
1445 function output_html() {
1446 if ($this->get_setting() === NULL) {
1447 $current = $this->defaultsetting;
1448 } else {
1449 $current = $this->get_setting();
1451 return format_admin_setting($this->name, $this->visiblename,
1452 '<input type="text" class="form-text" id="id_s_'.$this->name.'" name="s_'.$this->name.'" value="'.s($current).'" />',
1453 $this->description);
1458 class admin_setting_configpasswordunmask extends admin_setting_configtext {
1460 function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
1461 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1464 function output_html() {
1465 if ($this->get_setting() === NULL) {
1466 $current = $this->defaultsetting;
1467 } else {
1468 $current = $this->get_setting();
1470 $id = 'id_s_'.$this->name;
1471 $unmask = get_string('unmaskpassword', 'form');
1472 $unmaskjs = '<script type="text/javascript">
1473 //<![CDATA[
1474 document.write(\'<div class="unmask"><input id="'.$id.'unmask" value="1" type="checkbox" onclick="unmaskPassword(\\\''.$id.'\\\')"/><label for="'.$id.'unmask">'.addslashes_js($unmask).'<\/label><\/div>\');
1475 //]]>
1476 </script>';
1477 return format_admin_setting($this->name, $this->visiblename,
1478 '<input type="password" class="form-text" id="id_s_'.$this->name.'" name="s_'.$this->name.'" value="'.s($current).'" />'.$unmaskjs,
1479 $this->description);
1484 class admin_setting_configcheckbox extends admin_setting {
1486 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting) {
1487 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1490 function get_setting() {
1491 global $CFG;
1492 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1495 function write_setting($data) {
1496 if ($data == '1') {
1497 return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1498 } else {
1499 return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1503 function output_html() {
1504 if ($this->get_setting() === NULL) {
1505 $current = $this->defaultsetting;
1506 } else {
1507 $current = $this->get_setting();
1509 return format_admin_setting($this->name, $this->visiblename,
1510 '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($current == true ? 'checked="checked"' : '') . ' />',
1511 $this->description);
1516 class admin_setting_configselect extends admin_setting {
1518 var $choices;
1520 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
1521 $this->choices = $choices;
1522 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1525 function get_setting() {
1526 global $CFG;
1527 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1530 function write_setting($data) {
1531 // check that what we got was in the original choices
1532 // or that the data is the default setting - needed during install when choices can not be constructed yet
1533 if ($data != $this->defaultsetting and ! in_array($data, array_keys($this->choices))) {
1534 return 'Error setting ' . $this->visiblename . '<br />';
1537 return (set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1540 function output_html() {
1541 if ($this->get_setting() === NULL) {
1542 $current = $this->defaultsetting;
1543 } else {
1544 $current = $this->get_setting();
1546 $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'">';
1547 foreach ($this->choices as $key => $value) {
1548 // the string cast is needed because key may be integer - 0 is equal to most strings!
1549 $return .= '<option value="'.$key.'"'.((string)$key==$current ? ' selected="selected"' : '').'>'.$value.'</option>';
1551 $return .= '</select>';
1553 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1558 // 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
1559 // internally for the setting)
1560 class admin_setting_configtime extends admin_setting {
1562 var $name2;
1563 var $choices;
1564 var $choices2;
1566 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
1567 $this->name2 = $minutesname;
1568 $this->choices = array();
1569 for ($i = 0; $i < 24; $i++) {
1570 $this->choices[$i] = $i;
1572 $this->choices2 = array();
1573 for ($i = 0; $i < 60; $i += 5) {
1574 $this->choices2[$i] = $i;
1576 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
1579 function get_setting() {
1580 global $CFG;
1581 return (isset($CFG->{$this->name}) && isset($CFG->{$this->name2}) ? array('h' => $CFG->{$this->name}, 'm' => $CFG->{$this->name2}) : NULL);
1584 function write_setting($data) {
1585 // check that what we got was in the original choices
1586 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
1587 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1590 return (set_config($this->name, $data['h']) && set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1593 function output_html() {
1594 if ($this->get_setting() === NULL) {
1595 $currentsetting = $this->defaultsetting;
1596 } else {
1597 $currentsetting = $this->get_setting();
1599 $return = '<div class="form-group">'.
1600 '<select class="form-select" id="id_s_'.$this->name.'h" name="s_' . $this->name .'[h]">';
1601 foreach ($this->choices as $key => $value) {
1602 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['h'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1604 $return .= '</select>:<select class="form-select" id="id_s_'.$this->name.'m" name="s_' . $this->name . '[m]">';
1605 foreach ($this->choices2 as $key => $value) {
1606 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['m'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1608 $return .= '</select></div>';
1609 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
1614 class admin_setting_configmultiselect extends admin_setting_configselect {
1616 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
1617 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1620 function get_setting() {
1621 global $CFG;
1622 if (isset($CFG->{$this->name})) {
1623 if ($CFG->{$this->name}) {
1624 return explode(',', $CFG->{$this->name});
1625 } else {
1626 return array();
1628 } else {
1629 return NULL;
1633 function write_setting($data) {
1634 if (empty($data)) {
1635 $data = array();
1637 foreach ($data as $datum) {
1638 if (! in_array($datum, array_keys($this->choices))) {
1639 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1643 return (set_config($this->name, implode(',',$data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1646 function output_html() {
1647 if ($this->get_setting() === NULL) {
1648 $currentsetting = $this->defaultsetting;
1649 if (!$currentsetting) {
1650 $currentsetting = array();
1652 } else {
1653 $currentsetting = $this->get_setting();
1655 $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'[]" size="10" multiple="multiple">';
1656 foreach ($this->choices as $key => $value) {
1657 $return .= '<option value="' . $key . '"' . (in_array($key,$currentsetting) ? ' selected="selected"' : '') . '>' . $value . '</option>';
1659 $return .= '</select>';
1660 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1665 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
1667 function admin_setting_special_adminseesall() {
1668 $name = 'calendar_adminseesall';
1669 $visiblename = get_string('adminseesall', 'admin');
1670 $description = get_string('helpadminseesall', 'admin');
1671 parent::admin_setting($name, $visiblename, $description, 0);
1674 function write_setting($data) {
1675 global $SESSION;
1676 unset($SESSION->cal_courses_shown);
1677 parent::write_setting($data);
1681 class admin_setting_sitesetselect extends admin_setting_configselect {
1683 var $id;
1685 function admin_setting_sitesetselect($name, $visiblename, $description, $defaultsetting, $choices) {
1687 $this->id = SITEID;
1688 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1692 function get_setting() {
1693 $site = get_site();
1694 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1697 function write_setting($data) {
1698 if (!in_array($data, array_keys($this->choices))) {
1699 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1701 $record = new stdClass();
1702 $record->id = $this->id;
1703 $temp = $this->name;
1704 $record->$temp = $data;
1705 $record->timemodified = time();
1706 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1712 class admin_setting_courselist_frontpage extends admin_setting_configselect {
1714 function admin_setting_courselist_frontpage($loggedin) {
1715 global $CFG;
1716 require_once($CFG->dirroot . '/course/lib.php');
1717 $name = 'frontpage' . ($loggedin ? 'loggedin' : '');
1718 $visiblename = get_string('frontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1719 $description = get_string('configfrontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1720 $choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
1721 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
1722 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
1723 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
1724 '' => get_string('none'));
1725 if (!$loggedin and count_records("course") > FRONTPAGECOURSELIMIT) {
1726 unset($choices[FRONTPAGECOURSELIST]);
1728 $defaults = FRONTPAGECOURSELIST.',,,';
1729 parent::admin_setting_configselect($name, $visiblename, $description, $defaults, $choices);
1732 function get_setting() {
1733 global $CFG;
1734 return (isset($CFG->{$this->name}) ? explode(',', $CFG->{$this->name}) : ',1,,');
1737 function write_setting($data) {
1738 if (empty($data)) {
1739 $data = array();
1740 } if (!is_array($data)) {
1741 $data = explode(',', $data);
1743 foreach($data as $datum) {
1744 if (! in_array($datum, array_keys($this->choices))) {
1745 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1748 return (set_config($this->name, implode(',', $data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1751 function output_html() {
1752 if ($this->get_setting() === NULL) {
1753 $currentsetting = $this->defaultsetting;
1754 } else {
1755 $currentsetting = $this->get_setting();
1757 for ($i = 0; $i < count($this->choices) - 1; $i++) {
1758 if (!isset($currentsetting[$i])) {
1759 $currentsetting[$i] = 0;
1762 $return = '<div class="form-group">';
1763 for ($i = 0; $i < count($this->choices) - 1; $i++) {
1764 $return .='<select class="form-select" id="id_s_'.$this->name.$i.'" name="s_' . $this->name .'[]">';
1765 foreach ($this->choices as $key => $value) {
1766 $return .= '<option value="' . $key . '"' . ($key == $currentsetting[$i] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1768 $return .= '</select>';
1769 if ($i !== count($this->choices) - 2) {
1770 $return .= '<br />';
1773 $return .= '</div>';
1775 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
1779 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
1781 var $id;
1783 function admin_setting_sitesetcheckbox($name, $visiblename, $description, $defaultsetting) {
1785 $this->id = SITEID;
1786 parent::admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting);
1790 function get_setting() {
1791 $site = get_site();
1792 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1795 function write_setting($data) {
1796 $record = new stdClass();
1797 $record->id = $this->id;
1798 $temp = $this->name;
1799 $record->$temp = ($data == '1' ? 1 : 0);
1800 $record->timemodified = time();
1801 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1806 class admin_setting_sitesettext extends admin_setting_configtext {
1808 var $id;
1810 function admin_setting_sitesettext($name, $visiblename, $description, $defaultsetting) {
1812 $this->id = SITEID;
1813 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting);
1817 function get_setting() {
1818 $site = get_site();
1819 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1822 function validate($data) {
1823 $cleaned = stripslashes(clean_param($data, PARAM_MULTILANG));
1824 if ($cleaned == '') {
1825 return false; // can not be empty
1827 return ($data == $cleaned); // implicit conversion to string is needed to do exact comparison
1830 function write_setting($data) {
1831 $data = trim($data);
1832 if (!$this->validate($data)) {
1833 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
1836 $record = new stdClass();
1837 $record->id = $this->id;
1838 $record->{$this->name} = addslashes($data);
1839 $record->timemodified = time();
1840 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1845 class admin_setting_special_frontpagedesc extends admin_setting {
1847 var $id;
1849 function admin_setting_special_frontpagedesc() {
1850 $this->id = SITEID;
1851 $name = 'summary';
1852 $visiblename = get_string('frontpagedescription');
1853 $description = get_string('frontpagedescriptionhelp');
1854 parent::admin_setting($name, $visiblename, $description, '');
1857 function output_html() {
1859 global $CFG;
1861 if ($this->get_setting() === NULL) {
1862 $currentsetting = $this->defaultsetting;
1863 } else {
1864 $currentsetting = $this->get_setting();
1867 $CFG->adminusehtmleditor = can_use_html_editor();
1869 $return = print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, 's_' . $this->name, $currentsetting, 0, true);
1871 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
1874 function get_setting() {
1876 $site = get_site();
1877 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1881 function write_setting($data) {
1883 $data = addslashes(clean_param($data, PARAM_CLEANHTML));
1885 $record = new stdClass();
1886 $record->id = $this->id;
1887 $temp = $this->name;
1888 $record->$temp = $data;
1889 $record->timemodified = time();
1891 return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1898 class admin_setting_special_editorfontlist extends admin_setting {
1900 var $items;
1902 function admin_setting_special_editorfontlist() {
1903 global $CFG;
1904 $name = 'editorfontlist';
1905 $visiblename = get_string('editorfontlist', 'admin');
1906 $description = get_string('configeditorfontlist', 'admin');
1907 $defaults = array('k0' => 'Trebuchet',
1908 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
1909 'k1' => 'Arial',
1910 'v1' => 'arial,helvetica,sans-serif',
1911 'k2' => 'Courier New',
1912 'v2' => 'courier new,courier,monospace',
1913 'k3' => 'Georgia',
1914 'v3' => 'georgia,times new roman,times,serif',
1915 'k4' => 'Tahoma',
1916 'v4' => 'tahoma,arial,helvetica,sans-serif',
1917 'k5' => 'Times New Roman',
1918 'v5' => 'times new roman,times,serif',
1919 'k6' => 'Verdana',
1920 'v6' => 'verdana,arial,helvetica,sans-serif',
1921 'k7' => 'Impact',
1922 'v7' => 'impact',
1923 'k8' => 'Wingdings',
1924 'v8' => 'wingdings');
1925 parent::admin_setting($name, $visiblename, $description, $defaults);
1928 function get_setting() {
1929 global $CFG;
1930 if (isset($CFG->editorfontlist)) {
1931 $i = 0;
1932 $currentsetting = array();
1933 $items = explode(';', $CFG->editorfontlist);
1934 foreach ($items as $item) {
1935 $item = explode(':', $item);
1936 $currentsetting['k' . $i] = $item[0];
1937 $currentsetting['v' . $i] = $item[1];
1938 $i++;
1940 return $currentsetting;
1941 } else {
1942 return NULL;
1946 function write_setting($data) {
1948 // there miiight be an easier way to do this :)
1949 // if this is changed, make sure the $defaults array above is modified so that this
1950 // function processes it correctly
1952 $keys = array();
1953 $values = array();
1955 foreach ($data as $key => $value) {
1956 if (substr($key,0,1) == 'k') {
1957 $keys[substr($key,1)] = $value;
1958 } elseif (substr($key,0,1) == 'v') {
1959 $values[substr($key,1)] = $value;
1963 $result = '';
1964 for ($i = 0; $i < count($keys); $i++) {
1965 if (($keys[$i] !== '') && ($values[$i] !== '')) {
1966 $result .= clean_param($keys[$i],PARAM_NOTAGS) . ':' . clean_param($values[$i], PARAM_NOTAGS) . ';';
1970 $result = substr($result, 0, -1); // trim the last semicolon
1972 return (set_config($this->name, $result) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1975 function output_html() {
1977 if ($this->get_setting() === NULL) {
1978 $currentsetting = $this->defaultsetting;
1979 } else {
1980 $currentsetting = $this->get_setting();
1983 $return = '<div class="form-group">';
1984 for ($i = 0; $i < count($currentsetting) / 2; $i++) {
1985 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="' . $currentsetting['k' . $i] . '" />';
1986 $return .= '&nbsp;&nbsp;';
1987 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="' . $currentsetting['v' . $i] . '" /><br />';
1989 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="" />';
1990 $return .= '&nbsp;&nbsp;';
1991 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="" /><br />';
1992 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . ($i + 1) . ']" value="" />';
1993 $return .= '&nbsp;&nbsp;';
1994 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . ($i + 1) . ']" value="" />';
1995 $return .= '</div>';
1997 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
2002 class admin_setting_special_editordictionary extends admin_setting_configselect {
2004 function admin_setting_special_editordictionary() {
2005 $name = 'editordictionary';
2006 $visiblename = get_string('editordictionary','admin');
2007 $description = get_string('configeditordictionary', 'admin');
2008 $choices = $this->editor_get_dictionaries();
2009 if (! is_array($choices)) {
2010 $choices = array('');
2013 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
2016 // function borrowed from the old moodle/admin/editor.php, slightly modified
2017 function editor_get_dictionaries () {
2018 /// Get all installed dictionaries in the system
2020 global $CFG;
2022 // error_reporting(E_ALL); // for debug, final version shouldn't have this...
2023 clearstatcache();
2025 // If aspellpath isn't set don't even bother ;-)
2026 if (empty($CFG->aspellpath)) {
2027 return 'Empty aspell path!';
2030 // Do we have access to popen function?
2031 if (!function_exists('popen')) {
2032 return 'Popen function disabled!';
2035 $cmd = $CFG->aspellpath;
2036 $output = '';
2037 $dictionaries = array();
2038 $dicts = array();
2040 if(!($handle = @popen(escapeshellarg($cmd) .' dump dicts', 'r'))) {
2041 return 'Couldn\'t create handle!';
2044 while(!feof($handle)) {
2045 $output .= fread($handle, 1024);
2047 @pclose($handle);
2049 $dictionaries = explode(chr(10), $output);
2051 // Get rid of possible empty values
2052 if (is_array($dictionaries)) {
2054 $cnt = count($dictionaries);
2056 for ($i = 0; $i < $cnt; $i++) {
2057 if (!empty($dictionaries[$i])) {
2058 $dicts[$dictionaries[$i]] = $dictionaries[$i];
2063 if (count($dicts) >= 1) {
2064 return $dicts;
2067 return 'Error! Check your aspell installation!';
2075 class admin_setting_special_editorhidebuttons extends admin_setting {
2077 var $name;
2078 var $visiblename;
2079 var $description;
2080 var $items;
2082 function admin_setting_special_editorhidebuttons() {
2083 $this->name = 'editorhidebuttons';
2084 $this->visiblename = get_string('editorhidebuttons', 'admin');
2085 $this->description = get_string('confeditorhidebuttons', 'admin');
2086 $this->defaultsetting = array();
2087 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
2088 $this->items = array('fontname' => '',
2089 'fontsize' => '',
2090 'formatblock' => '',
2091 'bold' => 'ed_format_bold.gif',
2092 'italic' => 'ed_format_italic.gif',
2093 'underline' => 'ed_format_underline.gif',
2094 'strikethrough' => 'ed_format_strike.gif',
2095 'subscript' => 'ed_format_sub.gif',
2096 'superscript' => 'ed_format_sup.gif',
2097 'copy' => 'ed_copy.gif',
2098 'cut' => 'ed_cut.gif',
2099 'paste' => 'ed_paste.gif',
2100 'clean' => 'ed_wordclean.gif',
2101 'undo' => 'ed_undo.gif',
2102 'redo' => 'ed_redo.gif',
2103 'justifyleft' => 'ed_align_left.gif',
2104 'justifycenter' => 'ed_align_center.gif',
2105 'justifyright' => 'ed_align_right.gif',
2106 'justifyfull' => 'ed_align_justify.gif',
2107 'lefttoright' => 'ed_left_to_right.gif',
2108 'righttoleft' => 'ed_right_to_left.gif',
2109 'insertorderedlist' => 'ed_list_num.gif',
2110 'insertunorderedlist' => 'ed_list_bullet.gif',
2111 'outdent' => 'ed_indent_less.gif',
2112 'indent' => 'ed_indent_more.gif',
2113 'forecolor' => 'ed_color_fg.gif',
2114 'hilitecolor' => 'ed_color_bg.gif',
2115 'inserthorizontalrule' => 'ed_hr.gif',
2116 'createanchor' => 'ed_anchor.gif',
2117 'createlink' => 'ed_link.gif',
2118 'unlink' => 'ed_unlink.gif',
2119 'insertimage' => 'ed_image.gif',
2120 'inserttable' => 'insert_table.gif',
2121 'insertsmile' => 'em.icon.smile.gif',
2122 'insertchar' => 'icon_ins_char.gif',
2123 'spellcheck' => 'spell-check.gif',
2124 'htmlmode' => 'ed_html.gif',
2125 'popupeditor' => 'fullscreen_maximize.gif',
2126 'search_replace' => 'ed_replace.gif');
2129 function get_setting() {
2130 global $CFG;
2131 return (isset($CFG->{$this->name}) ? explode(' ', $CFG->{$this->name}) : NULL);
2134 function write_setting($data) {
2135 $result = array();
2136 if (empty($data)) { $data = array(); }
2137 foreach ($data as $key => $value) {
2138 if (!in_array($key, array_keys($this->items))) {
2139 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2141 if ($value == '1') {
2142 $result[] = $key;
2145 return (set_config($this->name, implode(' ',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2148 function output_html() {
2150 global $CFG;
2152 // checkboxes with input name="$this->name[$key]" value="1"
2153 // we do 15 fields per column
2155 if ($this->get_setting() === NULL) {
2156 $currentsetting = $this->defaultsetting;
2157 } else {
2158 $currentsetting = $this->get_setting();
2161 $return = '<div class="form-group">';
2162 $return .= '<table><tr><td valign="top" align="right">';
2164 $count = 0;
2166 foreach($this->items as $key => $value) {
2167 if ($count % 15 == 0 and $count != 0) {
2168 $return .= '</td><td valign="top" align="right">';
2171 $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;';
2172 $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;';
2173 $count++;
2174 if ($count % 15 != 0) {
2175 $return .= '<br /><br />';
2179 $return .= '</td></tr>';
2180 $return .= '</table>';
2181 $return .= '</div>';
2183 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
2188 class admin_setting_langlist extends admin_setting_configtext {
2189 function admin_setting_langlist() {
2190 parent::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
2193 function write_setting($data) {
2194 $return = parent::write_setting($data);
2195 get_list_of_languages(true);//refresh the list
2196 return $return;
2200 class admin_setting_backupselect extends admin_setting_configselect {
2202 function admin_setting_backupselect($name, $visiblename, $description, $default, $choices) {
2203 parent::admin_setting_configselect($name, $visiblename, $description, $default, $choices);
2206 function get_setting() {
2207 $backup_config = backup_get_config();
2208 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2211 function write_setting($data) {
2212 // check that what we got was in the original choices
2213 if (! in_array($data, array_keys($this->choices))) {
2214 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2217 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2222 class admin_setting_special_backupsaveto extends admin_setting_configtext {
2224 function admin_setting_special_backupsaveto() {
2225 $name = 'backup_sche_destination';
2226 $visiblename = get_string('saveto');
2227 $description = get_string('backupsavetohelp');
2228 parent::admin_setting_configtext($name, $visiblename, $description, '');
2231 function get_setting() {
2232 $backup_config = backup_get_config();
2233 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2236 function write_setting($data) {
2237 $data = trim($data);
2238 if (!empty($data) and !is_dir($data)) {
2239 return get_string('pathnotexists') . '<br />';
2241 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2246 class admin_setting_backupcheckbox extends admin_setting_configcheckbox {
2248 function admin_setting_backupcheckbox($name, $visiblename, $description, $default) {
2249 parent::admin_setting_configcheckbox($name, $visiblename, $description, $default);
2252 function write_setting($data) {
2253 if ($data == '1') {
2254 return (backup_set_config($this->name, 1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2255 } else {
2256 return (backup_set_config($this->name, 0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2260 function get_setting() {
2261 $backup_config = backup_get_config();
2262 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2267 class admin_setting_special_backuptime extends admin_setting_configtime {
2269 function admin_setting_special_backuptime() {
2270 $name = 'backup_sche_hour';
2271 $name2 = 'backup_sche_minute';
2272 $visiblename = get_string('executeat');
2273 $description = get_string('backupexecuteathelp');
2274 $default = array('h' => 0, 'm' => 0);
2275 parent::admin_setting_configtime($name, $name2, $visiblename, $description, $default);
2278 function get_setting() {
2279 $backup_config = backup_get_config();
2280 return (isset($backup_config->{$this->name}) && isset($backup_config->{$this->name}) ? array('h'=>$backup_config->{$this->name}, 'm'=>$backup_config->{$this->name2}) : NULL);
2283 function write_setting($data) {
2284 // check that what we got was in the original choices
2285 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
2286 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2289 return (backup_set_config($this->name, $data['h']) && backup_set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2294 class admin_setting_special_backupdays extends admin_setting {
2296 function admin_setting_special_backupdays() {
2297 $name = 'backup_sche_weekdays';
2298 $visiblename = get_string('schedule');
2299 $description = get_string('backupschedulehelp');
2300 $default = array('u' => 0, 'm' => 0, 't' => 0, 'w' => 0, 'r' => 0, 'f' => 0, 's' => 0);
2301 parent::admin_setting($name, $visiblename, $description, $default);
2304 function get_setting() {
2305 $backup_config = backup_get_config();
2306 if (isset($backup_config->{$this->name})) {
2307 $currentsetting = $backup_config->{$this->name};
2308 return array('u' => substr($currentsetting, 0, 1),
2309 'm' => substr($currentsetting, 1, 1),
2310 't' => substr($currentsetting, 2, 1),
2311 'w' => substr($currentsetting, 3, 1),
2312 'r' => substr($currentsetting, 4, 1),
2313 'f' => substr($currentsetting, 5, 1),
2314 's' => substr($currentsetting, 6, 1));
2315 } else {
2316 return NULL;
2320 function output_html() {
2322 if ($this->get_setting() === NULL) {
2323 $currentsetting = $this->defaultsetting;
2324 } else {
2325 $currentsetting = $this->get_setting();
2328 // rewrite for simplicity
2329 $currentsetting = $currentsetting['u'] . $currentsetting['m'] . $currentsetting['t'] . $currentsetting['w'] .
2330 $currentsetting['r'] . $currentsetting['f'] . $currentsetting['s'];
2332 $return = '<table><tr><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2333 get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2334 get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2335 get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2336 '<td><div style="text-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>' .
2337 '<td><div style="text-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>' .
2338 '<td><div style="text-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>' .
2339 '<td><div style="text-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>' .
2340 '<td><div style="text-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>' .
2341 '<td><div style="text-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>' .
2342 '<td><div style="text-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>' .
2343 '</tr></table>';
2345 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
2349 // 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
2350 // admin_settingpage (note that admin_settingpage only calls write_setting with the data that matches $this->name... so if we have multiple form fields,
2351 // they MUST go into an array named $this->name, or else we won't receive them here
2352 function write_setting($data) {
2353 $week = 'umtwrfs';
2354 $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
2355 if (!empty($data)) {
2356 foreach($data as $key => $value) {
2357 if ($value == '1') {
2358 $result[strpos($week, $key)] = 1;
2362 return (backup_set_config($this->name, implode('',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2366 class admin_setting_special_debug extends admin_setting_configselect {
2368 function admin_setting_special_debug() {
2369 $name = 'debug';
2370 $visiblename = get_string('debug', 'admin');
2371 $description = get_string('configdebug', 'admin');
2372 $choices = array( DEBUG_NONE => get_string('debugnone', 'admin'),
2373 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
2374 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
2375 DEBUG_ALL => get_string('debugall', 'admin'),
2376 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin')
2378 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
2381 function get_setting() {
2382 global $CFG;
2383 if (isset($CFG->debug)) {
2384 return $CFG->debug;
2385 } else {
2386 return NULL;
2390 function write_setting($data) {
2391 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2397 class admin_setting_special_calendar_weekend extends admin_setting {
2399 function admin_setting_special_calendar_weekend() {
2400 $name = 'calendar_weekend';
2401 $visiblename = get_string('calendar_weekend', 'admin');
2402 $description = get_string('helpweekenddays', 'admin');
2403 $default = array ('0', '6'); // Saturdays and Sundays
2404 parent::admin_setting($name, $visiblename, $description, $default);
2407 function get_setting() {
2408 global $CFG;
2409 return isset($CFG->{$this->name}) ? $CFG->{$this->name} : 0;
2412 function write_setting($data) {
2413 $result = 0;
2414 if (!empty($data)) {
2415 foreach($data as $index) {
2416 $result |= 1 << $index;
2419 return (set_config($this->name, $result) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2422 function output_html() {
2423 if ($this->get_setting() === NULL) {
2424 $currentsetting = $this->defaultsetting;
2425 } else {
2426 $currentsetting = $this->get_setting();
2429 // The order matters very much because of the implied numeric keys
2430 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
2431 $return = '<table><thead><tr>';
2432 foreach($days as $index => $day) {
2433 $return .= '<td><label for="id_s_'.$this->name.$index.'">'.get_string($day, 'calendar').'</label></td>';
2435 $return .= '</tr></thead><tbody><tr>';
2436 foreach($days as $index => $day) {
2437 $return .= '<td><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.$index.'" name="s_'.$this->name.'[]" value="'.$index.'" '.($currentsetting & (1 << $index) ? 'checked="checked"' : '') . ' /></td>';
2439 $return .= '</tr></tbody></table>';
2441 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
2448 * this is used in config->appearance->gradeconfig
2450 class admin_setting_special_gradebookroles extends admin_setting {
2452 function admin_setting_special_gradebookroles() {
2453 $name = 'gradebookroles';
2454 $visiblename = get_string('gradebookroles', 'admin');
2455 $description = get_string('configgradebookroles', 'admin');
2456 $default = array(5=>'1'); // The student role in a default install
2457 parent::admin_setting($name, $visiblename, $description, $default);
2460 function get_setting() {
2461 global $CFG;
2462 if (!empty($CFG->{$this->name})) {
2463 $result = explode(',', $CFG->{$this->name});
2464 foreach ($result as $roleid) {
2465 $array[$roleid] = 1;
2467 return $array;
2468 } else {
2469 return null;
2473 function write_setting($data) {
2474 if (!empty($data)) {
2475 $str = '';
2476 foreach ($data as $key => $value) {
2477 if ($value) {
2478 $str .= $key.',';
2481 return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2482 } else {
2483 return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2487 function output_html() {
2489 if ($this->get_setting() === NULL) {
2490 $currentsetting = $this->defaultsetting;
2491 } else {
2492 $currentsetting = $this->get_setting();
2494 // from to process which roles to display
2495 if ($roles = get_records('role')) {
2496 $return = '<div class="form-group">';
2497 $first = true;
2498 foreach ($roles as $roleid=>$role) {
2499 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
2500 $checked = ' checked="checked"';
2501 } else {
2502 $checked = '';
2504 if ($first) {
2505 $first = false;
2506 } else {
2507 $return .= '<br />';
2509 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$roleid.']" value="1"'.$checked.' />&nbsp;'.format_string($role->name);
2511 $return .= '</div>';
2514 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
2521 * this is used in config->appearance->coursemanager
2522 * (which roles to show on course decription page)
2524 class admin_setting_special_coursemanager extends admin_setting {
2526 function admin_setting_special_coursemanager() {
2527 $name = 'coursemanager';
2528 $visiblename = get_string('coursemanager', 'admin');
2529 $description = get_string('configcoursemanager', 'admin');
2530 $default = array(3=>'1'); // The teahcer role in a default install
2531 parent::admin_setting($name, $visiblename, $description, $default);
2534 function get_setting() {
2536 global $CFG;
2537 if (!empty($CFG->{$this->name})) {
2538 $result = explode(',', $CFG->{$this->name});
2539 foreach ($result as $roleid) {
2540 $array[$roleid] = 1;
2542 return $array;
2543 } else if (isset($CFG->{$this->name})) {
2544 return array();
2545 } else {
2546 return null;
2550 function write_setting($data) {
2552 if (!empty($data)) {
2553 $str = '';
2554 foreach ($data as $key => $value) {
2555 if ($value) {
2556 $str .= $key.',';
2559 return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2560 } else {
2561 return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2565 function output_html() {
2567 if ($this->get_setting() === NULL) {
2568 $currentsetting = $this->defaultsetting;
2569 } else {
2570 $currentsetting = $this->get_setting();
2572 // from to process which roles to display
2573 if ($roles = get_records_select('role', '', 'sortorder')) {
2574 $return = '<div class="form-group">';
2575 $first = true;
2576 foreach ($roles as $roleid=>$role) {
2577 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
2578 $checked = 'checked="checked"';
2579 } else {
2580 $checked = '';
2582 if ($first) {
2583 $first = false;
2584 } else {
2585 $return .= '<br />';
2587 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$roleid.']" value="1" '.$checked.' />&nbsp;'.$role->name;
2589 $return .= '</div>';
2591 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
2596 * this is used in config->courses->gradeexports
2597 * (which roles to show on course decription page)
2599 class admin_setting_special_gradeexport extends admin_setting {
2601 function admin_setting_special_gradeexport() {
2602 $name = 'gradeexport';
2603 $visiblename = get_string('gradeexport', 'admin');
2604 $description = get_string('configgradeexport', 'admin');
2605 $default = array(3=>'1'); // The teahcer role in a default install
2606 parent::admin_setting($name, $visiblename, $description, $default);
2609 function get_setting() {
2611 global $CFG;
2612 if (!empty($CFG->{$this->name})) {
2613 $result = explode(',', $CFG->{$this->name});
2614 foreach ($result as $plugin) {
2615 $array[$plugin] = 1;
2617 return $array;
2618 } else if (isset($CFG->{$this->name})) {
2619 return array();
2620 } else {
2621 return null;
2625 function write_setting($data) {
2627 if (!empty($data)) {
2628 $str = '';
2629 foreach ($data as $key => $value) {
2630 if ($value) {
2631 $str .= $key.',';
2634 return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2635 } else {
2636 return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2640 function output_html() {
2642 if ($this->get_setting() === NULL) {
2643 $currentsetting = $this->defaultsetting;
2644 } else {
2645 $currentsetting = $this->get_setting();
2647 // from to process which roles to display
2648 if ($exports = get_list_of_plugins('grade/export')) {
2649 $return = '<div class="form-group">';
2650 $first = true;
2651 foreach ($exports as $export) {
2652 if (is_array($currentsetting) && in_array($export, array_keys($currentsetting))) {
2653 $checked = 'checked="checked"';
2654 } else {
2655 $checked = '';
2657 if ($first) {
2658 $first = false;
2659 } else {
2660 $return .= '<br />';
2662 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$export.']" value="1" '.$checked.' />&nbsp;'.$export;
2664 $return .= '</div>';
2666 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
2673 class admin_setting_special_perfdebug extends admin_setting_configcheckbox {
2675 function admin_setting_special_perfdebug() {
2676 $name = 'perfdebug';
2677 $visiblename = get_string('perfdebug', 'admin');
2678 $description = get_string('configperfdebug', 'admin');
2679 parent::admin_setting_configcheckbox($name, $visiblename, $description, '');
2682 function write_setting($data) {
2684 if ($data == '1') {
2685 return (set_config($this->name,15) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2686 } else {
2687 return (set_config($this->name,7) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2691 function output_html() {
2693 if ($this->get_setting() === NULL) {
2694 $currentsetting = $this->defaultsetting;
2695 } else {
2696 $currentsetting = $this->get_setting();
2699 $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 15 ? 'checked="checked"' : '') . ' />';
2700 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2705 class admin_setting_special_debugdisplay extends admin_setting_configcheckbox {
2707 function admin_setting_special_debugdisplay() {
2708 $name = 'debugdisplay';
2709 $visiblename = get_string('debugdisplay', 'admin');
2710 $description = get_string('configdebugdisplay', 'admin');
2711 $default = ini_get('display_errors');
2712 parent::admin_setting_configcheckbox($name, $visiblename, $description, $default);
2715 function write_setting($data) {
2717 if ($data == '1') {
2718 return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2719 } else {
2720 return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2724 function output_html() {
2726 if ($this->get_setting() === NULL) {
2727 $currentsetting = $this->defaultsetting;
2728 } else {
2729 $currentsetting = $this->get_setting();
2732 $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 1 ? 'checked="checked"' : '') . ' />';
2733 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2739 // Code for a function that helps externalpages print proper headers and footers
2740 // N.B.: THIS FUNCTION HANDLES AUTHENTICATION
2741 function admin_externalpage_setup($section) {
2743 global $CFG, $PAGE, $USER;
2745 $adminroot = admin_get_root();
2747 require_once($CFG->libdir . '/blocklib.php');
2748 require_once($CFG->dirroot . '/'.$CFG->admin.'/pagelib.php');
2750 page_map_class(PAGE_ADMIN, 'page_admin');
2752 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
2754 $PAGE->init_extra($section); // hack alert!
2756 $root = $adminroot->locate($PAGE->section);
2758 if ($site = get_site()) {
2759 require_login();
2760 } else {
2761 redirect($CFG->wwwroot . '/'.$CFG->admin.'/index.php');
2762 die;
2765 if (!is_a($root, 'admin_externalpage')) {
2766 error(get_string('sectionerror','admin'));
2767 die;
2770 // this eliminates our need to authenticate on the actual pages
2771 if (!($root->check_access())) {
2772 error(get_string('accessdenied', 'admin'));
2773 die;
2776 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
2778 if (!isset($USER->adminediting)) {
2779 $USER->adminediting = false;
2782 if ($PAGE->user_allowed_editing()) {
2783 if ($adminediting == 1) {
2784 $USER->adminediting = true;
2785 } elseif ($adminediting == 0) {
2786 $USER->adminediting = false;
2793 * TODO document
2795 function admin_externalpage_print_header() {
2797 global $CFG, $PAGE, $SITE, $THEME;
2799 if (!empty($THEME->customcorners)) {
2800 require_once($CFG->dirroot.'/lib/custom_corners_lib.php');
2803 define('ADMIN_EXT_HEADER_PRINTED', 'true');
2805 if (!empty($SITE->fullname)) {
2806 $pageblocks = blocks_setup($PAGE);
2808 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
2809 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
2810 BLOCK_L_MAX_WIDTH);
2811 $PAGE->print_header();
2812 echo '<table id="layout-table" summary=""><tr>';
2814 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
2815 foreach ($lt as $column) {
2816 $lt1[] = $column;
2817 if ($column == 'middle') break;
2819 foreach ($lt1 as $column) {
2820 switch ($column) {
2821 case 'left':
2822 echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">';
2823 if (!empty($THEME->customcorners)) print_custom_corners_start();
2824 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
2825 if (!empty($THEME->customcorners)) print_custom_corners_end();
2826 echo '</td>';
2827 break;
2829 case 'middle':
2830 echo '<td id="middle-column">';
2831 if (!empty($THEME->customcorners)) print_custom_corners_start();
2832 break;
2834 case 'right':
2835 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
2836 echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">';
2837 if (!empty($THEME->customcorners)) print_custom_corners_start();
2838 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
2839 if (!empty($THEME->customcorners)) print_custom_corners_end();
2840 echo '</td>';
2842 break;
2845 } else {
2846 print_header();
2850 function admin_externalpage_print_footer() {
2852 global $CFG, $PAGE, $SITE, $THEME;
2854 if (!empty($THEME->customcorners)) {
2855 require_once($CFG->dirroot.'/lib/custom_corners_lib.php');
2858 define('ADMIN_EXT_FOOTER_PRINTED', 'true');
2860 if (!empty($SITE->fullname)) {
2861 $pageblocks = blocks_setup($PAGE);
2862 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
2863 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
2864 BLOCK_R_MAX_WIDTH);
2866 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
2867 foreach ($lt as $column) {
2868 if ($column != 'middle') {
2869 array_shift($lt);
2870 } else if ($column == 'middle') {
2871 break;
2874 foreach ($lt as $column) {
2875 switch ($column) {
2876 case 'left':
2877 echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">';
2878 if (!empty($THEME->customcorners)) print_custom_corners_start();
2879 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
2880 if (!empty($THEME->customcorners)) print_custom_corners_end();
2881 echo '</td>';
2882 break;
2884 case 'middle':
2885 if (!empty($THEME->customcorners)) print_custom_corners_end();
2886 echo '</td>';
2887 break;
2889 case 'right':
2890 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
2891 echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">';
2892 if (!empty($THEME->customcorners)) print_custom_corners_start();
2893 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
2895 if (!empty($THEME->customcorners)) print_custom_corners_end();
2896 echo '</td>';
2898 break;
2901 echo '</tr></table>';
2903 print_footer();
2906 function admin_get_root() {
2907 global $CFG;
2909 static $ADMIN;
2911 if (!isset($ADMIN)) {
2912 // start the admin tree!
2913 $ADMIN = new admin_category('root', get_string("administration"));
2914 // we process this file first to get categories up and running
2915 include($CFG->dirroot . '/'.$CFG->admin.'/settings/top.php');
2917 // now we process all other files in admin/settings to build the
2918 // admin tree
2919 foreach (glob($CFG->dirroot . '/'.$CFG->admin.'/settings/*.php') as $file) {
2920 if ($file != $CFG->dirroot . '/'.$CFG->admin.'/settings/top.php') {
2921 include_once($file);
2926 return $ADMIN;
2929 /// settings utiliti functions
2931 // n.b. this function unconditionally applies default settings
2932 function apply_default_settings(&$node) {
2934 global $CFG;
2936 if (is_a($node, 'admin_category')) {
2937 $entries = array_keys($node->children);
2938 foreach ($entries as $entry) {
2939 apply_default_settings($node->children[$entry]);
2941 return;
2944 if (is_a($node, 'admin_settingpage')) {
2945 foreach ($node->settings as $setting) {
2946 $CFG->{$setting->name} = $setting->defaultsetting;
2947 $setting->write_setting($setting->defaultsetting);
2948 unset($setting); // needed to prevent odd (imho) reference behaviour
2949 // see http://www.php.net/manual/en/language.references.whatdo.php#AEN6399
2951 return;
2954 return;
2958 // n.b. this function unconditionally applies default settings
2959 function apply_default_exception_settings($defaults) {
2961 global $CFG;
2963 foreach($defaults as $key => $value) {
2964 $CFG->$key = $value;
2965 set_config($key, $value);
2970 function format_admin_setting($name, $title='', $form='', $description='', $label=true) {
2972 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
2973 if ($label) {
2974 $labelfor = 'for = "id_s_'.$name.'"';
2975 } else {
2976 $labelfor = '';
2979 $str = "\n".
2980 '<div class="form-item" id="admin-'.$name.'">'."\n".
2981 '<label '.$labelfor.'>'.$title."\n".
2982 ' <span class="form-shortname">'.$name.'</span>'."\n".
2983 '</label>'."\n".
2984 $form."\n".
2985 '<div class="description">'.$description.'</div>'."\n".
2986 '</div>'.
2987 "\n\n";
2989 return $str;
2993 * Try to upgrade the given language pack (or current language)
2994 * If it doesn't work, fail silently and return false
2996 function upgrade_language_pack($lang='') {
2997 global $CFG;
2999 if (empty($lang)) {
3000 $lang = current_language();
3003 if ($lang == 'en_utf8') {
3004 return true; // Nothing to do
3007 notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
3009 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
3010 @mkdir ($CFG->dataroot.'/lang/');
3012 require_once($CFG->libdir.'/componentlib.class.php');
3014 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
3015 $status = $cd->install(); //returns ERROR | UPTODATE | INSTALLED
3017 if ($status == INSTALLED) {
3018 debugging('Downloading successful: '.$lang);
3019 @unlink($CFG->dataroot.'/cache/languages');
3020 return true;
3024 return false;
3028 * Based on find_new_settings{@link ()} in upgradesettings.php
3029 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
3031 * @param string &$node The node at which to start searching.
3032 * @return int Returns 1 if any settings haven't been initialised, 0 if they all have
3034 function any_new_admin_settings(&$node) {
3036 if (is_a($node, 'admin_category')) {
3037 $entries = array_keys($node->children);
3038 foreach ($entries as $entry) {
3039 if( any_new_admin_settings($node->children[$entry]) ){
3040 return 1;
3045 if (is_a($node, 'admin_settingpage')) {
3046 foreach ($node->settings as $setting) {
3047 if ($setting->get_setting() === NULL) {
3048 return 1;
3054 return 0;