4 * adminlib.php - Contains functions that only administrators will ever need to use
6 * @author Martin Dougiamas and many others
8 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
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) {
24 /// Let's know if the header has been printed, so the funcion is being called embedded in an outer page
25 $embedded = defined('HEADER_PRINTED');
27 $plugs = get_list_of_plugins($dir);
28 $updated_plugins = false;
29 $strpluginsetup = get_string('pluginsetup');
31 foreach ($plugs as $plug) {
33 $fullplug = $CFG->dirroot
.'/'.$dir.'/'. $plug;
37 if (is_readable($fullplug .'/version.php')) {
38 include_once($fullplug .'/version.php'); // defines $plugin with version etc
40 continue; // Nothing to do.
45 if (is_readable($fullplug . '/db/'. $CFG->dbtype
. '.php')) {
46 include_once($fullplug . '/db/'. $CFG->dbtype
. '.php'); // defines old upgrading function
49 if (is_readable($fullplug . '/db/upgrade.php')) {
50 include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
54 if (!isset($plugin)) {
58 if (!empty($plugin->requires
)) {
59 if ($plugin->requires
> $CFG->version
) {
61 $info->pluginname
= $plug;
62 $info->pluginversion
= $plugin->version
;
63 $info->currentmoodle
= $CFG->version
;
64 $info->requiremoodle
= $plugin->requires
;
65 if (!$updated_plugins && !$embedded) {
66 print_header($strpluginsetup, $strpluginsetup,
67 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
68 upgrade_get_javascript(), false, ' ', ' ');
71 notify(get_string('pluginrequirementsnotmet', 'error', $info));
72 $updated_plugins = true;
77 $plugin->name
= $plug; // The name MUST match the directory
79 $pluginversion = $type.'_'.$plug.'_version';
81 if (!isset($CFG->$pluginversion)) {
82 set_config($pluginversion, 0);
85 if ($CFG->$pluginversion == $plugin->version
) {
87 } else if ($CFG->$pluginversion < $plugin->version
) {
88 if (!$updated_plugins && !$embedded) {
89 print_header($strpluginsetup, $strpluginsetup,
90 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
91 upgrade_get_javascript(), false, ' ', ' ');
93 $updated_plugins = true;
95 print_heading($dir.'/'. $plugin->name
.' plugin needs upgrading');
97 @set_time_limit
(0); // To allow slow databases to complete the long SQL
99 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
100 /// Both old .sql files and new install.xml are supported
101 /// but we priorize install.xml (XMLDB) if present
103 if (file_exists($fullplug . '/db/install.xml')) {
104 $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
105 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype
.'.sql')) {
106 $status = modify_database($fullplug .'/db/'. $CFG->dbtype
.'.sql'); //Old method
112 /// Continue with the instalation, roles and other stuff
114 /// OK so far, now update the plugins record
115 set_config($pluginversion, $plugin->version
);
117 /// Install capabilities
118 if (!update_capabilities($type.'/'.$plug)) {
119 error('Could not set up the capabilities for '.$plugin->name
.'!');
122 events_update_definition($type.'/'.$plug);
124 /// Run local install function if there is one
125 if (is_readable($fullplug .'/lib.php')) {
126 include_once($fullplug .'/lib.php');
127 $installfunction = $plugin->name
.'_install';
128 if (function_exists($installfunction)) {
129 if (! $installfunction() ) {
130 notify('Encountered a problem running install function for '.$module->name
.'!');
135 notify(get_string('modulesuccess', '', $plugin->name
), 'notifysuccess');
137 notify('Installing '. $plugin->name
.' FAILED!');
139 } else { // Upgrade existing install
140 /// Run de old and new upgrade functions for the module
141 $oldupgrade_function = $type.'_'.$plugin->name
.'_upgrade';
142 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name
.'_upgrade';
144 /// First, the old function if exists
145 $oldupgrade_status = true;
146 if ($oldupgrade && function_exists($oldupgrade_function)) {
148 $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
149 } else if ($oldupgrade) {
150 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
151 $fullplug . '/db/' . $CFG->dbtype
. '.php');
154 /// Then, the new function if exists and the old one was ok
155 $newupgrade_status = true;
156 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
158 $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
159 } else if ($newupgrade) {
160 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
161 $fullplug . '/db/upgrade.php');
165 /// Now analyze upgrade results
166 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
167 // OK so far, now update the plugins record
168 set_config($pluginversion, $plugin->version
);
169 if (!update_capabilities($type.'/'.$plug)) {
170 error('Could not update '.$plugin->name
.' capabilities!');
172 events_update_definition($type.'/'.$plug);
173 notify(get_string('modulesuccess', '', $plugin->name
), 'notifysuccess');
175 notify('Upgrading '. $plugin->name
.' from '. $CFG->$pluginversion .' to '. $plugin->version
.' FAILED!');
181 error('Version mismatch: '. $plugin->name
.' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version
.' !');
185 upgrade_log_finish();
187 if ($updated_plugins && !$embedded) {
188 print_continue($return);
189 print_footer('none');
195 * Find and check all modules and load them up or upgrade them if necessary
199 * @param string $return The url to prompt the user to continue to
200 * @todo Finish documenting this function
202 function upgrade_activity_modules($return) {
206 if (!$mods = get_list_of_plugins('mod') ) {
207 error('No modules installed!');
210 $updated_modules = false;
211 $strmodulesetup = get_string('modulesetup');
213 foreach ($mods as $mod) {
215 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
219 $fullmod = $CFG->dirroot
.'/mod/'. $mod;
223 if ( is_readable($fullmod .'/version.php')) {
224 include_once($fullmod .'/version.php'); // defines $module with version etc
226 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
232 if ( is_readable($fullmod .'/db/' . $CFG->dbtype
. '.php')) {
233 include_once($fullmod .'/db/' . $CFG->dbtype
. '.php'); // defines old upgrading function
236 if ( is_readable($fullmod . '/db/upgrade.php')) {
237 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
241 if (!isset($module)) {
245 if (!empty($module->requires
)) {
246 if ($module->requires
> $CFG->version
) {
247 $info = new object();
248 $info->modulename
= $mod;
249 $info->moduleversion
= $module->version
;
250 $info->currentmoodle
= $CFG->version
;
251 $info->requiremoodle
= $module->requires
;
252 if (!$updated_modules) {
253 print_header($strmodulesetup, $strmodulesetup,
254 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
255 upgrade_get_javascript(), false, ' ', ' ');
258 notify(get_string('modulerequirementsnotmet', 'error', $info));
259 $updated_modules = true;
264 $module->name
= $mod; // The name MUST match the directory
266 include_once($fullmod.'/lib.php'); // defines upgrading and/or installing functions
268 if ($currmodule = get_record('modules', 'name', $module->name
)) {
269 if ($currmodule->version
== $module->version
) {
271 } else if ($currmodule->version
< $module->version
) {
272 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
273 if (!$oldupgrade && !$newupgrade) {
274 notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype
. '.php or ' .
275 $fullmod . '/db/upgrade.php were not readable');
278 if (!$updated_modules) {
279 print_header($strmodulesetup, $strmodulesetup,
280 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
281 upgrade_get_javascript(), false, ' ', ' ');
284 print_heading($module->name
.' module needs upgrading');
286 /// Run de old and new upgrade functions for the module
287 $oldupgrade_function = $module->name
. '_upgrade';
288 $newupgrade_function = 'xmldb_' . $module->name
. '_upgrade';
290 /// First, the old function if exists
291 $oldupgrade_status = true;
292 if ($oldupgrade && function_exists($oldupgrade_function)) {
294 $oldupgrade_status = $oldupgrade_function($currmodule->version
, $module);
295 } else if ($oldupgrade) {
296 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
297 $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype
. '.php');
300 /// Then, the new function if exists and the old one was ok
301 $newupgrade_status = true;
302 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
304 $newupgrade_status = $newupgrade_function($currmodule->version
, $module);
305 } else if ($newupgrade) {
306 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
307 $mod . ': ' . $fullmod . '/db/upgrade.php');
311 /// Now analyze upgrade results
312 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
313 // OK so far, now update the modules record
314 $module->id
= $currmodule->id
;
315 if (! update_record('modules', $module)) {
316 error('Could not update '. $module->name
.' record in modules table!');
318 remove_dir($CFG->dataroot
. '/cache', true); // flush cache
319 notify(get_string('modulesuccess', '', $module->name
), 'notifysuccess');
322 notify('Upgrading '. $module->name
.' from '. $currmodule->version
.' to '. $module->version
.' FAILED!');
325 /// Update the capabilities table?
326 if (!update_capabilities('mod/'.$module->name
)) {
327 error('Could not update '.$module->name
.' capabilities!');
329 events_update_definition('mod/'.$module->name
);
331 $updated_modules = true;
335 error('Version mismatch: '. $module->name
.' can\'t downgrade '. $currmodule->version
.' -> '. $module->version
.' !');
338 } else { // module not installed yet, so install it
339 if (!$updated_modules) {
340 print_header($strmodulesetup, $strmodulesetup,
341 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
342 upgrade_get_javascript(), false, ' ', ' ');
345 print_heading($module->name
);
346 $updated_modules = true;
348 @set_time_limit
(0); // To allow slow databases to complete the long SQL
350 /// Both old .sql files and new install.xml are supported
351 /// but we priorize install.xml (XMLDB) if present
352 if (file_exists($fullmod . '/db/install.xml')) {
353 $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
355 $status = modify_database($fullmod .'/db/'. $CFG->dbtype
.'.sql'); //Old method
360 /// Continue with the installation, roles and other stuff
362 if ($module->id
= insert_record('modules', $module)) {
365 if (!update_capabilities('mod/'.$module->name
)) {
366 error('Could not set up the capabilities for '.$module->name
.'!');
370 events_update_definition('mod/'.$module->name
);
372 /// Run local install function if there is one
373 $installfunction = $module->name
.'_install';
374 if (function_exists($installfunction)) {
375 if (! $installfunction() ) {
376 notify('Encountered a problem running install function for '.$module->name
.'!');
380 notify(get_string('modulesuccess', '', $module->name
), 'notifysuccess');
383 error($module->name
.' module could not be added to the module list!');
386 error($module->name
.' tables could NOT be set up successfully!');
390 /// Check submodules of this module if necessary
392 $submoduleupgrade = $module->name
.'_upgrade_submodules';
393 if (function_exists($submoduleupgrade)) {
398 /// Run any defaults or final code that is necessary for this module
400 if ( is_readable($fullmod .'/defaults.php')) {
401 // Insert default values for any important configuration variables
403 include_once($fullmod .'/defaults.php');
404 if (!empty($defaults)) {
405 foreach ($defaults as $name => $value) {
406 if (!isset($CFG->$name)) {
407 set_config($name, $value);
414 upgrade_log_finish(); // finish logging if started
416 if ($updated_modules) {
417 print_continue($return);
418 print_footer('none');
424 * This function will return FALSE if the lock fails to be set (ie, if it's already locked)
426 * @param string $name ?
427 * @param bool $value ?
428 * @param int $staleafter ?
429 * @param bool $clobberstale ?
430 * @todo Finish documenting this function
432 function set_cron_lock($name,$value=true,$staleafter=7200,$clobberstale=false) {
435 mtrace("Tried to get a cron lock for a null fieldname");
444 if ($config = get_record('config','name',$name)) {
445 if (empty($config->value
)) {
446 set_config($name,time());
449 if ((time() - $staleafter) > $config->value
) {
450 mtrace("STALE LOCKFILE FOR $name - was $config->value");
451 if (!empty($clobberstale)) {
452 set_config($name,time());
456 return false; // was not stale - ie, we're ok to still be running.
461 set_config($name,time());
466 function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
470 if ($total < 2) { // No need to show anything
474 if (empty($starttime)) {
475 $starttime = $lasttime = time();
476 $lasttime = $starttime - $updatetime;
477 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
478 echo '<div id="bar'.$total.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
479 echo '<div id="slider'.$total.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
481 echo '<div id="text'.$total.'" align="center" style="width:500px;"></div>';
482 echo '</td></tr></table>';
488 if ($done && (($now - $lasttime) >= $updatetime)) {
489 $elapsedtime = $now - $starttime;
490 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
491 $percentage = round((float)$done / (float)$total, 2);
492 $width = (int)(500 * $percentage);
494 if ($projectedtime > 10) {
495 $projectedtext = ' Ending: '.format_time($projectedtime);
501 echo 'document.getElementById("text'.$total.'").innerHTML = "'.addslashes($donetext).' ('.$done.'/'.$total.') '.$projectedtext.'";'."\n";
502 echo 'document.getElementById("slider'.$total.'").style.width = \''.$width.'px\';'."\n";
510 function upgrade_get_javascript() {
513 if (!empty($_SESSION['installautopilot'])) {
514 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
516 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
518 $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot
. '/lib/scroll_to_errors.js"></script>';
520 return $linktoscrolltoerrors;
523 function create_admin_user() {
526 if (empty($CFG->rolesactive
)) { // No admin user yet.
528 $user = new object();
529 $user->auth
= 'manual';
530 $user->firstname
= get_string('admin');
531 $user->lastname
= get_string('user');
532 $user->username
= 'admin';
533 $user->password
= hash_internal_user_password('admin');
534 $user->email
= 'root@localhost';
535 $user->confirmed
= 1;
536 $user->mnethostid
= $CFG->mnet_localhost_id
;
537 $user->lang
= $CFG->lang
;
538 $user->maildisplay
= 1;
539 $user->timemodified
= time();
541 if (!$user->id
= insert_record('user', $user)) {
542 error('SERIOUS ERROR: Could not create admin user record !!!');
545 if (!$user = get_record('user', 'id', $user->id
)) { // Double check.
546 error('User ID was incorrect (can\'t find it)');
549 // Assign the default admin roles to the new user.
550 if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW
)) {
551 error('No admin role could be found');
553 $sitecontext = get_context_instance(CONTEXT_SYSTEM
);
554 foreach ($adminroles as $adminrole) {
555 role_assign($adminrole->id
, $user->id
, 0, $sitecontext->id
);
558 set_config('rolesactive', 1);
561 $USER = get_complete_user_data('username', 'admin');
562 $USER->newadminuser
= 1;
563 load_all_capabilities();
565 redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id"); // Edit thyself
567 error('Can not create admin!');
571 ////////////////////////////////////////////////
572 /// upgrade logging functions
573 ////////////////////////////////////////////////
575 $upgradeloghandle = false;
576 $upgradelogbuffer = '';
577 // I did not find out how to use static variable in callback function,
578 // the problem was that I could not flush the static buffer :-(
579 global $upgradeloghandle, $upgradelogbuffer;
582 * Check if upgrade is already running.
584 * If anything goes wrong due to missing call to upgrade_log_finish()
585 * just restart the browser.
587 * @param string warning message indicating upgrade is already running
588 * @param int page reload timeout
590 function upgrade_check_running($message, $timeout) {
591 if (!empty($_SESSION['upgraderunning'])) {
593 redirect(me(), $message, $timeout);
598 * Start logging of output into file (if not disabled) and
599 * prevent aborting and concurrent execution of upgrade script.
601 * Please note that you can not write into session variables after calling this function!
603 * This function may be called repeatedly.
605 function upgrade_log_start() {
606 global $CFG, $upgradeloghandle;
608 if (!empty($_SESSION['upgraderunning'])) {
609 return; // logging already started
612 @ignore_user_abort
(true); // ignore if user stops or otherwise aborts page loading
613 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
614 if (empty($CFG->dbsessions
)) { // workaround for bug in adodb, db session can not be restarted
615 session_write_close(); // from now on user can reload page - will be displayed warning
617 make_upload_directory('upgradelogs');
618 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
619 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
623 * Terminate logging of output, flush all data, allow script aborting
624 * and reopen session for writing. Function error() does terminate the logging too.
626 * Please make sure that each upgrade_log_start() is properly terminated by
627 * this function or error().
629 * This function may be called repeatedly.
631 function upgrade_log_finish() {
632 global $CFG, $upgradeloghandle, $upgradelogbuffer;
634 if (empty($_SESSION['upgraderunning'])) {
635 return; // logging already terminated
639 if ($upgradelogbuffer !== '') {
640 @fwrite
($upgradeloghandle, $upgradelogbuffer);
641 $upgradelogbuffer = '';
643 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
644 @fclose
($upgradeloghandle);
645 $upgradeloghandle = false;
647 if (empty($CFG->dbsessions
)) {
648 @session_start
(); // ignore header errors, we only need to reopen session
650 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
651 if (connection_aborted()) {
654 @ignore_user_abort
(false);
658 * Callback function for logging into files. Not more than one file is created per minute,
659 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
661 * This function must not output any characters or throw warnigns and errors!
663 function upgrade_log_callback($string) {
664 global $CFG, $upgradeloghandle, $upgradelogbuffer;
666 if (empty($CFG->disableupgradelogging
) and ($string != '') and ($upgradeloghandle !== 'error')) {
667 if ($upgradeloghandle or ($upgradeloghandle = @fopen
($CFG->dataroot
.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
668 $upgradelogbuffer .= $string;
669 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
670 @fwrite
($upgradeloghandle, $upgradelogbuffer);
671 $upgradelogbuffer = '';
674 $upgradeloghandle = 'error';
681 * Try to verify that dataroot is not accessible from web.
682 * It is not 100% correct but might help to reduce number of vulnerable sites.
684 * Protection from httpd.conf and .htaccess is not detected properly.
686 function is_dataroot_insecure() {
689 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot
.'/')); // win32 backslash workaround
691 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot
, 1);
692 $rp = strrev(trim($rp, '/'));
693 $rp = explode('/', $rp);
695 if (strpos($siteroot, '/'.$r.'/') === 0) {
696 $siteroot = substr($siteroot, strlen($r)+
1); // moodle web in subdirectory
698 break; // probably alias root
702 $siteroot = strrev($siteroot);
703 $dataroot = str_replace('\\', '/', $CFG->dataroot
.'/');
705 if (strpos($dataroot, $siteroot) === 0) {
711 /// =============================================================================================================
712 /// administration tree classes and functions
715 // n.b. documentation is still in progress for this code
719 /// This file performs the following tasks:
720 /// -it defines the necessary objects and interfaces to build the Moodle
722 /// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
723 /// and admin_externalpage_print_footer() functions used on admin pages
725 /// ADMIN_SETTING OBJECTS
727 /// Moodle settings are represented by objects that inherit from the admin_setting
728 /// class. These objects encapsulate how to read a setting, how to write a new value
729 /// to a setting, and how to appropriately display the HTML to modify the setting.
731 /// ADMIN_SETTINGPAGE OBJECTS
733 /// The admin_setting objects are then grouped into admin_settingpages. The latter
734 /// appear in the Moodle admin tree block. All interaction with admin_settingpage
735 /// objects is handled by the admin/settings.php file.
737 /// ADMIN_EXTERNALPAGE OBJECTS
739 /// There are some settings in Moodle that are too complex to (efficiently) handle
740 /// with admin_settingpages. (Consider, for example, user management and displaying
741 /// lists of users.) In this case, we use the admin_externalpage object. This object
742 /// places a link to an external PHP file in the admin tree block.
744 /// If you're using an admin_externalpage object for some settings, you can take
745 /// advantage of the admin_externalpage_* functions. For example, suppose you wanted
746 /// to add a foo.php file into admin. First off, you add the following line to
747 /// admin/settings/first.php (at the end of the file) or to some other file in
750 /// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
751 /// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
753 /// Next, in foo.php, your file structure would resemble the following:
755 /// require_once('.../config.php');
756 /// require_once($CFG->libdir.'/adminlib.php');
757 /// admin_externalpage_setup('foo');
758 /// // functionality like processing form submissions goes here
759 /// admin_externalpage_print_header();
760 /// // your HTML goes here
761 /// admin_externalpage_print_footer();
763 /// The admin_externalpage_setup() function call ensures the user is logged in,
764 /// and makes sure that they have the proper role permission to access the page.
766 /// The admin_externalpage_print_header() function prints the header (it figures
767 /// out what category and subcategories the page is classified under) and ensures
768 /// that you're using the admin pagelib (which provides the admin tree block and
769 /// the admin bookmarks block).
771 /// The admin_externalpage_print_footer() function properly closes the tables
772 /// opened up by the admin_externalpage_print_header() function and prints the
773 /// standard Moodle footer.
775 /// ADMIN_CATEGORY OBJECTS
777 /// Above and beyond all this, we have admin_category objects. These objects
778 /// appear as folders in the admin tree block. They contain admin_settingpage's,
779 /// admin_externalpage's, and other admin_category's.
783 /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
784 /// from part_of_admin_tree (a pseudointerface). This interface insists that
785 /// a class has a check_access method for access permissions, a locate method
786 /// used to find a specific node in the admin tree, and a path method used
787 /// to determine the path to a specific node in the $ADMIN tree.
789 /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
790 /// interface ensures that the class implements a recursive add function which
791 /// accepts a part_of_admin_tree object and searches for the proper place to
792 /// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
794 /// Please note that the $this->name field of any part_of_admin_tree must be
795 /// UNIQUE throughout the ENTIRE admin tree.
797 /// The $this->name field of an admin_setting object (which is *not* part_of_
798 /// admin_tree) must be unique on the respective admin_settingpage where it is
802 /// MISCELLANEOUS STUFF (used by classes defined below) ///////////////////////
803 include_once($CFG->dirroot
. '/backup/lib.php');
805 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
808 * Pseudointerface for anything appearing in the admin tree
810 * The pseudointerface that is implemented by anything that appears in the admin tree
811 * block. It forces inheriting classes to define a method for checking user permissions
812 * and methods for finding something in the admin tree.
814 * @author Vincenzo K. Marcovecchio
817 class part_of_admin_tree
{
820 * Finds a named part_of_admin_tree.
822 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
823 * and not parentable_part_of_admin_tree, then this function should only check if
824 * $this->name matches $name. If it does, it should return a reference to $this,
825 * otherwise, it should return a reference to NULL.
827 * If a class inherits parentable_part_of_admin_tree, this method should be called
828 * recursively on all child objects (assuming, of course, the parent object's name
829 * doesn't match the search criterion).
831 * @param string $name The internal name of the part_of_admin_tree we're searching for.
832 * @return mixed An object reference or a NULL reference.
834 function &locate($name) {
835 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING
);
840 * Removes named part_of_admin_tree.
842 * @param string $name The internal name of the part_of_admin_tree we want to remove.
843 * @return bool success.
845 function prune($name) {
846 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING
);
851 * Verifies current user's access to this part_of_admin_tree.
853 * Used to check if the current user has access to this part of the admin tree or
854 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
855 * then this method is usually just a call to has_capability() in the site context.
857 * If a class inherits parentable_part_of_admin_tree, this method should return the
858 * logical OR of the return of check_access() on all child objects.
860 * @return bool True if the user has access, false if she doesn't.
862 function check_access() {
863 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING
);
868 * Mostly usefull for removing of some parts of the tree in admin tree block.
870 * @return True is hidden from normal list view
872 function is_hidden() {
873 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING
);
878 * Determines the path to $name in the admin tree.
880 * Used to determine the path to $name in the admin tree. If a class inherits only
881 * part_of_admin_tree and not parentable_part_of_admin_tree, then this method should
882 * check if $this->name matches $name. If it does, $name is pushed onto the $path
883 * array (at the end), and $path should be returned. If it doesn't, NULL should be
886 * If a class inherits parentable_part_of_admin_tree, it should do the above, but not
887 * return NULL on failure. Instead, it pushes $this->name onto $path, and then
888 * recursively calls path() on its child objects. If any are non-NULL, it should
889 * return $path (being certain that the last element of $path is equal to $name).
890 * If they are all NULL, it returns NULL.
892 * @param string $name The internal name of the part_of_admin_tree we're searching for.
893 * @param array $path Not used on external calls. Defaults to empty array.
894 * @return mixed If found, an array containing the internal names of each part_of_admin_tree that leads to $name. If not found, NULL.
896 function path($name, $path = array()) {
897 trigger_error('Admin class does not implement method <strong>path()</strong>', E_USER_WARNING
);
903 * Pseudointerface implemented by any part_of_admin_tree that has children.
905 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
906 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
907 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
908 * include an add method for adding other part_of_admin_tree objects as children.
910 * @author Vincenzo K. Marcovecchio
913 class parentable_part_of_admin_tree
extends part_of_admin_tree
{
916 * Adds a part_of_admin_tree object to the admin tree.
918 * Used to add a part_of_admin_tree object to this object or a child of this
919 * object. $something should only be added if $destinationname matches
920 * $this->name. If it doesn't, add should be called on child objects that are
921 * also parentable_part_of_admin_tree's.
923 * @param string $destinationname The internal name of the new parent for $something.
924 * @param part_of_admin_tree &$something The object to be added.
925 * @return bool True on success, false on failure.
927 function add($destinationname, &$something) {
928 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING
);
935 * The object used to represent folders (a.k.a. categories) in the admin tree block.
937 * Each admin_category object contains a number of part_of_admin_tree objects.
939 * @author Vincenzo K. Marcovecchio
942 class admin_category
extends parentable_part_of_admin_tree
{
945 * @var mixed An array of part_of_admin_tree objects that are this object's children
950 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
955 * @var string The displayed name for this category. Usually obtained through get_string()
960 * @var bool Should this category be hidden in admin tree block?
964 // constructor for an empty admin category
965 // $name is the internal name of the category. it MUST be unique in the entire hierarchy
966 // $visiblename is the displayed name of the category. use a get_string for this
969 * Constructor for an empty admin category
971 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
972 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
973 * @param bool $hidden hide category in admin tree block
974 * @return mixed Returns the new object.
976 function admin_category($name, $visiblename, $hidden = false) {
977 $this->children
= array();
979 $this->visiblename
= $visiblename;
980 $this->hidden
= $hidden;
984 * Finds the path to the part_of_admin_tree called $name.
986 * @param string $name The internal name that we're searching for.
987 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
988 * @return mixed An array of internal names that leads to $name, or NULL if not found.
990 function path($name, $path = array()) {
992 $path[count($path)] = $this->name
;
994 if ($this->name
== $name) {
998 foreach($this->children
as $child) {
999 if ($return = $child->path($name, $path)) {
1009 * Returns a reference to the part_of_admin_tree object with internal name $name.
1011 * @param string $name The internal name of the object we want.
1012 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1014 function &locate($name) {
1016 if ($this->name
== $name) {
1020 foreach($this->children
as $child) {
1021 if ($return =& $child->locate($name)) {
1030 * Removes part_of_admin_tree object with internal name $name.
1032 * @param string $name The internal name of the object we want to remove.
1033 * @return bool success
1035 function prune($name) {
1037 if ($this->name
== $name) {
1038 return false; //can not remove itself
1041 foreach($this->children
as $precedence => $child) {
1042 if ($child->name
== $name) {
1044 unset($this->children
[$precedence]);
1047 if ($this->children
[$precedence]->prune($name)) {
1055 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1057 * @param string $destinationame The internal name of the immediate parent that we want for &$something.
1058 * @param mixed &$something A part_of_admin_tree object to be added.
1059 * @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".
1060 * @return bool True if successfully added, false if &$something is not a part_of_admin_tree or if $name is not found.
1062 function add($destinationname, &$something, $precedence = '') {
1064 if (!is_a($something, 'part_of_admin_tree')) {
1068 if ($destinationname == $this->name
) {
1069 if ($precedence === '') {
1070 $this->children
[] = $something;
1072 if (isset($this->children
[$precedence])) { // this should never, ever be triggered in a release version of moodle.
1073 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 />');
1075 $this->children
[$precedence] = $something;
1082 $entries = array_keys($this->children
);
1084 foreach($entries as $entry) {
1085 $child =& $this->children
[$entry];
1086 if (is_a($child, 'parentable_part_of_admin_tree')) {
1087 if ($child->add($destinationname, $something, $precedence)) {
1098 * Checks if the user has access to anything in this category.
1100 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1102 function check_access() {
1105 foreach ($this->children
as $child) {
1106 $return = $return ||
$child->check_access();
1114 * Is this category hidden in admin tree block?
1116 * @return bool True if hidden
1118 function is_hidden() {
1119 return $this->hidden
;
1124 * Links external PHP pages into the admin tree.
1126 * See detailed usage example at the top of this document (adminlib.php)
1128 * @author Vincenzo K. Marcovecchio
1131 class admin_externalpage
extends part_of_admin_tree
{
1134 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1139 * @var string The displayed name for this external page. Usually obtained through get_string().
1144 * @var string The external URL that we should link to when someone requests this external page.
1149 * @var string The role capability/permission a user must have to access this external page.
1151 var $req_capability;
1154 * @var object The context in which capability/permission should be checked, default is site context.
1159 * @var bool hidden in admin tree block.
1164 * Constructor for adding an external page into the admin tree.
1166 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1167 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1168 * @param string $url The external URL that we should link to when someone requests this external page.
1169 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1171 function admin_externalpage($name, $visiblename, $url, $req_capability = 'moodle/site:config', $hidden=false, $context=NULL) {
1172 $this->name
= $name;
1173 $this->visiblename
= $visiblename;
1175 if (is_array($req_capability)) {
1176 $this->req_capability
= $req_capability;
1178 $this->req_capability
= array($req_capability);
1180 $this->hidden
= $hidden;
1181 $this->context
= $context;
1185 * Finds the path to the part_of_admin_tree called $name.
1187 * @param string $name The internal name that we're searching for.
1188 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
1189 * @return mixed An array of internal names that leads to $name, or NULL if not found.
1191 function path($name, $path = array()) {
1192 if ($name == $this->name
) {
1193 array_push($path, $this->name
);
1201 * Returns a reference to the part_of_admin_tree object with internal name $name.
1203 * @param string $name The internal name of the object we want.
1204 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1206 function &locate($name) {
1207 $return = ($this->name
== $name ?
$this : NULL);
1211 function prune($name) {
1216 * Determines if the current user has access to this external page based on $this->req_capability.
1218 * @uses CONTEXT_SYSTEM
1220 * @return bool True if user has access, false otherwise.
1222 function check_access() {
1224 return true; // no access check before site is fully set up
1226 $context = empty($this->context
) ?
get_context_instance(CONTEXT_SYSTEM
) : $this->context
;
1227 foreach($this->req_capability
as $cap) {
1228 if (has_capability($cap, $context)) {
1236 * Is this external page hidden in admin tree block?
1238 * @return bool True if hidden
1240 function is_hidden() {
1241 return $this->hidden
;
1247 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1249 * @author Vincenzo K. Marcovecchio
1252 class admin_settingpage
extends part_of_admin_tree
{
1255 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1260 * @var string The displayed name for this external page. Usually obtained through get_string().
1264 * @var mixed An array of admin_setting objects that are part of this setting page.
1269 * @var string The role capability/permission a user must have to access this external page.
1271 var $req_capability;
1274 * @var object The context in which capability/permission should be checked, default is site context.
1279 * @var bool hidden in admin tree block.
1283 // see admin_category
1284 function path($name, $path = array()) {
1285 if ($name == $this->name
) {
1286 array_push($path, $this->name
);
1293 // see admin_category
1294 function &locate($name) {
1295 $return = ($this->name
== $name ?
$this : NULL);
1299 function prune($name) {
1303 // see admin_externalpage
1304 function admin_settingpage($name, $visiblename, $req_capability = 'moodle/site:config', $hidden=false, $context=NULL) {
1306 $this->settings
= new stdClass();
1307 $this->name
= $name;
1308 $this->visiblename
= $visiblename;
1309 if (is_array($req_capability)) {
1310 $this->req_capability
= $req_capability;
1312 $this->req_capability
= array($req_capability);
1314 $this->hidden
= false;
1315 $this->context
= $context;
1318 // 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
1319 // n.b. each admin_setting in an admin_settingpage must have a unique internal name
1320 // &$setting is the admin_setting object you want to add
1321 // returns true if successful, false if not (will fail if &$setting is an admin_setting or child thereof)
1322 function add(&$setting) {
1323 if (is_a($setting, 'admin_setting')) {
1324 $this->settings
->{$setting->name
} =& $setting;
1330 // see admin_externalpage
1331 function check_access() {
1333 return true; // no access check before site is fully set up
1335 $context = empty($this->context
) ?
get_context_instance(CONTEXT_SYSTEM
) : $this->context
;
1336 foreach($this->req_capability
as $cap) {
1337 if (has_capability($cap, $context)) {
1344 // outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1345 // returns a string of the html
1346 function output_html() {
1347 $return = '<fieldset>' . "\n";
1348 $return .= '<div class="clearer"><!-- --></div>' . "\n";
1349 foreach($this->settings
as $setting) {
1350 $return .= $setting->output_html();
1352 $return .= '</fieldset>';
1356 // 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
1357 // -- calls write_setting() to each child setting, sending it only the data that matches each setting's internal name
1358 // $data should be the result from data_submitted()
1359 // returns an empty string if everything went well, otherwise returns a printable error string (that's language-specific)
1360 function write_settings($data) {
1362 foreach($this->settings
as $setting) {
1363 if (isset($data['s_' . $setting->name
])) {
1364 $return .= $setting->write_setting($data['s_' . $setting->name
]);
1366 $return .= $setting->write_setting('');
1373 * Is this settigns page hidden in admin tree block?
1375 * @return bool True if hidden
1377 function is_hidden() {
1378 return $this->hidden
;
1384 // read & write happens at this level; no authentication
1385 class admin_setting
{
1390 var $defaultsetting;
1392 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1393 $this->name
= $name;
1394 $this->visiblename
= $visiblename;
1395 $this->description
= $description;
1396 $this->defaultsetting
= $defaultsetting;
1399 function get_setting() {
1400 return NULL; // has to be overridden
1403 function write_setting($data) {
1404 return; // has to be overridden
1407 function output_html() {
1408 return; // has to be overridden
1414 class admin_setting_configtext
extends admin_setting
{
1418 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW
) {
1419 $this->paramtype
= $paramtype;
1420 parent
::admin_setting($name, $visiblename, $description, $defaultsetting);
1423 // returns a string or NULL
1424 function get_setting() {
1426 return (isset($CFG->{$this->name
}) ?
$CFG->{$this->name
} : NULL);
1429 // $data is a string
1430 function write_setting($data) {
1431 if (!$this->validate($data)) {
1432 return get_string('validateerror', 'admin') . $this->visiblename
. '<br />';
1434 return (set_config($this->name
,$data) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1437 function validate($data) {
1438 if (is_string($this->paramtype
)) {
1439 return preg_match($this->paramtype
, $data);
1440 } else if ($this->paramtype
=== PARAM_RAW
) {
1443 $cleaned = clean_param($data, $this->paramtype
);
1444 return ("$data" == "$cleaned"); // implicit conversion to string is needed to do exact comparison
1448 function output_html() {
1449 if ($this->get_setting() === NULL) {
1450 $current = $this->defaultsetting
;
1452 $current = $this->get_setting();
1454 return format_admin_setting($this->name
, $this->visiblename
,
1455 '<input type="text" class="form-text" id="id_s_'.$this->name
.'" name="s_'.$this->name
.'" value="'.s($current).'" />',
1456 $this->description
);
1461 class admin_setting_configpasswordunmask
extends admin_setting_configtext
{
1463 function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW
) {
1464 parent
::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1467 function output_html() {
1468 if ($this->get_setting() === NULL) {
1469 $current = $this->defaultsetting
;
1471 $current = $this->get_setting();
1473 $id = 'id_s_'.$this->name
;
1474 $unmask = get_string('unmaskpassword', 'form');
1475 $unmaskjs = '<script type="text/javascript">
1477 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>\');
1480 return format_admin_setting($this->name
, $this->visiblename
,
1481 '<input type="password" class="form-text" id="id_s_'.$this->name
.'" name="s_'.$this->name
.'" value="'.s($current).'" />'.$unmaskjs,
1482 $this->description
);
1487 class admin_setting_configcheckbox
extends admin_setting
{
1489 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting) {
1490 parent
::admin_setting($name, $visiblename, $description, $defaultsetting);
1493 function get_setting() {
1495 return (isset($CFG->{$this->name
}) ?
$CFG->{$this->name
} : NULL);
1498 function write_setting($data) {
1500 return (set_config($this->name
,1) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1502 return (set_config($this->name
,0) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1506 function output_html() {
1507 if ($this->get_setting() === NULL) {
1508 $current = $this->defaultsetting
;
1510 $current = $this->get_setting();
1512 return format_admin_setting($this->name
, $this->visiblename
,
1513 '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name
.'" name="s_'. $this->name
.'" value="1" ' . ($current == true ?
'checked="checked"' : '') . ' />',
1514 $this->description
);
1519 class admin_setting_configselect
extends admin_setting
{
1523 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
1524 $this->choices
= $choices;
1525 parent
::admin_setting($name, $visiblename, $description, $defaultsetting);
1528 function get_setting() {
1530 return (isset($CFG->{$this->name
}) ?
$CFG->{$this->name
} : NULL);
1533 function write_setting($data) {
1534 // check that what we got was in the original choices
1535 // or that the data is the default setting - needed during install when choices can not be constructed yet
1536 if ($data != $this->defaultsetting
and ! in_array($data, array_keys($this->choices
))) {
1537 return 'Error setting ' . $this->visiblename
. '<br />';
1540 return (set_config($this->name
, $data) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1543 function output_html() {
1544 if ($this->get_setting() === NULL) {
1545 $current = $this->defaultsetting
;
1547 $current = $this->get_setting();
1549 $return = '<select class="form-select" id="id_s_'.$this->name
.'" name="s_' . $this->name
.'">';
1550 foreach ($this->choices
as $key => $value) {
1551 // the string cast is needed because key may be integer - 0 is equal to most strings!
1552 $return .= '<option value="'.$key.'"'.((string)$key==$current ?
' selected="selected"' : '').'>'.$value.'</option>';
1554 $return .= '</select>';
1556 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
);
1561 // 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
1562 // internally for the setting)
1563 class admin_setting_configtime
extends admin_setting
{
1569 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
1570 $this->name2
= $minutesname;
1571 $this->choices
= array();
1572 for ($i = 0; $i < 24; $i++
) {
1573 $this->choices
[$i] = $i;
1575 $this->choices2
= array();
1576 for ($i = 0; $i < 60; $i +
= 5) {
1577 $this->choices2
[$i] = $i;
1579 parent
::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
1582 function get_setting() {
1584 return (isset($CFG->{$this->name
}) && isset($CFG->{$this->name2
}) ?
array('h' => $CFG->{$this->name
}, 'm' => $CFG->{$this->name2
}) : NULL);
1587 function write_setting($data) {
1588 // check that what we got was in the original choices
1589 if (!(in_array($data['h'], array_keys($this->choices
)) && in_array($data['m'], array_keys($this->choices2
)))) {
1590 return get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
1593 return (set_config($this->name
, $data['h']) && set_config($this->name2
, $data['m']) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1596 function output_html() {
1597 if ($this->get_setting() === NULL) {
1598 $currentsetting = $this->defaultsetting
;
1600 $currentsetting = $this->get_setting();
1602 $return = '<div class="form-group">'.
1603 '<select class="form-select" id="id_s_'.$this->name
.'h" name="s_' . $this->name
.'[h]">';
1604 foreach ($this->choices
as $key => $value) {
1605 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['h'] ?
' selected="selected"' : '') . '>' . $value . '</option>';
1607 $return .= '</select>:<select class="form-select" id="id_s_'.$this->name
.'m" name="s_' . $this->name
. '[m]">';
1608 foreach ($this->choices2
as $key => $value) {
1609 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['m'] ?
' selected="selected"' : '') . '>' . $value . '</option>';
1611 $return .= '</select></div>';
1612 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
1617 class admin_setting_configmultiselect
extends admin_setting_configselect
{
1619 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
1620 parent
::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1623 function get_setting() {
1625 if (isset($CFG->{$this->name
})) {
1626 if ($CFG->{$this->name
}) {
1627 return explode(',', $CFG->{$this->name
});
1636 function write_setting($data) {
1640 foreach ($data as $datum) {
1641 if (! in_array($datum, array_keys($this->choices
))) {
1642 return get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
1646 return (set_config($this->name
, implode(',',$data)) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1649 function output_html() {
1650 if ($this->get_setting() === NULL) {
1651 $currentsetting = $this->defaultsetting
;
1652 if (!$currentsetting) {
1653 $currentsetting = array();
1656 $currentsetting = $this->get_setting();
1658 $return = '<select class="form-select" id="id_s_'.$this->name
.'" name="s_' . $this->name
.'[]" size="10" multiple="multiple">';
1659 foreach ($this->choices
as $key => $value) {
1660 $return .= '<option value="' . $key . '"' . (in_array($key,$currentsetting) ?
' selected="selected"' : '') . '>' . $value . '</option>';
1662 $return .= '</select>';
1663 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
);
1668 class admin_setting_special_adminseesall
extends admin_setting_configcheckbox
{
1670 function admin_setting_special_adminseesall() {
1671 $name = 'calendar_adminseesall';
1672 $visiblename = get_string('adminseesall', 'admin');
1673 $description = get_string('helpadminseesall', 'admin');
1674 parent
::admin_setting($name, $visiblename, $description, 0);
1677 function write_setting($data) {
1679 unset($SESSION->cal_courses_shown
);
1680 parent
::write_setting($data);
1684 class admin_setting_sitesetselect
extends admin_setting_configselect
{
1688 function admin_setting_sitesetselect($name, $visiblename, $description, $defaultsetting, $choices) {
1691 parent
::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1695 function get_setting() {
1697 return (isset($site->{$this->name
}) ?
$site->{$this->name
} : NULL);
1700 function write_setting($data) {
1701 if (!in_array($data, array_keys($this->choices
))) {
1702 return get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
1704 $record = new stdClass();
1705 $record->id
= $this->id
;
1706 $temp = $this->name
;
1707 $record->$temp = $data;
1708 $record->timemodified
= time();
1709 return (update_record('course', $record) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1715 class admin_setting_courselist_frontpage
extends admin_setting_configselect
{
1717 function admin_setting_courselist_frontpage($loggedin) {
1719 require_once($CFG->dirroot
. '/course/lib.php');
1720 $name = 'frontpage' . ($loggedin ?
'loggedin' : '');
1721 $visiblename = get_string('frontpage' . ($loggedin ?
'loggedin' : ''),'admin');
1722 $description = get_string('configfrontpage' . ($loggedin ?
'loggedin' : ''),'admin');
1723 $choices = array(FRONTPAGENEWS
=> get_string('frontpagenews'),
1724 FRONTPAGECOURSELIST
=> get_string('frontpagecourselist'),
1725 FRONTPAGECATEGORYNAMES
=> get_string('frontpagecategorynames'),
1726 FRONTPAGECATEGORYCOMBO
=> get_string('frontpagecategorycombo'),
1727 '' => get_string('none'));
1728 if (!$loggedin and count_records("course") > FRONTPAGECOURSELIMIT
) {
1729 unset($choices[FRONTPAGECOURSELIST
]);
1731 $defaults = FRONTPAGECOURSELIST
.',,,';
1732 parent
::admin_setting_configselect($name, $visiblename, $description, $defaults, $choices);
1735 function get_setting() {
1737 return (isset($CFG->{$this->name
}) ?
explode(',', $CFG->{$this->name
}) : ',1,,');
1740 function write_setting($data) {
1743 } if (!is_array($data)) {
1744 $data = explode(',', $data);
1746 foreach($data as $datum) {
1747 if (! in_array($datum, array_keys($this->choices
))) {
1748 return get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
1751 return (set_config($this->name
, implode(',', $data)) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1754 function output_html() {
1755 if ($this->get_setting() === NULL) {
1756 $currentsetting = $this->defaultsetting
;
1758 $currentsetting = $this->get_setting();
1760 for ($i = 0; $i < count($this->choices
) - 1; $i++
) {
1761 if (!isset($currentsetting[$i])) {
1762 $currentsetting[$i] = 0;
1765 $return = '<div class="form-group">';
1766 for ($i = 0; $i < count($this->choices
) - 1; $i++
) {
1767 $return .='<select class="form-select" id="id_s_'.$this->name
.$i.'" name="s_' . $this->name
.'[]">';
1768 foreach ($this->choices
as $key => $value) {
1769 $return .= '<option value="' . $key . '"' . ($key == $currentsetting[$i] ?
' selected="selected"' : '') . '>' . $value . '</option>';
1771 $return .= '</select>';
1772 if ($i !== count($this->choices
) - 2) {
1773 $return .= '<br />';
1776 $return .= '</div>';
1778 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
1782 class admin_setting_sitesetcheckbox
extends admin_setting_configcheckbox
{
1786 function admin_setting_sitesetcheckbox($name, $visiblename, $description, $defaultsetting) {
1789 parent
::admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting);
1793 function get_setting() {
1795 return (isset($site->{$this->name
}) ?
$site->{$this->name
} : NULL);
1798 function write_setting($data) {
1799 $record = new stdClass();
1800 $record->id
= $this->id
;
1801 $temp = $this->name
;
1802 $record->$temp = ($data == '1' ?
1 : 0);
1803 $record->timemodified
= time();
1804 return (update_record('course', $record) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1809 class admin_setting_sitesettext
extends admin_setting_configtext
{
1813 function admin_setting_sitesettext($name, $visiblename, $description, $defaultsetting) {
1816 parent
::admin_setting_configtext($name, $visiblename, $description, $defaultsetting);
1820 function get_setting() {
1822 return (isset($site->{$this->name
}) ?
$site->{$this->name
} : NULL);
1825 function validate($data) {
1826 $cleaned = stripslashes(clean_param($data, PARAM_MULTILANG
));
1827 if ($cleaned == '') {
1828 return false; // can not be empty
1830 return ($data == $cleaned); // implicit conversion to string is needed to do exact comparison
1833 function write_setting($data) {
1834 $data = trim($data);
1835 if (!$this->validate($data)) {
1836 return get_string('validateerror', 'admin') . $this->visiblename
. '<br />';
1839 $record = new stdClass();
1840 $record->id
= $this->id
;
1841 $record->{$this->name
} = addslashes($data);
1842 $record->timemodified
= time();
1843 return (update_record('course', $record) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1848 class admin_setting_special_frontpagedesc
extends admin_setting
{
1852 function admin_setting_special_frontpagedesc() {
1855 $visiblename = get_string('frontpagedescription');
1856 $description = get_string('frontpagedescriptionhelp');
1857 parent
::admin_setting($name, $visiblename, $description, '');
1860 function output_html() {
1864 if ($this->get_setting() === NULL) {
1865 $currentsetting = $this->defaultsetting
;
1867 $currentsetting = $this->get_setting();
1870 $CFG->adminusehtmleditor
= can_use_html_editor();
1872 $return = print_textarea($CFG->adminusehtmleditor
, 15, 60, 0, 0, 's_' . $this->name
, $currentsetting, 0, true);
1874 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
1877 function get_setting() {
1880 return (isset($site->{$this->name
}) ?
$site->{$this->name
} : NULL);
1884 function write_setting($data) {
1886 $data = addslashes(clean_param($data, PARAM_CLEANHTML
));
1888 $record = new stdClass();
1889 $record->id
= $this->id
;
1890 $temp = $this->name
;
1891 $record->$temp = $data;
1892 $record->timemodified
= time();
1894 return(update_record('course', $record) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1901 class admin_setting_special_editorfontlist
extends admin_setting
{
1905 function admin_setting_special_editorfontlist() {
1907 $name = 'editorfontlist';
1908 $visiblename = get_string('editorfontlist', 'admin');
1909 $description = get_string('configeditorfontlist', 'admin');
1910 $defaults = array('k0' => 'Trebuchet',
1911 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
1913 'v1' => 'arial,helvetica,sans-serif',
1914 'k2' => 'Courier New',
1915 'v2' => 'courier new,courier,monospace',
1917 'v3' => 'georgia,times new roman,times,serif',
1919 'v4' => 'tahoma,arial,helvetica,sans-serif',
1920 'k5' => 'Times New Roman',
1921 'v5' => 'times new roman,times,serif',
1923 'v6' => 'verdana,arial,helvetica,sans-serif',
1926 'k8' => 'Wingdings',
1927 'v8' => 'wingdings');
1928 parent
::admin_setting($name, $visiblename, $description, $defaults);
1931 function get_setting() {
1933 if (isset($CFG->editorfontlist
)) {
1935 $currentsetting = array();
1936 $items = explode(';', $CFG->editorfontlist
);
1937 foreach ($items as $item) {
1938 $item = explode(':', $item);
1939 $currentsetting['k' . $i] = $item[0];
1940 $currentsetting['v' . $i] = $item[1];
1943 return $currentsetting;
1949 function write_setting($data) {
1951 // there miiight be an easier way to do this :)
1952 // if this is changed, make sure the $defaults array above is modified so that this
1953 // function processes it correctly
1958 foreach ($data as $key => $value) {
1959 if (substr($key,0,1) == 'k') {
1960 $keys[substr($key,1)] = $value;
1961 } elseif (substr($key,0,1) == 'v') {
1962 $values[substr($key,1)] = $value;
1967 for ($i = 0; $i < count($keys); $i++
) {
1968 if (($keys[$i] !== '') && ($values[$i] !== '')) {
1969 $result .= clean_param($keys[$i],PARAM_NOTAGS
) . ':' . clean_param($values[$i], PARAM_NOTAGS
) . ';';
1973 $result = substr($result, 0, -1); // trim the last semicolon
1975 return (set_config($this->name
, $result) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
1978 function output_html() {
1980 if ($this->get_setting() === NULL) {
1981 $currentsetting = $this->defaultsetting
;
1983 $currentsetting = $this->get_setting();
1986 $return = '<div class="form-group">';
1987 for ($i = 0; $i < count($currentsetting) / 2; $i++
) {
1988 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="' . $currentsetting['k' . $i] . '" />';
1989 $return .= ' ';
1990 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="' . $currentsetting['v' . $i] . '" /><br />';
1992 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="" />';
1993 $return .= ' ';
1994 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="" /><br />';
1995 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . ($i +
1) . ']" value="" />';
1996 $return .= ' ';
1997 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . ($i +
1) . ']" value="" />';
1998 $return .= '</div>';
2000 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
2005 class admin_setting_special_editordictionary
extends admin_setting_configselect
{
2007 function admin_setting_special_editordictionary() {
2008 $name = 'editordictionary';
2009 $visiblename = get_string('editordictionary','admin');
2010 $description = get_string('configeditordictionary', 'admin');
2011 $choices = $this->editor_get_dictionaries();
2012 if (! is_array($choices)) {
2013 $choices = array('');
2016 parent
::admin_setting_configselect($name, $visiblename, $description, '', $choices);
2019 // function borrowed from the old moodle/admin/editor.php, slightly modified
2020 function editor_get_dictionaries () {
2021 /// Get all installed dictionaries in the system
2025 // error_reporting(E_ALL); // for debug, final version shouldn't have this...
2028 // If aspellpath isn't set don't even bother ;-)
2029 if (empty($CFG->aspellpath
)) {
2030 return 'Empty aspell path!';
2033 // Do we have access to popen function?
2034 if (!function_exists('popen')) {
2035 return 'Popen function disabled!';
2038 $cmd = $CFG->aspellpath
;
2040 $dictionaries = array();
2043 if(!($handle = @popen
(escapeshellarg($cmd) .' dump dicts', 'r'))) {
2044 return 'Couldn\'t create handle!';
2047 while(!feof($handle)) {
2048 $output .= fread($handle, 1024);
2052 $dictionaries = explode(chr(10), $output);
2054 // Get rid of possible empty values
2055 if (is_array($dictionaries)) {
2057 $cnt = count($dictionaries);
2059 for ($i = 0; $i < $cnt; $i++
) {
2060 if (!empty($dictionaries[$i])) {
2061 $dicts[$dictionaries[$i]] = $dictionaries[$i];
2066 if (count($dicts) >= 1) {
2070 return 'Error! Check your aspell installation!';
2078 class admin_setting_special_editorhidebuttons
extends admin_setting
{
2085 function admin_setting_special_editorhidebuttons() {
2086 $this->name
= 'editorhidebuttons';
2087 $this->visiblename
= get_string('editorhidebuttons', 'admin');
2088 $this->description
= get_string('confeditorhidebuttons', 'admin');
2089 $this->defaultsetting
= array();
2090 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
2091 $this->items
= array('fontname' => '',
2093 'formatblock' => '',
2094 'bold' => 'ed_format_bold.gif',
2095 'italic' => 'ed_format_italic.gif',
2096 'underline' => 'ed_format_underline.gif',
2097 'strikethrough' => 'ed_format_strike.gif',
2098 'subscript' => 'ed_format_sub.gif',
2099 'superscript' => 'ed_format_sup.gif',
2100 'copy' => 'ed_copy.gif',
2101 'cut' => 'ed_cut.gif',
2102 'paste' => 'ed_paste.gif',
2103 'clean' => 'ed_wordclean.gif',
2104 'undo' => 'ed_undo.gif',
2105 'redo' => 'ed_redo.gif',
2106 'justifyleft' => 'ed_align_left.gif',
2107 'justifycenter' => 'ed_align_center.gif',
2108 'justifyright' => 'ed_align_right.gif',
2109 'justifyfull' => 'ed_align_justify.gif',
2110 'lefttoright' => 'ed_left_to_right.gif',
2111 'righttoleft' => 'ed_right_to_left.gif',
2112 'insertorderedlist' => 'ed_list_num.gif',
2113 'insertunorderedlist' => 'ed_list_bullet.gif',
2114 'outdent' => 'ed_indent_less.gif',
2115 'indent' => 'ed_indent_more.gif',
2116 'forecolor' => 'ed_color_fg.gif',
2117 'hilitecolor' => 'ed_color_bg.gif',
2118 'inserthorizontalrule' => 'ed_hr.gif',
2119 'createanchor' => 'ed_anchor.gif',
2120 'createlink' => 'ed_link.gif',
2121 'unlink' => 'ed_unlink.gif',
2122 'insertimage' => 'ed_image.gif',
2123 'inserttable' => 'insert_table.gif',
2124 'insertsmile' => 'em.icon.smile.gif',
2125 'insertchar' => 'icon_ins_char.gif',
2126 'spellcheck' => 'spell-check.gif',
2127 'htmlmode' => 'ed_html.gif',
2128 'popupeditor' => 'fullscreen_maximize.gif',
2129 'search_replace' => 'ed_replace.gif');
2132 function get_setting() {
2134 return (isset($CFG->{$this->name
}) ?
explode(' ', $CFG->{$this->name
}) : NULL);
2137 function write_setting($data) {
2139 if (empty($data)) { $data = array(); }
2140 foreach ($data as $key => $value) {
2141 if (!in_array($key, array_keys($this->items
))) {
2142 return get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
2144 if ($value == '1') {
2148 return (set_config($this->name
, implode(' ',$result)) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2151 function output_html() {
2155 // checkboxes with input name="$this->name[$key]" value="1"
2156 // we do 15 fields per column
2158 if ($this->get_setting() === NULL) {
2159 $currentsetting = $this->defaultsetting
;
2161 $currentsetting = $this->get_setting();
2164 $return = '<div class="form-group">';
2165 $return .= '<table><tr><td valign="top" align="right">';
2169 foreach($this->items
as $key => $value) {
2170 if ($count %
15 == 0 and $count != 0) {
2171 $return .= '</td><td valign="top" align="right">';
2174 $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') . '" />') . ' ';
2175 $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"' : '') . ' /> ';
2177 if ($count %
15 != 0) {
2178 $return .= '<br /><br />';
2182 $return .= '</td></tr>';
2183 $return .= '</table>';
2184 $return .= '</div>';
2186 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
2191 class admin_setting_langlist
extends admin_setting_configtext
{
2192 function admin_setting_langlist() {
2193 parent
::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS
);
2196 function write_setting($data) {
2197 $return = parent
::write_setting($data);
2198 get_list_of_languages(true);//refresh the list
2203 class admin_setting_backupselect
extends admin_setting_configselect
{
2205 function admin_setting_backupselect($name, $visiblename, $description, $default, $choices) {
2206 parent
::admin_setting_configselect($name, $visiblename, $description, $default, $choices);
2209 function get_setting() {
2210 $backup_config = backup_get_config();
2211 return (isset($backup_config->{$this->name
}) ?
$backup_config->{$this->name
} : NULL);
2214 function write_setting($data) {
2215 // check that what we got was in the original choices
2216 if (! in_array($data, array_keys($this->choices
))) {
2217 return get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
2220 return (backup_set_config($this->name
, $data) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2225 class admin_setting_special_backupsaveto
extends admin_setting_configtext
{
2227 function admin_setting_special_backupsaveto() {
2228 $name = 'backup_sche_destination';
2229 $visiblename = get_string('saveto');
2230 $description = get_string('backupsavetohelp');
2231 parent
::admin_setting_configtext($name, $visiblename, $description, '');
2234 function get_setting() {
2235 $backup_config = backup_get_config();
2236 return (isset($backup_config->{$this->name
}) ?
$backup_config->{$this->name
} : NULL);
2239 function write_setting($data) {
2240 $data = trim($data);
2241 if (!empty($data) and !is_dir($data)) {
2242 return get_string('pathnotexists') . '<br />';
2244 return (backup_set_config($this->name
, $data) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2249 class admin_setting_backupcheckbox
extends admin_setting_configcheckbox
{
2251 function admin_setting_backupcheckbox($name, $visiblename, $description, $default) {
2252 parent
::admin_setting_configcheckbox($name, $visiblename, $description, $default);
2255 function write_setting($data) {
2257 return (backup_set_config($this->name
, 1) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2259 return (backup_set_config($this->name
, 0) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2263 function get_setting() {
2264 $backup_config = backup_get_config();
2265 return (isset($backup_config->{$this->name
}) ?
$backup_config->{$this->name
} : NULL);
2270 class admin_setting_special_backuptime
extends admin_setting_configtime
{
2272 function admin_setting_special_backuptime() {
2273 $name = 'backup_sche_hour';
2274 $name2 = 'backup_sche_minute';
2275 $visiblename = get_string('executeat');
2276 $description = get_string('backupexecuteathelp');
2277 $default = array('h' => 0, 'm' => 0);
2278 parent
::admin_setting_configtime($name, $name2, $visiblename, $description, $default);
2281 function get_setting() {
2282 $backup_config = backup_get_config();
2283 return (isset($backup_config->{$this->name
}) && isset($backup_config->{$this->name
}) ?
array('h'=>$backup_config->{$this->name
}, 'm'=>$backup_config->{$this->name2
}) : NULL);
2286 function write_setting($data) {
2287 // check that what we got was in the original choices
2288 if (!(in_array($data['h'], array_keys($this->choices
)) && in_array($data['m'], array_keys($this->choices2
)))) {
2289 return get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
2292 return (backup_set_config($this->name
, $data['h']) && backup_set_config($this->name2
, $data['m']) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2297 class admin_setting_special_backupdays
extends admin_setting
{
2299 function admin_setting_special_backupdays() {
2300 $name = 'backup_sche_weekdays';
2301 $visiblename = get_string('schedule');
2302 $description = get_string('backupschedulehelp');
2303 $default = array('u' => 0, 'm' => 0, 't' => 0, 'w' => 0, 'r' => 0, 'f' => 0, 's' => 0);
2304 parent
::admin_setting($name, $visiblename, $description, $default);
2307 function get_setting() {
2308 $backup_config = backup_get_config();
2309 if (isset($backup_config->{$this->name
})) {
2310 $currentsetting = $backup_config->{$this->name
};
2311 return array('u' => substr($currentsetting, 0, 1),
2312 'm' => substr($currentsetting, 1, 1),
2313 't' => substr($currentsetting, 2, 1),
2314 'w' => substr($currentsetting, 3, 1),
2315 'r' => substr($currentsetting, 4, 1),
2316 'f' => substr($currentsetting, 5, 1),
2317 's' => substr($currentsetting, 6, 1));
2323 function output_html() {
2325 if ($this->get_setting() === NULL) {
2326 $currentsetting = $this->defaultsetting
;
2328 $currentsetting = $this->get_setting();
2331 // rewrite for simplicity
2332 $currentsetting = $currentsetting['u'] . $currentsetting['m'] . $currentsetting['t'] . $currentsetting['w'] .
2333 $currentsetting['r'] . $currentsetting['f'] . $currentsetting['s'];
2335 $return = '<table><tr><td><div style="text-align:center"> ' . get_string('sunday', 'calendar') . ' </div></td><td><div style="text-align:center"> ' .
2336 get_string('monday', 'calendar') . ' </div></td><td><div style="text-align:center"> ' . get_string('tuesday', 'calendar') . ' </div></td><td><div style="text-align:center"> ' .
2337 get_string('wednesday', 'calendar') . ' </div></td><td><div style="text-align:center"> ' . get_string('thursday', 'calendar') . ' </div></td><td><div style="text-align:center"> ' .
2338 get_string('friday', 'calendar') . ' </div></td><td><div style="text-align:center"> ' . get_string('saturday', 'calendar') . ' </div></td></tr><tr>' .
2339 '<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>' .
2340 '<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>' .
2341 '<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>' .
2342 '<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>' .
2343 '<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>' .
2344 '<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>' .
2345 '<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>' .
2348 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
2352 // 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
2353 // admin_settingpage (note that admin_settingpage only calls write_setting with the data that matches $this->name... so if we have multiple form fields,
2354 // they MUST go into an array named $this->name, or else we won't receive them here
2355 function write_setting($data) {
2357 $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
2358 if (!empty($data)) {
2359 foreach($data as $key => $value) {
2360 if ($value == '1') {
2361 $result[strpos($week, $key)] = 1;
2365 return (backup_set_config($this->name
, implode('',$result)) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2369 class admin_setting_special_debug
extends admin_setting_configselect
{
2371 function admin_setting_special_debug() {
2373 $visiblename = get_string('debug', 'admin');
2374 $description = get_string('configdebug', 'admin');
2375 $choices = array( DEBUG_NONE
=> get_string('debugnone', 'admin'),
2376 DEBUG_MINIMAL
=> get_string('debugminimal', 'admin'),
2377 DEBUG_NORMAL
=> get_string('debugnormal', 'admin'),
2378 DEBUG_ALL
=> get_string('debugall', 'admin'),
2379 DEBUG_DEVELOPER
=> get_string('debugdeveloper', 'admin')
2381 parent
::admin_setting_configselect($name, $visiblename, $description, '', $choices);
2384 function get_setting() {
2386 if (isset($CFG->debug
)) {
2393 function write_setting($data) {
2394 return (set_config($this->name
,$data) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2400 class admin_setting_special_calendar_weekend
extends admin_setting
{
2402 function admin_setting_special_calendar_weekend() {
2403 $name = 'calendar_weekend';
2404 $visiblename = get_string('calendar_weekend', 'admin');
2405 $description = get_string('helpweekenddays', 'admin');
2406 $default = array ('0', '6'); // Saturdays and Sundays
2407 parent
::admin_setting($name, $visiblename, $description, $default);
2410 function get_setting() {
2412 return isset($CFG->{$this->name
}) ?
$CFG->{$this->name
} : 0;
2415 function write_setting($data) {
2417 if (!empty($data)) {
2418 foreach($data as $index) {
2419 $result |
= 1 << $index;
2422 return (set_config($this->name
, $result) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2425 function output_html() {
2426 if ($this->get_setting() === NULL) {
2427 $currentsetting = $this->defaultsetting
;
2429 $currentsetting = $this->get_setting();
2432 // The order matters very much because of the implied numeric keys
2433 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
2434 $return = '<table><thead><tr>';
2435 foreach($days as $index => $day) {
2436 $return .= '<td><label for="id_s_'.$this->name
.$index.'">'.get_string($day, 'calendar').'</label></td>';
2438 $return .= '</tr></thead><tbody><tr>';
2439 foreach($days as $index => $day) {
2440 $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>';
2442 $return .= '</tr></tbody></table>';
2444 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
2451 * this is used in config->appearance->gradeconfig
2453 class admin_setting_special_gradebookroles
extends admin_setting
{
2455 function admin_setting_special_gradebookroles() {
2456 $name = 'gradebookroles';
2457 $visiblename = get_string('gradebookroles', 'admin');
2458 $description = get_string('configgradebookroles', 'admin');
2459 $default = array(5=>'1'); // The student role in a default install
2460 parent
::admin_setting($name, $visiblename, $description, $default);
2463 function get_setting() {
2465 if (!empty($CFG->{$this->name
})) {
2466 $result = explode(',', $CFG->{$this->name
});
2467 foreach ($result as $roleid) {
2468 $array[$roleid] = 1;
2476 function write_setting($data) {
2477 if (!empty($data)) {
2479 foreach ($data as $key => $value) {
2484 return set_config($this->name
, rtrim($str, ","))?
'':get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
2486 return set_config($this->name
, '')?
'':get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
2490 function output_html() {
2492 if ($this->get_setting() === NULL) {
2493 $currentsetting = $this->defaultsetting
;
2495 $currentsetting = $this->get_setting();
2497 // from to process which roles to display
2498 if ($roles = get_records('role')) {
2499 $return = '<div class="form-group">';
2501 foreach ($roles as $roleid=>$role) {
2502 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
2503 $checked = ' checked="checked"';
2510 $return .= '<br />';
2512 $return .= '<input type="checkbox" name="s_'.$this->name
.'['.$roleid.']" value="1"'.$checked.' /> '.format_string($role->name
);
2514 $return .= '</div>';
2517 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
2524 * this is used in config->appearance->coursemanager
2525 * (which roles to show on course decription page)
2527 class admin_setting_special_coursemanager
extends admin_setting
{
2529 function admin_setting_special_coursemanager() {
2530 $name = 'coursemanager';
2531 $visiblename = get_string('coursemanager', 'admin');
2532 $description = get_string('configcoursemanager', 'admin');
2533 $default = array(3=>'1'); // The teahcer role in a default install
2534 parent
::admin_setting($name, $visiblename, $description, $default);
2537 function get_setting() {
2540 if (!empty($CFG->{$this->name
})) {
2541 $result = explode(',', $CFG->{$this->name
});
2542 foreach ($result as $roleid) {
2543 $array[$roleid] = 1;
2546 } else if (isset($CFG->{$this->name
})) {
2553 function write_setting($data) {
2555 if (!empty($data)) {
2557 foreach ($data as $key => $value) {
2562 return set_config($this->name
, rtrim($str, ","))?
'':get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
2564 return set_config($this->name
, '')?
'':get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
2568 function output_html() {
2570 if ($this->get_setting() === NULL) {
2571 $currentsetting = $this->defaultsetting
;
2573 $currentsetting = $this->get_setting();
2575 // from to process which roles to display
2576 if ($roles = get_records_select('role', '', 'sortorder')) {
2577 $return = '<div class="form-group">';
2579 foreach ($roles as $roleid=>$role) {
2580 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
2581 $checked = 'checked="checked"';
2588 $return .= '<br />';
2590 $return .= '<input type="checkbox" name="s_'.$this->name
.'['.$roleid.']" value="1" '.$checked.' /> '.$role->name
;
2592 $return .= '</div>';
2594 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
2599 * this is used in config->courses->gradeexports
2600 * (which roles to show on course decription page)
2602 class admin_setting_special_gradeexport
extends admin_setting
{
2604 function admin_setting_special_gradeexport() {
2605 $name = 'gradeexport';
2606 $visiblename = get_string('gradeexport', 'admin');
2607 $description = get_string('configgradeexport', 'admin');
2608 $default = array(3=>'1'); // The teahcer role in a default install
2609 parent
::admin_setting($name, $visiblename, $description, $default);
2612 function get_setting() {
2615 if (!empty($CFG->{$this->name
})) {
2616 $result = explode(',', $CFG->{$this->name
});
2617 foreach ($result as $plugin) {
2618 $array[$plugin] = 1;
2621 } else if (isset($CFG->{$this->name
})) {
2628 function write_setting($data) {
2630 if (!empty($data)) {
2632 foreach ($data as $key => $value) {
2637 return set_config($this->name
, rtrim($str, ","))?
'':get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
2639 return set_config($this->name
, '')?
'':get_string('errorsetting', 'admin') . $this->visiblename
. '<br />';
2643 function output_html() {
2645 if ($this->get_setting() === NULL) {
2646 $currentsetting = $this->defaultsetting
;
2648 $currentsetting = $this->get_setting();
2650 // from to process which roles to display
2651 if ($exports = get_list_of_plugins('grade/export')) {
2652 $return = '<div class="form-group">';
2654 foreach ($exports as $export) {
2655 if (is_array($currentsetting) && in_array($export, array_keys($currentsetting))) {
2656 $checked = 'checked="checked"';
2663 $return .= '<br />';
2665 $return .= '<input type="checkbox" name="s_'.$this->name
.'['.$export.']" value="1" '.$checked.' /> '.$export;
2667 $return .= '</div>';
2669 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
, false);
2676 class admin_setting_special_perfdebug
extends admin_setting_configcheckbox
{
2678 function admin_setting_special_perfdebug() {
2679 $name = 'perfdebug';
2680 $visiblename = get_string('perfdebug', 'admin');
2681 $description = get_string('configperfdebug', 'admin');
2682 parent
::admin_setting_configcheckbox($name, $visiblename, $description, '');
2685 function write_setting($data) {
2688 return (set_config($this->name
,15) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2690 return (set_config($this->name
,7) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2694 function output_html() {
2696 if ($this->get_setting() === NULL) {
2697 $currentsetting = $this->defaultsetting
;
2699 $currentsetting = $this->get_setting();
2702 $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name
.'" name="s_'. $this->name
.'" value="1" ' . ($currentsetting == 15 ?
'checked="checked"' : '') . ' />';
2703 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
);
2708 class admin_setting_special_debugdisplay
extends admin_setting_configcheckbox
{
2710 function admin_setting_special_debugdisplay() {
2711 $name = 'debugdisplay';
2712 $visiblename = get_string('debugdisplay', 'admin');
2713 $description = get_string('configdebugdisplay', 'admin');
2714 $default = ini_get('display_errors');
2715 parent
::admin_setting_configcheckbox($name, $visiblename, $description, $default);
2718 function write_setting($data) {
2721 return (set_config($this->name
,1) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2723 return (set_config($this->name
,0) ?
'' : get_string('errorsetting', 'admin') . $this->visiblename
. '<br />');
2727 function output_html() {
2729 if ($this->get_setting() === NULL) {
2730 $currentsetting = $this->defaultsetting
;
2732 $currentsetting = $this->get_setting();
2735 $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name
.'" name="s_'. $this->name
.'" value="1" ' . ($currentsetting == 1 ?
'checked="checked"' : '') . ' />';
2736 return format_admin_setting($this->name
, $this->visiblename
, $return, $this->description
);
2742 // Code for a function that helps externalpages print proper headers and footers
2743 // N.B.: THIS FUNCTION HANDLES AUTHENTICATION
2744 function admin_externalpage_setup($section) {
2746 global $CFG, $PAGE, $USER;
2748 $adminroot = admin_get_root();
2750 require_once($CFG->libdir
. '/blocklib.php');
2751 require_once($CFG->dirroot
. '/'.$CFG->admin
.'/pagelib.php');
2753 page_map_class(PAGE_ADMIN
, 'page_admin');
2755 $PAGE = page_create_object(PAGE_ADMIN
, 0); // there must be any constant id number
2757 $PAGE->init_extra($section); // hack alert!
2759 $root = $adminroot->locate($PAGE->section
);
2761 if ($site = get_site()) {
2764 redirect($CFG->wwwroot
. '/'.$CFG->admin
.'/index.php');
2768 if (!is_a($root, 'admin_externalpage')) {
2769 error(get_string('sectionerror','admin'));
2773 // this eliminates our need to authenticate on the actual pages
2774 if (!($root->check_access())) {
2775 error(get_string('accessdenied', 'admin'));
2779 $adminediting = optional_param('adminedit', -1, PARAM_BOOL
);
2781 if (!isset($USER->adminediting
)) {
2782 $USER->adminediting
= false;
2785 if ($PAGE->user_allowed_editing()) {
2786 if ($adminediting == 1) {
2787 $USER->adminediting
= true;
2788 } elseif ($adminediting == 0) {
2789 $USER->adminediting
= false;
2798 function admin_externalpage_print_header() {
2800 global $CFG, $PAGE, $SITE, $THEME;
2802 if (!empty($THEME->customcorners
)) {
2803 require_once($CFG->dirroot
.'/lib/custom_corners_lib.php');
2806 define('ADMIN_EXT_HEADER_PRINTED', 'true');
2808 if (!empty($SITE->fullname
)) {
2809 $pageblocks = blocks_setup($PAGE);
2811 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH
,
2812 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT
]),
2814 $PAGE->print_header();
2815 echo '<table id="layout-table" summary=""><tr>';
2817 $lt = (empty($THEME->layouttable
)) ?
array('left', 'middle', 'right') : $THEME->layouttable
;
2818 foreach ($lt as $column) {
2820 if ($column == 'middle') break;
2822 foreach ($lt1 as $column) {
2825 echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">';
2826 if (!empty($THEME->customcorners
)) print_custom_corners_start();
2827 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT
);
2828 if (!empty($THEME->customcorners
)) print_custom_corners_end();
2833 echo '<td id="middle-column">';
2834 if (!empty($THEME->customcorners
)) print_custom_corners_start();
2838 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT
)) {
2839 echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">';
2840 if (!empty($THEME->customcorners
)) print_custom_corners_start();
2841 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT
);
2842 if (!empty($THEME->customcorners
)) print_custom_corners_end();
2853 function admin_externalpage_print_footer() {
2855 global $CFG, $PAGE, $SITE, $THEME;
2857 if (!empty($THEME->customcorners
)) {
2858 require_once($CFG->dirroot
.'/lib/custom_corners_lib.php');
2861 define('ADMIN_EXT_FOOTER_PRINTED', 'true');
2863 if (!empty($SITE->fullname
)) {
2864 $pageblocks = blocks_setup($PAGE);
2865 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH
,
2866 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT
]),
2869 $lt = (empty($THEME->layouttable
)) ?
array('left', 'middle', 'right') : $THEME->layouttable
;
2870 foreach ($lt as $column) {
2871 if ($column != 'middle') {
2873 } else if ($column == 'middle') {
2877 foreach ($lt as $column) {
2880 echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">';
2881 if (!empty($THEME->customcorners
)) print_custom_corners_start();
2882 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT
);
2883 if (!empty($THEME->customcorners
)) print_custom_corners_end();
2888 if (!empty($THEME->customcorners
)) print_custom_corners_end();
2893 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT
)) {
2894 echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">';
2895 if (!empty($THEME->customcorners
)) print_custom_corners_start();
2896 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT
);
2898 if (!empty($THEME->customcorners
)) print_custom_corners_end();
2904 echo '</tr></table>';
2909 function admin_get_root() {
2914 if (!isset($ADMIN)) {
2915 // start the admin tree!
2916 $ADMIN = new admin_category('root', get_string("administration"));
2917 // we process this file first to get categories up and running
2918 include($CFG->dirroot
. '/'.$CFG->admin
.'/settings/top.php');
2920 // now we process all other files in admin/settings to build the
2922 foreach (glob($CFG->dirroot
. '/'.$CFG->admin
.'/settings/*.php') as $file) {
2923 if ($file != $CFG->dirroot
. '/'.$CFG->admin
.'/settings/top.php') {
2924 include_once($file);
2932 /// settings utiliti functions
2934 // n.b. this function unconditionally applies default settings
2935 function apply_default_settings(&$node) {
2939 if (is_a($node, 'admin_category')) {
2940 $entries = array_keys($node->children
);
2941 foreach ($entries as $entry) {
2942 apply_default_settings($node->children
[$entry]);
2947 if (is_a($node, 'admin_settingpage')) {
2948 foreach ($node->settings
as $setting) {
2949 $CFG->{$setting->name
} = $setting->defaultsetting
;
2950 $setting->write_setting($setting->defaultsetting
);
2951 unset($setting); // needed to prevent odd (imho) reference behaviour
2952 // see http://www.php.net/manual/en/language.references.whatdo.php#AEN6399
2961 // n.b. this function unconditionally applies default settings
2962 function apply_default_exception_settings($defaults) {
2966 foreach($defaults as $key => $value) {
2967 $CFG->$key = $value;
2968 set_config($key, $value);
2973 function format_admin_setting($name, $title='', $form='', $description='', $label=true) {
2975 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
2977 $labelfor = 'for = "id_s_'.$name.'"';
2983 '<div class="form-item" id="admin-'.$name.'">'."\n".
2984 '<label '.$labelfor.'>'.$title."\n".
2985 ' <span class="form-shortname">'.$name.'</span>'."\n".
2988 '<div class="description">'.$description.'</div>'."\n".
2996 * Try to upgrade the given language pack (or current language)
2997 * If it doesn't work, fail silently and return false
2999 function upgrade_language_pack($lang='') {
3003 $lang = current_language();
3006 if ($lang == 'en_utf8') {
3007 return true; // Nothing to do
3010 notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
3012 @mkdir
($CFG->dataroot
.'/temp/'); //make it in case it's a fresh install, it might not be there
3013 @mkdir
($CFG->dataroot
.'/lang/');
3015 require_once($CFG->libdir
.'/componentlib.class.php');
3017 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
3018 $status = $cd->install(); //returns ERROR | UPTODATE | INSTALLED
3020 if ($status == INSTALLED
) {
3021 debugging('Downloading successful: '.$lang);
3022 @unlink
($CFG->dataroot
.'/cache/languages');
3031 * Based on find_new_settings{@link ()} in upgradesettings.php
3032 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
3034 * @param string &$node The node at which to start searching.
3035 * @return int Returns 1 if any settings haven't been initialised, 0 if they all have
3037 function any_new_admin_settings(&$node) {
3039 if (is_a($node, 'admin_category')) {
3040 $entries = array_keys($node->children
);
3041 foreach ($entries as $entry) {
3042 if( any_new_admin_settings($node->children
[$entry]) ){
3048 if (is_a($node, 'admin_settingpage')) {
3049 foreach ($node->settings
as $setting) {
3050 if ($setting->get_setting() === NULL) {