Deleting the check_defaults test from 19_STABLE. MDL-14854
[moodle-linuxchix.git] / lib / adminlib.php
blobe38bc3238b865e6bdb991ea37c5e24587a4c4be2
1 <?php
3 /**
4 * adminlib.php - Contains functions that only administrators will ever need to use
6 * @author Martin Dougiamas and many others
7 * @version $Id$
8 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
9 * @package moodlecore
12 function upgrade_main_savepoint($result, $version) {
13 global $CFG;
15 if ($result) {
16 if ($CFG->version >= $version) {
17 // something really wrong is going on in main upgrade script
18 error("Upgrade savepoint: Can not upgrade main version from $CFG->version to $version.");
20 set_config('version', $version);
21 } else {
22 notify ("Upgrade savepoint: Error during main upgrade to version $version");
26 function upgrade_mod_savepoint($result, $version, $type) {
27 //TODO
30 function upgrade_plugin_savepoint($result, $version, $type, $dir) {
31 //TODO
34 function upgrade_backup_savepoint($result, $version) {
35 //TODO
38 function upgrade_blocks_savepoint($result, $version, $type) {
39 //TODO
42 /**
43 * Upgrade plugins
45 * @uses $db
46 * @uses $CFG
47 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
48 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
49 * @param string $return The url to prompt the user to continue to
51 function upgrade_plugins($type, $dir, $return) {
52 global $CFG, $db;
54 /// Let's know if the header has been printed, so the funcion is being called embedded in an outer page
55 $embedded = defined('HEADER_PRINTED');
57 $plugs = get_list_of_plugins($dir);
58 $updated_plugins = false;
59 $strpluginsetup = get_string('pluginsetup');
61 foreach ($plugs as $plug) {
63 $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
65 unset($plugin);
67 if (is_readable($fullplug .'/version.php')) {
68 include_once($fullplug .'/version.php'); // defines $plugin with version etc
69 } else {
70 continue; // Nothing to do.
73 $oldupgrade = false;
74 $newupgrade = false;
75 if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) {
76 include_once($fullplug . '/db/'. $CFG->dbtype . '.php'); // defines old upgrading function
77 $oldupgrade = true;
79 if (is_readable($fullplug . '/db/upgrade.php')) {
80 include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
81 $newupgrade = true;
84 if (!isset($plugin)) {
85 continue;
88 if (!empty($plugin->requires)) {
89 if ($plugin->requires > $CFG->version) {
90 $info = new object();
91 $info->pluginname = $plug;
92 $info->pluginversion = $plugin->version;
93 $info->currentmoodle = $CFG->version;
94 $info->requiremoodle = $plugin->requires;
95 if (!$updated_plugins && !$embedded) {
96 print_header($strpluginsetup, $strpluginsetup,
97 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
98 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
100 upgrade_log_start();
101 notify(get_string('pluginrequirementsnotmet', 'error', $info));
102 $updated_plugins = true;
103 continue;
107 $plugin->name = $plug; // The name MUST match the directory
109 $pluginversion = $type.'_'.$plug.'_version';
111 if (!isset($CFG->$pluginversion)) {
112 set_config($pluginversion, 0);
115 if ($CFG->$pluginversion == $plugin->version) {
116 // do nothing
117 } else if ($CFG->$pluginversion < $plugin->version) {
118 if (!$updated_plugins && !$embedded) {
119 print_header($strpluginsetup, $strpluginsetup,
120 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
121 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
123 $updated_plugins = true;
124 upgrade_log_start();
125 print_heading($dir.'/'. $plugin->name .' plugin needs upgrading');
126 $db->debug = true;
127 @set_time_limit(0); // To allow slow databases to complete the long SQL
129 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
130 /// Both old .sql files and new install.xml are supported
131 /// but we priorize install.xml (XMLDB) if present
132 $status = false;
133 if (file_exists($fullplug . '/db/install.xml')) {
134 $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
135 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
136 $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
137 } else {
138 $status = true;
141 $db->debug = false;
142 /// Continue with the instalation, roles and other stuff
143 if ($status) {
144 /// OK so far, now update the plugins record
145 set_config($pluginversion, $plugin->version);
147 /// Install capabilities
148 if (!update_capabilities($type.'/'.$plug)) {
149 error('Could not set up the capabilities for '.$plugin->name.'!');
151 /// Install events
152 events_update_definition($type.'/'.$plug);
154 /// Run local install function if there is one
155 if (is_readable($fullplug .'/lib.php')) {
156 include_once($fullplug .'/lib.php');
157 $installfunction = $plugin->name.'_install';
158 if (function_exists($installfunction)) {
159 if (! $installfunction() ) {
160 notify('Encountered a problem running install function for '.$module->name.'!');
165 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
166 } else {
167 notify('Installing '. $plugin->name .' FAILED!');
169 } else { // Upgrade existing install
170 /// Run de old and new upgrade functions for the module
171 $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade';
172 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
174 /// First, the old function if exists
175 $oldupgrade_status = true;
176 if ($oldupgrade && function_exists($oldupgrade_function)) {
177 $db->debug = true;
178 $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
179 } else if ($oldupgrade) {
180 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
181 $fullplug . '/db/' . $CFG->dbtype . '.php');
184 /// Then, the new function if exists and the old one was ok
185 $newupgrade_status = true;
186 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
187 $db->debug = true;
188 $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
189 } else if ($newupgrade) {
190 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
191 $fullplug . '/db/upgrade.php');
194 $db->debug=false;
195 /// Now analyze upgrade results
196 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
197 // OK so far, now update the plugins record
198 set_config($pluginversion, $plugin->version);
199 if (!update_capabilities($type.'/'.$plug)) {
200 error('Could not update '.$plugin->name.' capabilities!');
202 events_update_definition($type.'/'.$plug);
203 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
204 } else {
205 notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
208 echo '<hr />';
209 } else {
210 upgrade_log_start();
211 error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
215 upgrade_log_finish();
217 if ($updated_plugins && !$embedded) {
218 print_continue($return);
219 print_footer('none');
220 die;
225 * Find and check all modules and load them up or upgrade them if necessary
227 * @uses $db
228 * @uses $CFG
229 * @param string $return The url to prompt the user to continue to
230 * @todo Finish documenting this function
232 function upgrade_activity_modules($return) {
234 global $CFG, $db;
236 if (!$mods = get_list_of_plugins('mod') ) {
237 error('No modules installed!');
240 $updated_modules = false;
241 $strmodulesetup = get_string('modulesetup');
243 foreach ($mods as $mod) {
245 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
246 continue;
249 $fullmod = $CFG->dirroot .'/mod/'. $mod;
251 unset($module);
253 if ( is_readable($fullmod .'/version.php')) {
254 include_once($fullmod .'/version.php'); // defines $module with version etc
255 } else {
256 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
257 continue;
260 $oldupgrade = false;
261 $newupgrade = false;
262 if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
263 include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function
264 $oldupgrade = true;
266 if ( is_readable($fullmod . '/db/upgrade.php')) {
267 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
268 $newupgrade = true;
271 if (!isset($module)) {
272 continue;
275 if (!empty($module->requires)) {
276 if ($module->requires > $CFG->version) {
277 $info = new object();
278 $info->modulename = $mod;
279 $info->moduleversion = $module->version;
280 $info->currentmoodle = $CFG->version;
281 $info->requiremoodle = $module->requires;
282 if (!$updated_modules) {
283 print_header($strmodulesetup, $strmodulesetup,
284 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
285 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
287 upgrade_log_start();
288 notify(get_string('modulerequirementsnotmet', 'error', $info));
289 $updated_modules = true;
290 continue;
294 $module->name = $mod; // The name MUST match the directory
296 include_once($fullmod.'/lib.php'); // defines upgrading and/or installing functions
298 if ($currmodule = get_record('modules', 'name', $module->name)) {
299 if ($currmodule->version == $module->version) {
300 // do nothing
301 } else if ($currmodule->version < $module->version) {
302 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
303 if (!$oldupgrade && !$newupgrade) {
304 notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' .
305 $fullmod . '/db/upgrade.php were not readable');
306 continue;
308 if (!$updated_modules) {
309 print_header($strmodulesetup, $strmodulesetup,
310 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
311 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
313 upgrade_log_start();
314 print_heading($module->name .' module needs upgrading');
316 /// Run de old and new upgrade functions for the module
317 $oldupgrade_function = $module->name . '_upgrade';
318 $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
320 /// First, the old function if exists
321 $oldupgrade_status = true;
322 if ($oldupgrade && function_exists($oldupgrade_function)) {
323 $db->debug = true;
324 $oldupgrade_status = $oldupgrade_function($currmodule->version, $module);
325 if (!$oldupgrade_status) {
326 notify ('Upgrade function ' . $oldupgrade_function .
327 ' did not complete successfully.');
329 } else if ($oldupgrade) {
330 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
331 $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php');
334 /// Then, the new function if exists and the old one was ok
335 $newupgrade_status = true;
336 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
337 $db->debug = true;
338 $newupgrade_status = $newupgrade_function($currmodule->version, $module);
339 } else if ($newupgrade && $oldupgrade_status) {
340 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
341 $mod . ': ' . $fullmod . '/db/upgrade.php');
344 $db->debug=false;
345 /// Now analyze upgrade results
346 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
347 // OK so far, now update the modules record
348 $module->id = $currmodule->id;
349 if (! update_record('modules', $module)) {
350 error('Could not update '. $module->name .' record in modules table!');
352 remove_dir($CFG->dataroot . '/cache', true); // flush cache
353 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
354 echo '<hr />';
355 } else {
356 notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
359 /// Update the capabilities table?
360 if (!update_capabilities('mod/'.$module->name)) {
361 error('Could not update '.$module->name.' capabilities!');
363 events_update_definition('mod/'.$module->name);
365 $updated_modules = true;
367 } else {
368 upgrade_log_start();
369 error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
372 } else { // module not installed yet, so install it
373 if (!$updated_modules) {
374 print_header($strmodulesetup, $strmodulesetup,
375 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
376 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
378 upgrade_log_start();
379 print_heading($module->name);
380 $updated_modules = true;
381 $db->debug = true;
382 @set_time_limit(0); // To allow slow databases to complete the long SQL
384 /// Both old .sql files and new install.xml are supported
385 /// but we priorize install.xml (XMLDB) if present
386 if (file_exists($fullmod . '/db/install.xml')) {
387 $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
388 } else {
389 $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method
392 $db->debug = false;
394 /// Continue with the installation, roles and other stuff
395 if ($status) {
396 if ($module->id = insert_record('modules', $module)) {
398 /// Capabilities
399 if (!update_capabilities('mod/'.$module->name)) {
400 error('Could not set up the capabilities for '.$module->name.'!');
403 /// Events
404 events_update_definition('mod/'.$module->name);
406 /// Run local install function if there is one
407 $installfunction = $module->name.'_install';
408 if (function_exists($installfunction)) {
409 if (! $installfunction() ) {
410 notify('Encountered a problem running install function for '.$module->name.'!');
414 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
415 echo '<hr />';
416 } else {
417 error($module->name .' module could not be added to the module list!');
419 } else {
420 error($module->name .' tables could NOT be set up successfully!');
424 /// Check submodules of this module if necessary
426 $submoduleupgrade = $module->name.'_upgrade_submodules';
427 if (function_exists($submoduleupgrade)) {
428 $submoduleupgrade();
432 /// Run any defaults or final code that is necessary for this module
434 if ( is_readable($fullmod .'/defaults.php')) {
435 // Insert default values for any important configuration variables
436 unset($defaults);
437 include($fullmod .'/defaults.php'); // include here means execute, not library include
438 if (!empty($defaults)) {
439 foreach ($defaults as $name => $value) {
440 if (!isset($CFG->$name)) {
441 set_config($name, $value);
448 upgrade_log_finish(); // finish logging if started
450 if ($updated_modules) {
451 print_continue($return);
452 print_footer('none');
453 die;
458 * Try to obtain or release the cron lock.
460 * @param string $name name of lock
461 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionaly
462 * @param bool $ignorecurrent ignore current lock state, usually entend previous lock
463 * @return bool true if lock obtained
465 function set_cron_lock($name, $until, $ignorecurrent=false) {
466 if (empty($name)) {
467 debugging("Tried to get a cron lock for a null fieldname");
468 return false;
471 // remove lock by force == remove from config table
472 if (is_null($until)) {
473 set_config($name, null);
474 return true;
477 if (!$ignorecurrent) {
478 // read value from db - other processes might have changed it
479 $value = get_field('config', 'value', 'name', $name);
481 if ($value and $value > time()) {
482 //lock active
483 return false;
487 set_config($name, $until);
488 return true;
491 function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
492 static $starttime;
493 static $lasttime;
495 if ($total < 2) { // No need to show anything
496 return;
499 if (empty($starttime)) {
500 $starttime = $lasttime = time();
501 $lasttime = $starttime - $updatetime;
502 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
503 echo '<div id="bar'.$total.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
504 echo '<div id="slider'.$total.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
505 echo '</div>';
506 echo '<div id="text'.$total.'" align="center" style="width:500px;"></div>';
507 echo '</td></tr></table>';
508 echo '</div>';
511 $now = time();
513 if ($done && (($now - $lasttime) >= $updatetime)) {
514 $elapsedtime = $now - $starttime;
515 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
516 $percentage = round((float)$done / (float)$total, 2);
517 $width = (int)(500 * $percentage);
519 if ($projectedtime > 10) {
520 $projectedtext = ' Ending: '.format_time($projectedtime);
521 } else {
522 $projectedtext = '';
525 echo '<script>';
526 echo 'document.getElementById("text'.$total.'").innerHTML = "'.addslashes($donetext).' ('.$done.'/'.$total.') '.$projectedtext.'";'."\n";
527 echo 'document.getElementById("slider'.$total.'").style.width = \''.$width.'px\';'."\n";
528 echo '</script>';
530 $lasttime = $now;
531 sleep($sleeptime);
535 function upgrade_get_javascript() {
536 global $CFG;
538 if (!empty($_SESSION['installautopilot'])) {
539 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
540 } else {
541 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
543 $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>';
545 return $linktoscrolltoerrors;
548 function create_admin_user() {
549 global $CFG, $USER;
551 if (empty($CFG->rolesactive)) { // No admin user yet.
553 $user = new object();
554 $user->auth = 'manual';
555 $user->firstname = get_string('admin');
556 $user->lastname = get_string('user');
557 $user->username = 'admin';
558 $user->password = hash_internal_user_password('admin');
559 $user->email = 'root@localhost';
560 $user->confirmed = 1;
561 $user->mnethostid = $CFG->mnet_localhost_id;
562 $user->lang = $CFG->lang;
563 $user->maildisplay = 1;
564 $user->timemodified = time();
566 if (!$user->id = insert_record('user', $user)) {
567 error('SERIOUS ERROR: Could not create admin user record !!!');
570 if (!$user = get_record('user', 'id', $user->id)) { // Double check.
571 error('User ID was incorrect (can\'t find it)');
574 // Assign the default admin roles to the new user.
575 if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW)) {
576 error('No admin role could be found');
578 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
579 foreach ($adminroles as $adminrole) {
580 role_assign($adminrole->id, $user->id, 0, $sitecontext->id);
583 set_config('rolesactive', 1);
585 // Log the user in.
586 $USER = get_complete_user_data('username', 'admin');
587 $USER->newadminuser = 1;
588 load_all_capabilities();
590 redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id"); // Edit thyself
591 } else {
592 error('Can not create admin!');
596 ////////////////////////////////////////////////
597 /// upgrade logging functions
598 ////////////////////////////////////////////////
600 $upgradeloghandle = false;
601 $upgradelogbuffer = '';
602 // I did not find out how to use static variable in callback function,
603 // the problem was that I could not flush the static buffer :-(
604 global $upgradeloghandle, $upgradelogbuffer;
607 * Check if upgrade is already running.
609 * If anything goes wrong due to missing call to upgrade_log_finish()
610 * just restart the browser.
612 * @param string warning message indicating upgrade is already running
613 * @param int page reload timeout
615 function upgrade_check_running($message, $timeout) {
616 if (!empty($_SESSION['upgraderunning'])) {
617 print_header();
618 redirect(me(), $message, $timeout);
623 * Start logging of output into file (if not disabled) and
624 * prevent aborting and concurrent execution of upgrade script.
626 * Please note that you can not write into session variables after calling this function!
628 * This function may be called repeatedly.
630 function upgrade_log_start() {
631 global $CFG, $upgradeloghandle;
633 if (!empty($_SESSION['upgraderunning'])) {
634 return; // logging already started
637 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
638 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
639 if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
640 session_write_close(); // from now on user can reload page - will be displayed warning
642 make_upload_directory('upgradelogs');
643 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
644 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
648 * Terminate logging of output, flush all data, allow script aborting
649 * and reopen session for writing. Function error() does terminate the logging too.
651 * Please make sure that each upgrade_log_start() is properly terminated by
652 * this function or error().
654 * This function may be called repeatedly.
656 function upgrade_log_finish() {
657 global $CFG, $upgradeloghandle, $upgradelogbuffer;
659 if (empty($_SESSION['upgraderunning'])) {
660 return; // logging already terminated
663 @ob_end_flush();
664 if ($upgradelogbuffer !== '') {
665 @fwrite($upgradeloghandle, $upgradelogbuffer);
666 $upgradelogbuffer = '';
668 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
669 @fclose($upgradeloghandle);
670 $upgradeloghandle = false;
672 if (empty($CFG->dbsessions)) {
673 @session_start(); // ignore header errors, we only need to reopen session
675 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
676 if (connection_aborted()) {
677 die;
679 @ignore_user_abort(false);
683 * Callback function for logging into files. Not more than one file is created per minute,
684 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
686 * This function must not output any characters or throw warnigns and errors!
688 function upgrade_log_callback($string) {
689 global $CFG, $upgradeloghandle, $upgradelogbuffer;
691 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
692 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
693 $upgradelogbuffer .= $string;
694 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
695 @fwrite($upgradeloghandle, $upgradelogbuffer);
696 $upgradelogbuffer = '';
698 } else {
699 $upgradeloghandle = 'error';
702 return $string;
706 * Try to verify that dataroot is not accessible from web.
707 * It is not 100% correct but might help to reduce number of vulnerable sites.
709 * Protection from httpd.conf and .htaccess is not detected properly.
711 function is_dataroot_insecure() {
712 global $CFG;
714 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
716 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
717 $rp = strrev(trim($rp, '/'));
718 $rp = explode('/', $rp);
719 foreach($rp as $r) {
720 if (strpos($siteroot, '/'.$r.'/') === 0) {
721 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
722 } else {
723 break; // probably alias root
727 $siteroot = strrev($siteroot);
728 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
730 if (strpos($dataroot, $siteroot) === 0) {
731 return true;
733 return false;
736 /// =============================================================================================================
737 /// administration tree classes and functions
740 // n.b. documentation is still in progress for this code
742 /// INTRODUCTION
744 /// This file performs the following tasks:
745 /// -it defines the necessary objects and interfaces to build the Moodle
746 /// admin hierarchy
747 /// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
748 /// and admin_externalpage_print_footer() functions used on admin pages
750 /// ADMIN_SETTING OBJECTS
752 /// Moodle settings are represented by objects that inherit from the admin_setting
753 /// class. These objects encapsulate how to read a setting, how to write a new value
754 /// to a setting, and how to appropriately display the HTML to modify the setting.
756 /// ADMIN_SETTINGPAGE OBJECTS
758 /// The admin_setting objects are then grouped into admin_settingpages. The latter
759 /// appear in the Moodle admin tree block. All interaction with admin_settingpage
760 /// objects is handled by the admin/settings.php file.
762 /// ADMIN_EXTERNALPAGE OBJECTS
764 /// There are some settings in Moodle that are too complex to (efficiently) handle
765 /// with admin_settingpages. (Consider, for example, user management and displaying
766 /// lists of users.) In this case, we use the admin_externalpage object. This object
767 /// places a link to an external PHP file in the admin tree block.
769 /// If you're using an admin_externalpage object for some settings, you can take
770 /// advantage of the admin_externalpage_* functions. For example, suppose you wanted
771 /// to add a foo.php file into admin. First off, you add the following line to
772 /// admin/settings/first.php (at the end of the file) or to some other file in
773 /// admin/settings:
775 /// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
776 /// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
778 /// Next, in foo.php, your file structure would resemble the following:
780 /// require_once('.../config.php');
781 /// require_once($CFG->libdir.'/adminlib.php');
782 /// admin_externalpage_setup('foo');
783 /// // functionality like processing form submissions goes here
784 /// admin_externalpage_print_header();
785 /// // your HTML goes here
786 /// admin_externalpage_print_footer();
788 /// The admin_externalpage_setup() function call ensures the user is logged in,
789 /// and makes sure that they have the proper role permission to access the page.
791 /// The admin_externalpage_print_header() function prints the header (it figures
792 /// out what category and subcategories the page is classified under) and ensures
793 /// that you're using the admin pagelib (which provides the admin tree block and
794 /// the admin bookmarks block).
796 /// The admin_externalpage_print_footer() function properly closes the tables
797 /// opened up by the admin_externalpage_print_header() function and prints the
798 /// standard Moodle footer.
800 /// ADMIN_CATEGORY OBJECTS
802 /// Above and beyond all this, we have admin_category objects. These objects
803 /// appear as folders in the admin tree block. They contain admin_settingpage's,
804 /// admin_externalpage's, and other admin_category's.
806 /// OTHER NOTES
808 /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
809 /// from part_of_admin_tree (a pseudointerface). This interface insists that
810 /// a class has a check_access method for access permissions, a locate method
811 /// used to find a specific node in the admin tree and find parent path.
813 /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
814 /// interface ensures that the class implements a recursive add function which
815 /// accepts a part_of_admin_tree object and searches for the proper place to
816 /// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
818 /// Please note that the $this->name field of any part_of_admin_tree must be
819 /// UNIQUE throughout the ENTIRE admin tree.
821 /// The $this->name field of an admin_setting object (which is *not* part_of_
822 /// admin_tree) must be unique on the respective admin_settingpage where it is
823 /// used.
826 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
829 * Pseudointerface for anything appearing in the admin tree
831 * The pseudointerface that is implemented by anything that appears in the admin tree
832 * block. It forces inheriting classes to define a method for checking user permissions
833 * and methods for finding something in the admin tree.
835 * @author Vincenzo K. Marcovecchio
836 * @package admin
838 class part_of_admin_tree {
841 * Finds a named part_of_admin_tree.
843 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
844 * and not parentable_part_of_admin_tree, then this function should only check if
845 * $this->name matches $name. If it does, it should return a reference to $this,
846 * otherwise, it should return a reference to NULL.
848 * If a class inherits parentable_part_of_admin_tree, this method should be called
849 * recursively on all child objects (assuming, of course, the parent object's name
850 * doesn't match the search criterion).
852 * @param string $name The internal name of the part_of_admin_tree we're searching for.
853 * @return mixed An object reference or a NULL reference.
855 function &locate($name) {
856 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
857 return;
861 * Removes named part_of_admin_tree.
863 * @param string $name The internal name of the part_of_admin_tree we want to remove.
864 * @return bool success.
866 function prune($name) {
867 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
868 return;
872 * Search using query
873 * @param strin query
874 * @return mixed array-object structure of found settings and pages
876 function search($query) {
877 trigger_error('Admin class does not implement method <strong>search()</strong>', E_USER_WARNING);
878 return;
882 * Verifies current user's access to this part_of_admin_tree.
884 * Used to check if the current user has access to this part of the admin tree or
885 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
886 * then this method is usually just a call to has_capability() in the site context.
888 * If a class inherits parentable_part_of_admin_tree, this method should return the
889 * logical OR of the return of check_access() on all child objects.
891 * @return bool True if the user has access, false if she doesn't.
893 function check_access() {
894 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
895 return;
899 * Mostly usefull for removing of some parts of the tree in admin tree block.
901 * @return True is hidden from normal list view
903 function is_hidden() {
904 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
905 return;
910 * Pseudointerface implemented by any part_of_admin_tree that has children.
912 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
913 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
914 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
915 * include an add method for adding other part_of_admin_tree objects as children.
917 * @author Vincenzo K. Marcovecchio
918 * @package admin
920 class parentable_part_of_admin_tree extends part_of_admin_tree {
923 * Adds a part_of_admin_tree object to the admin tree.
925 * Used to add a part_of_admin_tree object to this object or a child of this
926 * object. $something should only be added if $destinationname matches
927 * $this->name. If it doesn't, add should be called on child objects that are
928 * also parentable_part_of_admin_tree's.
930 * @param string $destinationname The internal name of the new parent for $something.
931 * @param part_of_admin_tree &$something The object to be added.
932 * @return bool True on success, false on failure.
934 function add($destinationname, $something) {
935 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
936 return;
942 * The object used to represent folders (a.k.a. categories) in the admin tree block.
944 * Each admin_category object contains a number of part_of_admin_tree objects.
946 * @author Vincenzo K. Marcovecchio
947 * @package admin
949 class admin_category extends parentable_part_of_admin_tree {
952 * @var mixed An array of part_of_admin_tree objects that are this object's children
954 var $children;
957 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
959 var $name;
962 * @var string The displayed name for this category. Usually obtained through get_string()
964 var $visiblename;
967 * @var bool Should this category be hidden in admin tree block?
969 var $hidden;
972 * paths
974 var $path;
975 var $visiblepath;
978 * Constructor for an empty admin category
980 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
981 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
982 * @param bool $hidden hide category in admin tree block
984 function admin_category($name, $visiblename, $hidden=false) {
985 $this->children = array();
986 $this->name = $name;
987 $this->visiblename = $visiblename;
988 $this->hidden = $hidden;
992 * Returns a reference to the part_of_admin_tree object with internal name $name.
994 * @param string $name The internal name of the object we want.
995 * @param bool $findpath initialize path and visiblepath arrays
996 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
998 function &locate($name, $findpath=false) {
999 if ($this->name == $name) {
1000 if ($findpath) {
1001 $this->visiblepath[] = $this->visiblename;
1002 $this->path[] = $this->name;
1004 return $this;
1007 $return = NULL;
1008 foreach($this->children as $childid=>$unused) {
1009 if ($return =& $this->children[$childid]->locate($name, $findpath)) {
1010 break;
1014 if (!is_null($return) and $findpath) {
1015 $return->visiblepath[] = $this->visiblename;
1016 $return->path[] = $this->name;
1019 return $return;
1023 * Search using query
1024 * @param strin query
1025 * @return mixed array-object structure of found settings and pages
1027 function search($query) {
1028 $result = array();
1029 foreach ($this->children as $child) {
1030 $subsearch = $child->search($query);
1031 if (!is_array($subsearch)) {
1032 debugging('Incorrect search result from '.$child->name);
1033 continue;
1035 $result = array_merge($result, $subsearch);
1037 return $result;
1041 * Removes part_of_admin_tree object with internal name $name.
1043 * @param string $name The internal name of the object we want to remove.
1044 * @return bool success
1046 function prune($name) {
1048 if ($this->name == $name) {
1049 return false; //can not remove itself
1052 foreach($this->children as $precedence => $child) {
1053 if ($child->name == $name) {
1054 // found it!
1055 unset($this->children[$precedence]);
1056 return true;
1058 if ($this->children[$precedence]->prune($name)) {
1059 return true;
1062 return false;
1066 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1068 * @param string $destinationame The internal name of the immediate parent that we want for $something.
1069 * @param mixed $something A part_of_admin_tree or setting instanceto be added.
1070 * @return bool True if successfully added, false if $something can not be added.
1072 function add($parentname, $something) {
1073 $parent =& $this->locate($parentname);
1074 if (is_null($parent)) {
1075 debugging('parent does not exist!');
1076 return false;
1079 if (is_a($something, 'part_of_admin_tree')) {
1080 if (!is_a($parent, 'parentable_part_of_admin_tree')) {
1081 debugging('error - parts of tree can be inserted only into parentable parts');
1082 return false;
1084 $parent->children[] = $something;
1085 return true;
1087 } else {
1088 debugging('error - can not add this element');
1089 return false;
1095 * Checks if the user has access to anything in this category.
1097 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1099 function check_access() {
1100 foreach ($this->children as $child) {
1101 if ($child->check_access()) {
1102 return true;
1105 return false;
1109 * Is this category hidden in admin tree block?
1111 * @return bool True if hidden
1113 function is_hidden() {
1114 return $this->hidden;
1118 class admin_root extends admin_category {
1120 * list of errors
1122 var $errors;
1125 * search query
1127 var $search;
1130 * full tree flag - true means all settings required, false onlypages required
1132 var $fulltree;
1135 function admin_root() {
1136 parent::admin_category('root', get_string('administration'), false);
1137 $this->errors = array();
1138 $this->search = '';
1139 $this->fulltree = true;
1144 * Links external PHP pages into the admin tree.
1146 * See detailed usage example at the top of this document (adminlib.php)
1148 * @author Vincenzo K. Marcovecchio
1149 * @package admin
1151 class admin_externalpage extends part_of_admin_tree {
1154 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1156 var $name;
1159 * @var string The displayed name for this external page. Usually obtained through get_string().
1161 var $visiblename;
1164 * @var string The external URL that we should link to when someone requests this external page.
1166 var $url;
1169 * @var string The role capability/permission a user must have to access this external page.
1171 var $req_capability;
1174 * @var object The context in which capability/permission should be checked, default is site context.
1176 var $context;
1179 * @var bool hidden in admin tree block.
1181 var $hidden;
1184 * visible path
1186 var $path;
1187 var $visiblepath;
1190 * Constructor for adding an external page into the admin tree.
1192 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1193 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1194 * @param string $url The external URL that we should link to when someone requests this external page.
1195 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1197 function admin_externalpage($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1198 $this->name = $name;
1199 $this->visiblename = $visiblename;
1200 $this->url = $url;
1201 if (is_array($req_capability)) {
1202 $this->req_capability = $req_capability;
1203 } else {
1204 $this->req_capability = array($req_capability);
1206 $this->hidden = $hidden;
1207 $this->context = $context;
1211 * Returns a reference to the part_of_admin_tree object with internal name $name.
1213 * @param string $name The internal name of the object we want.
1214 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1216 function &locate($name, $findpath=false) {
1217 if ($this->name == $name) {
1218 if ($findpath) {
1219 $this->visiblepath = array($this->visiblename);
1220 $this->path = array($this->name);
1222 return $this;
1223 } else {
1224 $return = NULL;
1225 return $return;
1229 function prune($name) {
1230 return false;
1234 * Search using query
1235 * @param strin query
1236 * @return mixed array-object structure of found settings and pages
1238 function search($query) {
1239 $textlib = textlib_get_instance();
1241 $found = false;
1242 if (strpos(strtolower($this->name), $query) !== false) {
1243 $found = true;
1244 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1245 $found = true;
1247 if ($found) {
1248 $result = new object();
1249 $result->page = $this;
1250 $result->settings = array();
1251 return array($this->name => $result);
1252 } else {
1253 return array();
1258 * Determines if the current user has access to this external page based on $this->req_capability.
1259 * @return bool True if user has access, false otherwise.
1261 function check_access() {
1262 if (!get_site()) {
1263 return true; // no access check before site is fully set up
1265 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1266 foreach($this->req_capability as $cap) {
1267 if (has_capability($cap, $context)) {
1268 return true;
1271 return false;
1275 * Is this external page hidden in admin tree block?
1277 * @return bool True if hidden
1279 function is_hidden() {
1280 return $this->hidden;
1286 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1288 * @author Vincenzo K. Marcovecchio
1289 * @package admin
1291 class admin_settingpage extends part_of_admin_tree {
1294 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1296 var $name;
1299 * @var string The displayed name for this external page. Usually obtained through get_string().
1301 var $visiblename;
1303 * @var mixed An array of admin_setting objects that are part of this setting page.
1305 var $settings;
1308 * @var string The role capability/permission a user must have to access this external page.
1310 var $req_capability;
1313 * @var object The context in which capability/permission should be checked, default is site context.
1315 var $context;
1318 * @var bool hidden in admin tree block.
1320 var $hidden;
1323 * paths
1325 var $path;
1326 var $visiblepath;
1328 // see admin_externalpage
1329 function admin_settingpage($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1330 $this->settings = new object();
1331 $this->name = $name;
1332 $this->visiblename = $visiblename;
1333 if (is_array($req_capability)) {
1334 $this->req_capability = $req_capability;
1335 } else {
1336 $this->req_capability = array($req_capability);
1338 $this->hidden = $hidden;
1339 $this->context = $context;
1342 // see admin_category
1343 function &locate($name, $findpath=false) {
1344 if ($this->name == $name) {
1345 if ($findpath) {
1346 $this->visiblepath = array($this->visiblename);
1347 $this->path = array($this->name);
1349 return $this;
1350 } else {
1351 $return = NULL;
1352 return $return;
1356 function search($query) {
1357 $found = array();
1359 foreach ($this->settings as $setting) {
1360 if ($setting->is_related($query)) {
1361 $found[] = $setting;
1365 if ($found) {
1366 $result = new object();
1367 $result->page = $this;
1368 $result->settings = $found;
1369 return array($this->name => $result);
1372 $textlib = textlib_get_instance();
1374 $found = false;
1375 if (strpos(strtolower($this->name), $query) !== false) {
1376 $found = true;
1377 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1378 $found = true;
1380 if ($found) {
1381 $result = new object();
1382 $result->page = $this;
1383 $result->settings = array();
1384 return array($this->name => $result);
1385 } else {
1386 return array();
1390 function prune($name) {
1391 return false;
1395 * 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
1396 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1397 * @param object $setting is the admin_setting object you want to add
1398 * @return true if successful, false if not
1400 function add($setting) {
1401 if (!is_a($setting, 'admin_setting')) {
1402 debugging('error - not a setting instance');
1403 return false;
1406 $this->settings->{$setting->name} = $setting;
1407 return true;
1410 // see admin_externalpage
1411 function check_access() {
1412 if (!get_site()) {
1413 return true; // no access check before site is fully set up
1415 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1416 foreach($this->req_capability as $cap) {
1417 if (has_capability($cap, $context)) {
1418 return true;
1421 return false;
1425 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1426 * returns a string of the html
1428 function output_html() {
1429 $adminroot =& admin_get_root();
1430 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
1431 foreach($this->settings as $setting) {
1432 $fullname = $setting->get_full_name();
1433 if (array_key_exists($fullname, $adminroot->errors)) {
1434 $data = $adminroot->errors[$fullname]->data;
1435 } else {
1436 $data = $setting->get_setting();
1437 if (is_null($data)) {
1438 $data = $setting->get_defaultsetting();
1441 $return .= $setting->output_html($data);
1443 $return .= '</fieldset>';
1444 return $return;
1448 * Is this settigns page hidden in admin tree block?
1450 * @return bool True if hidden
1452 function is_hidden() {
1453 return $this->hidden;
1460 * Admin settings class. Only exists on setting pages.
1461 * Read & write happens at this level; no authentication.
1463 class admin_setting {
1465 var $name;
1466 var $visiblename;
1467 var $description;
1468 var $defaultsetting;
1469 var $updatedcallback;
1470 var $plugin; // null means main config table
1473 * Constructor
1474 * @param $name string unique ascii name
1475 * @param $visiblename string localised name
1476 * @param strin $description localised long description
1477 * @param mixed $defaultsetting string or array depending on implementation
1479 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1480 $this->name = $name;
1481 $this->visiblename = $visiblename;
1482 $this->description = $description;
1483 $this->defaultsetting = $defaultsetting;
1486 function get_full_name() {
1487 return 's_'.$this->plugin.'_'.$this->name;
1490 function get_id() {
1491 return 'id_s_'.$this->plugin.'_'.$this->name;
1494 function config_read($name) {
1495 global $CFG;
1496 if ($this->plugin === 'backup') {
1497 require_once($CFG->dirroot.'/backup/lib.php');
1498 $backupconfig = backup_get_config();
1499 if (isset($backupconfig->$name)) {
1500 return $backupconfig->$name;
1501 } else {
1502 return NULL;
1505 } else if (!empty($this->plugin)) {
1506 $value = get_config($this->plugin, $name);
1507 return $value === false ? NULL : $value;
1509 } else {
1510 if (isset($CFG->$name)) {
1511 return $CFG->$name;
1512 } else {
1513 return NULL;
1518 function config_write($name, $value) {
1519 global $CFG;
1520 if ($this->plugin === 'backup') {
1521 require_once($CFG->dirroot.'/backup/lib.php');
1522 return (boolean)backup_set_config($name, $value);
1523 } else {
1524 return (boolean)set_config($name, $value, $this->plugin);
1529 * Returns current value of this setting
1530 * @return mixed array or string depending on instance, NULL means not set yet
1532 function get_setting() {
1533 // has to be overridden
1534 return NULL;
1538 * Returns default setting if exists
1539 * @return mixed array or string depending on instance; NULL means no default, user must supply
1541 function get_defaultsetting() {
1542 return $this->defaultsetting;
1546 * Store new setting
1547 * @param mixed string or array, must not be NULL
1548 * @return '' if ok, string error message otherwise
1550 function write_setting($data) {
1551 // should be overridden
1552 return '';
1556 * Return part of form with setting
1557 * @param mixed data array or string depending on setting
1558 * @return string
1560 function output_html($data, $query='') {
1561 // should be overridden
1562 return;
1566 * function called if setting updated - cleanup, cache reset, etc.
1568 function set_updatedcallback($functionname) {
1569 $this->updatedcallback = $functionname;
1573 * Is setting related to query text - used when searching
1574 * @param string $query
1575 * @return bool
1577 function is_related($query) {
1578 if (strpos(strtolower($this->name), $query) !== false) {
1579 return true;
1581 $textlib = textlib_get_instance();
1582 if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1583 return true;
1585 if (strpos($textlib->strtolower($this->description), $query) !== false) {
1586 return true;
1588 $current = $this->get_setting();
1589 if (!is_null($current)) {
1590 if (is_string($current)) {
1591 if (strpos($textlib->strtolower($current), $query) !== false) {
1592 return true;
1596 $default = $this->get_defaultsetting();
1597 if (!is_null($default)) {
1598 if (is_string($default)) {
1599 if (strpos($textlib->strtolower($default), $query) !== false) {
1600 return true;
1604 return false;
1609 * No setting - just heading and text.
1611 class admin_setting_heading extends admin_setting {
1613 * not a setting, just text
1614 * @param string $name of setting
1615 * @param string $heading heading
1616 * @param string $information text in box
1618 function admin_setting_heading($name, $heading, $information) {
1619 parent::admin_setting($name, $heading, $information, '');
1622 function get_setting() {
1623 return true;
1626 function get_defaultsetting() {
1627 return true;
1630 function write_setting($data) {
1631 // do not write any setting
1632 return '';
1635 function output_html($data, $query='') {
1636 $return = '';
1637 if ($this->visiblename != '') {
1638 $return .= print_heading('<a name="'.$this->name.'">'.highlightfast($query, $this->visiblename).'</a>', '', 3, 'main', true);
1640 if ($this->description != '') {
1641 $return .= print_box(highlight($query, $this->description), 'generalbox formsettingheading', '', true);
1643 return $return;
1648 * The most flexibly setting, user is typing text
1650 class admin_setting_configtext extends admin_setting {
1652 var $paramtype;
1653 var $size;
1656 * config text contructor
1657 * @param string $name of setting
1658 * @param string $visiblename localised
1659 * @param string $description long localised info
1660 * @param string $defaultsetting
1661 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
1662 * @param int $size default field size
1664 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
1665 $this->paramtype = $paramtype;
1666 if (!is_null($size)) {
1667 $this->size = $size;
1668 } else {
1669 $this->size = ($paramtype == PARAM_INT) ? 5 : 30;
1671 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1674 function get_setting() {
1675 return $this->config_read($this->name);
1678 function write_setting($data) {
1679 if ($this->paramtype === PARAM_INT and $data === '') {
1680 // do not complain if '' used instead of 0
1681 $data = 0;
1683 // $data is a string
1684 $validated = $this->validate($data);
1685 if ($validated !== true) {
1686 return $validated;
1688 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
1692 * Validate data before storage
1693 * @param string data
1694 * @return mixed true if ok string if error found
1696 function validate($data) {
1697 if (is_string($this->paramtype)) {
1698 if (preg_match($this->paramtype, $data)) {
1699 return true;
1700 } else {
1701 return get_string('validateerror', 'admin');
1704 } else if ($this->paramtype === PARAM_RAW) {
1705 return true;
1707 } else {
1708 $cleaned = stripslashes(clean_param(addslashes($data), $this->paramtype));
1709 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
1710 return true;
1711 } else {
1712 return get_string('validateerror', 'admin');
1717 function output_html($data, $query='') {
1718 $default = $this->get_defaultsetting();
1720 return format_admin_setting($this, $this->visiblename,
1721 '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>',
1722 $this->description, true, '', $default, $query);
1727 * General text area without html editor.
1729 class admin_setting_configtextarea extends admin_setting_configtext {
1730 var $rows;
1731 var $cols;
1733 function admin_setting_configtextarea($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
1734 $this->rows = $rows;
1735 $this->cols = $cols;
1736 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1739 function output_html($data, $query='') {
1740 $default = $this->get_defaultsetting();
1742 $defaultinfo = $default;
1743 if (!is_null($default) and $default !== '') {
1744 $defaultinfo = "\n".$default;
1747 return format_admin_setting($this, $this->visiblename,
1748 '<div class="form-textarea" ><textarea rows="'.$this->rows.'" cols="'.$this->cols.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'">'.s($data).'</textarea></div>',
1749 $this->description, true, '', $defaultinfo, $query);
1754 * Password field, allows unmasking of password
1756 class admin_setting_configpasswordunmask extends admin_setting_configtext {
1758 * Constructor
1759 * @param string $name of setting
1760 * @param string $visiblename localised
1761 * @param string $description long localised info
1762 * @param string $defaultsetting default password
1764 function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting) {
1765 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
1768 function output_html($data, $query='') {
1769 $id = $this->get_id();
1770 $unmask = get_string('unmaskpassword', 'form');
1771 $unmaskjs = '<script type="text/javascript">
1772 //<![CDATA[
1773 document.write(\'<span class="unmask"><input id="'.$id.'unmask" value="1" type="checkbox" onclick="unmaskPassword(\\\''.$id.'\\\')"/><label for="'.$id.'unmask">'.addslashes_js($unmask).'<\/label><\/span>\');
1774 //]]>
1775 </script>';
1776 return format_admin_setting($this, $this->visiblename,
1777 '<div class="form-password"><input type="password" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$unmaskjs.'</div>',
1778 $this->description, true, '', NULL, $query);
1783 * Path to directory
1785 class admin_setting_configfile extends admin_setting_configtext {
1787 * Constructor
1788 * @param string $name of setting
1789 * @param string $visiblename localised
1790 * @param string $description long localised info
1791 * @param string $defaultdirectory default directory location
1793 function admin_setting_configfile($name, $visiblename, $description, $defaultdirectory) {
1794 parent::admin_setting_configtext($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
1797 function output_html($data, $query='') {
1798 $default = $this->get_defaultsetting();
1800 if ($data) {
1801 if (file_exists($data)) {
1802 $executable = '<span class="pathok">&#x2714;</span>';
1803 } else {
1804 $executable = '<span class="patherror">&#x2718;</span>';
1806 } else {
1807 $executable = '';
1810 return format_admin_setting($this, $this->visiblename,
1811 '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
1812 $this->description, true, '', $default, $query);
1817 * Path to executable file
1819 class admin_setting_configexecutable extends admin_setting_configfile {
1821 function output_html($data, $query='') {
1822 $default = $this->get_defaultsetting();
1824 if ($data) {
1825 if (file_exists($data) and is_executable($data)) {
1826 $executable = '<span class="pathok">&#x2714;</span>';
1827 } else {
1828 $executable = '<span class="patherror">&#x2718;</span>';
1830 } else {
1831 $executable = '';
1834 return format_admin_setting($this, $this->visiblename,
1835 '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
1836 $this->description, true, '', $default, $query);
1841 * Path to directory
1843 class admin_setting_configdirectory extends admin_setting_configfile {
1844 function output_html($data, $query='') {
1845 $default = $this->get_defaultsetting();
1847 if ($data) {
1848 if (file_exists($data) and is_dir($data)) {
1849 $executable = '<span class="pathok">&#x2714;</span>';
1850 } else {
1851 $executable = '<span class="patherror">&#x2718;</span>';
1853 } else {
1854 $executable = '';
1857 return format_admin_setting($this, $this->visiblename,
1858 '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
1859 $this->description, true, '', $default, $query);
1864 * Checkbox
1866 class admin_setting_configcheckbox extends admin_setting {
1867 var $yes;
1868 var $no;
1871 * Constructor
1872 * @param string $name of setting
1873 * @param string $visiblename localised
1874 * @param string $description long localised info
1875 * @param string $defaultsetting
1876 * @param string $yes value used when checked
1877 * @param string $no value used when not checked
1879 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
1880 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1881 $this->yes = (string)$yes;
1882 $this->no = (string)$no;
1885 function get_setting() {
1886 return $this->config_read($this->name);
1889 function write_setting($data) {
1890 if ((string)$data === $this->yes) { // convert to strings before comparison
1891 $data = $this->yes;
1892 } else {
1893 $data = $this->no;
1895 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
1898 function output_html($data, $query='') {
1899 $default = $this->get_defaultsetting();
1901 if (!is_null($default)) {
1902 if ((string)$default === $this->yes) {
1903 $defaultinfo = get_string('checkboxyes', 'admin');
1904 } else {
1905 $defaultinfo = get_string('checkboxno', 'admin');
1907 } else {
1908 $defaultinfo = NULL;
1911 if ((string)$data === $this->yes) { // convert to strings before comparison
1912 $checked = 'checked="checked"';
1913 } else {
1914 $checked = '';
1917 return format_admin_setting($this, $this->visiblename,
1918 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
1919 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
1920 $this->description, true, '', $defaultinfo, $query);
1925 * Multiple checkboxes, each represents different value, stored in csv format
1927 class admin_setting_configmulticheckbox extends admin_setting {
1928 var $choices;
1931 * Constructor
1932 * @param string $name of setting
1933 * @param string $visiblename localised
1934 * @param string $description long localised info
1935 * @param array $defaultsetting array of selected
1936 * @param array $choices array of $value=>$label for each checkbox
1938 function admin_setting_configmulticheckbox($name, $visiblename, $description, $defaultsetting, $choices) {
1939 $this->choices = $choices;
1940 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1944 * This function may be used in ancestors for lazy loading of choices
1945 * @return true if loaded, false if error
1947 function load_choices() {
1949 if (is_array($this->choices)) {
1950 return true;
1952 .... load choices here
1954 return true;
1958 * Is setting related to query text - used when searching
1959 * @param string $query
1960 * @return bool
1962 function is_related($query) {
1963 if (!$this->load_choices() or empty($this->choices)) {
1964 return false;
1966 if (parent::is_related($query)) {
1967 return true;
1970 $textlib = textlib_get_instance();
1971 foreach ($this->choices as $desc) {
1972 if (strpos($textlib->strtolower($desc), $query) !== false) {
1973 return true;
1976 return false;
1979 function get_setting() {
1980 $result = $this->config_read($this->name);
1981 if (is_null($result)) {
1982 return NULL;
1984 if ($result === '') {
1985 return array();
1987 return explode(',', $result);
1990 function write_setting($data) {
1991 if (!is_array($data)) {
1992 return ''; // ignore it
1994 if (!$this->load_choices() or empty($this->choices)) {
1995 return '';
1997 unset($data['xxxxx']);
1998 $result = array();
1999 foreach ($data as $key => $value) {
2000 if ($value and array_key_exists($key, $this->choices)) {
2001 $result[] = $key;
2004 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
2007 function output_html($data, $query='') {
2008 if (!$this->load_choices() or empty($this->choices)) {
2009 return '';
2011 $default = $this->get_defaultsetting();
2012 if (is_null($default)) {
2013 $default = array();
2015 if (is_null($data)) {
2016 foreach ($default as $key=>$value) {
2017 if ($value) {
2018 $current[] = $value;
2023 $options = array();
2024 $defaults = array();
2025 foreach($this->choices as $key=>$description) {
2026 if (in_array($key, $data)) {
2027 $checked = 'checked="checked"';
2028 } else {
2029 $checked = '';
2031 if (!empty($default[$key])) {
2032 $defaults[] = $description;
2035 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
2036 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
2039 if (is_null($default)) {
2040 $defaultinfo = NULL;
2041 } else if (!empty($defaults)) {
2042 $defaultinfo = implode(', ', $defaults);
2043 } else {
2044 $defaultinfo = get_string('none');
2047 $return = '<div class="form-multicheckbox">';
2048 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2049 if ($options) {
2050 $return .= '<ul>';
2051 foreach ($options as $option) {
2052 $return .= '<li>'.$option.'</li>';
2054 $return .= '</ul>';
2056 $return .= '</div>';
2058 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2064 * Multiple checkboxes 2, value stored as string 00101011
2066 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
2067 function get_setting() {
2068 $result = $this->config_read($this->name);
2069 if (is_null($result)) {
2070 return NULL;
2072 if (!$this->load_choices()) {
2073 return NULL;
2075 $result = str_pad($result, count($this->choices), '0');
2076 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2077 $setting = array();
2078 foreach ($this->choices as $key=>$unused) {
2079 $value = array_shift($result);
2080 if ($value) {
2081 $setting[] = $key;
2084 return $setting;
2087 function write_setting($data) {
2088 if (!is_array($data)) {
2089 return ''; // ignore it
2091 if (!$this->load_choices() or empty($this->choices)) {
2092 return '';
2094 $result = '';
2095 foreach ($this->choices as $key=>$unused) {
2096 if (!empty($data[$key])) {
2097 $result .= '1';
2098 } else {
2099 $result .= '0';
2102 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
2107 * Select one value from list
2109 class admin_setting_configselect extends admin_setting {
2110 var $choices;
2113 * Constructor
2114 * @param string $name of setting
2115 * @param string $visiblename localised
2116 * @param string $description long localised info
2117 * @param string $defaultsetting
2118 * @param array $choices array of $value=>$label for each selection
2120 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
2121 $this->choices = $choices;
2122 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2126 * This function may be used in ancestors for lazy loading of choices
2127 * @return true if loaded, false if error
2129 function load_choices() {
2131 if (is_array($this->choices)) {
2132 return true;
2134 .... load choices here
2136 return true;
2139 function is_related($query) {
2140 if (parent::is_related($query)) {
2141 return true;
2143 if (!$this->load_choices()) {
2144 return false;
2146 $textlib = textlib_get_instance();
2147 foreach ($this->choices as $key=>$value) {
2148 if (strpos($textlib->strtolower($key), $query) !== false) {
2149 return true;
2151 if (strpos($textlib->strtolower($value), $query) !== false) {
2152 return true;
2155 return false;
2158 function get_setting() {
2159 return $this->config_read($this->name);
2162 function write_setting($data) {
2163 if (!$this->load_choices() or empty($this->choices)) {
2164 return '';
2166 if (!array_key_exists($data, $this->choices)) {
2167 return ''; // ignore it
2170 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2173 function output_html($data, $query='') {
2174 if (!$this->load_choices() or empty($this->choices)) {
2175 return '';
2177 $default = $this->get_defaultsetting();
2179 if (!is_null($default) and array_key_exists($default, $this->choices)) {
2180 $defaultinfo = $this->choices[$default];
2181 } else {
2182 $defaultinfo = NULL;
2185 $current = $this->get_setting();
2186 $warning = '';
2187 if (is_null($current)) {
2188 //first run
2189 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
2190 // no warning
2191 } else if (!array_key_exists($current, $this->choices)) {
2192 $warning = get_string('warningcurrentsetting', 'admin', s($current));
2193 if (!is_null($default) and $data==$current) {
2194 $data = $default; // use default instead of first value when showing the form
2198 $return = '<div class="form-select defaultsnext"><select id="'.$this->get_id().'" name="'.$this->get_full_name().'">';
2199 foreach ($this->choices as $key => $value) {
2200 // the string cast is needed because key may be integer - 0 is equal to most strings!
2201 $return .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
2203 $return .= '</select></div>';
2205 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
2211 * Select multiple items from list
2213 class admin_setting_configmultiselect extends admin_setting_configselect {
2215 * Constructor
2216 * @param string $name of setting
2217 * @param string $visiblename localised
2218 * @param string $description long localised info
2219 * @param array $defaultsetting array of selected items
2220 * @param array $choices array of $value=>$label for each list item
2222 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
2223 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
2226 function get_setting() {
2227 $result = $this->config_read($this->name);
2228 if (is_null($result)) {
2229 return NULL;
2231 if ($result === '') {
2232 return array();
2234 return explode(',', $result);
2237 function write_setting($data) {
2238 if (!is_array($data)) {
2239 return ''; //ignore it
2241 if (!$this->load_choices() or empty($this->choices)) {
2242 return '';
2245 unset($data['xxxxx']);
2247 $save = array();
2248 foreach ($data as $value) {
2249 if (!array_key_exists($value, $this->choices)) {
2250 continue; // ignore it
2252 $save[] = $value;
2255 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2259 * Is setting related to query text - used when searching
2260 * @param string $query
2261 * @return bool
2263 function is_related($query) {
2264 if (!$this->load_choices() or empty($this->choices)) {
2265 return false;
2267 if (parent::is_related($query)) {
2268 return true;
2271 $textlib = textlib_get_instance();
2272 foreach ($this->choices as $desc) {
2273 if (strpos($textlib->strtolower($desc), $query) !== false) {
2274 return true;
2277 return false;
2280 function output_html($data, $query='') {
2281 if (!$this->load_choices() or empty($this->choices)) {
2282 return '';
2284 $choices = $this->choices;
2285 $default = $this->get_defaultsetting();
2286 if (is_null($default)) {
2287 $default = array();
2289 if (is_null($data)) {
2290 $data = array();
2293 $defaults = array();
2294 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2295 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="10" multiple="multiple">';
2296 foreach ($this->choices as $key => $description) {
2297 if (in_array($key, $data)) {
2298 $selected = 'selected="selected"';
2299 } else {
2300 $selected = '';
2302 if (in_array($key, $default)) {
2303 $defaults[] = $description;
2306 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
2309 if (is_null($default)) {
2310 $defaultinfo = NULL;
2311 } if (!empty($defaults)) {
2312 $defaultinfo = implode(', ', $defaults);
2313 } else {
2314 $defaultinfo = get_string('none');
2317 $return .= '</select></div>';
2318 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
2323 * Time selector
2324 * this is a liiitle bit messy. we're using two selects, but we're returning
2325 * them as an array named after $name (so we only use $name2 internally for the setting)
2327 class admin_setting_configtime extends admin_setting {
2328 var $name2;
2331 * Constructor
2332 * @param string $hoursname setting for hours
2333 * @param string $minutesname setting for hours
2334 * @param string $visiblename localised
2335 * @param string $description long localised info
2336 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
2338 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
2339 $this->name2 = $minutesname;
2340 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
2343 function get_setting() {
2344 $result1 = $this->config_read($this->name);
2345 $result2 = $this->config_read($this->name2);
2346 if (is_null($result1) or is_null($result2)) {
2347 return NULL;
2350 return array('h' => $result1, 'm' => $result2);
2353 function write_setting($data) {
2354 if (!is_array($data)) {
2355 return '';
2358 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
2359 return ($result ? '' : get_string('errorsetting', 'admin'));
2362 function output_html($data, $query='') {
2363 $default = $this->get_defaultsetting();
2365 if (is_array($default)) {
2366 $defaultinfo = $default['h'].':'.$default['m'];
2367 } else {
2368 $defaultinfo = NULL;
2371 $return = '<div class="form-time defaultsnext">'.
2372 '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
2373 for ($i = 0; $i < 24; $i++) {
2374 $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2376 $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
2377 for ($i = 0; $i < 60; $i += 5) {
2378 $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2380 $return .= '</select></div>';
2381 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2387 * Special checkbox for calendar - resets SESSION vars.
2389 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
2390 function admin_setting_special_adminseesall() {
2391 parent::admin_setting_configcheckbox('calendar_adminseesall', get_string('adminseesall', 'admin'),
2392 get_string('helpadminseesall', 'admin'), '0');
2395 function write_setting($data) {
2396 global $SESSION;
2397 unset($SESSION->cal_courses_shown);
2398 return parent::write_setting($data);
2403 * Special select for settings that are altered in setup.php and can not be altered on the fly
2405 class admin_setting_special_selectsetup extends admin_setting_configselect {
2406 function get_setting() {
2407 // read directly from db!
2408 return get_config(NULL, $this->name);
2411 function write_setting($data) {
2412 global $CFG;
2413 // do not change active CFG setting!
2414 $current = $CFG->{$this->name};
2415 $result = parent::write_setting($data);
2416 $CFG->{$this->name} = $current;
2417 return $result;
2422 * Special select for frontpage - stores data in course table
2424 class admin_setting_sitesetselect extends admin_setting_configselect {
2425 function get_setting() {
2426 $site = get_site();
2427 return $site->{$this->name};
2430 function write_setting($data) {
2431 if (!in_array($data, array_keys($this->choices))) {
2432 return get_string('errorsetting', 'admin');
2434 $record = new stdClass();
2435 $record->id = SITEID;
2436 $temp = $this->name;
2437 $record->$temp = $data;
2438 $record->timemodified = time();
2439 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2444 * Special select - lists on the frontpage - hacky
2446 class admin_setting_courselist_frontpage extends admin_setting {
2447 var $choices;
2449 function admin_setting_courselist_frontpage($loggedin) {
2450 global $CFG;
2451 require_once($CFG->dirroot.'/course/lib.php');
2452 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
2453 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
2454 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
2455 $defaults = array(FRONTPAGECOURSELIST);
2456 parent::admin_setting($name, $visiblename, $description, $defaults);
2459 function load_choices() {
2460 if (is_array($this->choices)) {
2461 return true;
2463 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
2464 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
2465 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
2466 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
2467 'none' => get_string('none'));
2468 if ($this->name == 'frontpage' and count_records('course') > FRONTPAGECOURSELIMIT) {
2469 unset($this->choices[FRONTPAGECOURSELIST]);
2471 return true;
2473 function get_setting() {
2474 $result = $this->config_read($this->name);
2475 if (is_null($result)) {
2476 return NULL;
2478 if ($result === '') {
2479 return array();
2481 return explode(',', $result);
2484 function write_setting($data) {
2485 if (!is_array($data)) {
2486 return '';
2488 $this->load_choices();
2489 $save = array();
2490 foreach($data as $datum) {
2491 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
2492 continue;
2494 $save[$datum] = $datum; // no duplicates
2496 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2499 function output_html($data, $query='') {
2500 $this->load_choices();
2501 $currentsetting = array();
2502 foreach ($data as $key) {
2503 if ($key != 'none' and array_key_exists($key, $this->choices)) {
2504 $currentsetting[] = $key; // already selected first
2508 $return = '<div class="form-group">';
2509 for ($i = 0; $i < count($this->choices) - 1; $i++) {
2510 if (!array_key_exists($i, $currentsetting)) {
2511 $currentsetting[$i] = 'none'; //none
2513 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
2514 foreach ($this->choices as $key => $value) {
2515 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
2517 $return .= '</select>';
2518 if ($i !== count($this->choices) - 2) {
2519 $return .= '<br />';
2522 $return .= '</div>';
2524 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2529 * Special checkbox for frontpage - stores data in course table
2531 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
2532 function get_setting() {
2533 $site = get_site();
2534 return $site->{$this->name};
2537 function write_setting($data) {
2538 $record = new object();
2539 $record->id = SITEID;
2540 $record->{$this->name} = ($data == '1' ? 1 : 0);
2541 $record->timemodified = time();
2542 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2547 * Special text for frontpage - stores data in course table.
2548 * Empty string means not set here. Manual setting is required.
2550 class admin_setting_sitesettext extends admin_setting_configtext {
2551 function get_setting() {
2552 $site = get_site();
2553 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
2556 function validate($data) {
2557 $cleaned = stripslashes(clean_param(addslashes($data), PARAM_MULTILANG));
2558 if ($cleaned === '') {
2559 return get_string('required');
2561 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
2562 return true;
2563 } else {
2564 return get_string('validateerror', 'admin');
2568 function write_setting($data) {
2569 $data = trim($data);
2570 $validated = $this->validate($data);
2571 if ($validated !== true) {
2572 return $validated;
2575 $record = new object();
2576 $record->id = SITEID;
2577 $record->{$this->name} = addslashes($data);
2578 $record->timemodified = time();
2579 return (update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
2584 * Special text editor for site description.
2586 class admin_setting_special_frontpagedesc extends admin_setting {
2587 function admin_setting_special_frontpagedesc() {
2588 parent::admin_setting('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
2591 function get_setting() {
2592 $site = get_site();
2593 return $site->{$this->name};
2596 function write_setting($data) {
2597 $record = new object();
2598 $record->id = SITEID;
2599 $record->{$this->name} = addslashes($data);
2600 $record->timemodified = time();
2601 return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2604 function output_html($data, $query='') {
2605 global $CFG;
2607 $CFG->adminusehtmleditor = can_use_html_editor();
2608 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true).'</div>';
2610 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2614 class admin_setting_special_editorfontlist extends admin_setting {
2616 var $items;
2618 function admin_setting_special_editorfontlist() {
2619 global $CFG;
2620 $name = 'editorfontlist';
2621 $visiblename = get_string('editorfontlist', 'admin');
2622 $description = get_string('configeditorfontlist', 'admin');
2623 $defaults = array('k0' => 'Trebuchet',
2624 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
2625 'k1' => 'Arial',
2626 'v1' => 'arial,helvetica,sans-serif',
2627 'k2' => 'Courier New',
2628 'v2' => 'courier new,courier,monospace',
2629 'k3' => 'Georgia',
2630 'v3' => 'georgia,times new roman,times,serif',
2631 'k4' => 'Tahoma',
2632 'v4' => 'tahoma,arial,helvetica,sans-serif',
2633 'k5' => 'Times New Roman',
2634 'v5' => 'times new roman,times,serif',
2635 'k6' => 'Verdana',
2636 'v6' => 'verdana,arial,helvetica,sans-serif',
2637 'k7' => 'Impact',
2638 'v7' => 'impact',
2639 'k8' => 'Wingdings',
2640 'v8' => 'wingdings');
2641 parent::admin_setting($name, $visiblename, $description, $defaults);
2644 function get_setting() {
2645 global $CFG;
2646 $result = $this->config_read($this->name);
2647 if (is_null($result)) {
2648 return NULL;
2650 $i = 0;
2651 $currentsetting = array();
2652 $items = explode(';', $result);
2653 foreach ($items as $item) {
2654 $item = explode(':', $item);
2655 $currentsetting['k'.$i] = $item[0];
2656 $currentsetting['v'.$i] = $item[1];
2657 $i++;
2659 return $currentsetting;
2662 function write_setting($data) {
2664 // there miiight be an easier way to do this :)
2665 // if this is changed, make sure the $defaults array above is modified so that this
2666 // function processes it correctly
2668 $keys = array();
2669 $values = array();
2671 foreach ($data as $key => $value) {
2672 if (substr($key,0,1) == 'k') {
2673 $keys[substr($key,1)] = $value;
2674 } elseif (substr($key,0,1) == 'v') {
2675 $values[substr($key,1)] = $value;
2679 $result = array();
2680 for ($i = 0; $i < count($keys); $i++) {
2681 if (($keys[$i] !== '') && ($values[$i] !== '')) {
2682 $result[] = clean_param($keys[$i],PARAM_NOTAGS).':'.clean_param($values[$i], PARAM_NOTAGS);
2686 return ($this->config_write($this->name, implode(';', $result)) ? '' : get_string('errorsetting', 'admin'));
2689 function output_html($data, $query='') {
2690 $fullname = $this->get_full_name();
2691 $return = '<div class="form-group">';
2692 for ($i = 0; $i < count($data) / 2; $i++) {
2693 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
2694 $return .= '&nbsp;&nbsp;';
2695 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
2697 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
2698 $return .= '&nbsp;&nbsp;';
2699 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2700 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
2701 $return .= '&nbsp;&nbsp;';
2702 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
2703 $return .= '</div>';
2705 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2710 class admin_setting_emoticons extends admin_setting {
2712 var $items;
2714 function admin_setting_emoticons() {
2715 global $CFG;
2716 $name = 'emoticons';
2717 $visiblename = get_string('emoticons', 'admin');
2718 $description = get_string('configemoticons', 'admin');
2719 $defaults = array('k0' => ':-)',
2720 'v0' => 'smiley',
2721 'k1' => ':)',
2722 'v1' => 'smiley',
2723 'k2' => ':-D',
2724 'v2' => 'biggrin',
2725 'k3' => ';-)',
2726 'v3' => 'wink',
2727 'k4' => ':-/',
2728 'v4' => 'mixed',
2729 'k5' => 'V-.',
2730 'v5' => 'thoughtful',
2731 'k6' => ':-P',
2732 'v6' => 'tongueout',
2733 'k7' => 'B-)',
2734 'v7' => 'cool',
2735 'k8' => '^-)',
2736 'v8' => 'approve',
2737 'k9' => '8-)',
2738 'v9' => 'wideeyes',
2739 'k10' => ':o)',
2740 'v10' => 'clown',
2741 'k11' => ':-(',
2742 'v11' => 'sad',
2743 'k12' => ':(',
2744 'v12' => 'sad',
2745 'k13' => '8-.',
2746 'v13' => 'shy',
2747 'k14' => ':-I',
2748 'v14' => 'blush',
2749 'k15' => ':-X',
2750 'v15' => 'kiss',
2751 'k16' => '8-o',
2752 'v16' => 'surprise',
2753 'k17' => 'P-|',
2754 'v17' => 'blackeye',
2755 'k18' => '8-[',
2756 'v18' => 'angry',
2757 'k19' => 'xx-P',
2758 'v19' => 'dead',
2759 'k20' => '|-.',
2760 'v20' => 'sleepy',
2761 'k21' => '}-]',
2762 'v21' => 'evil',
2763 'k22' => '(h)',
2764 'v22' => 'heart',
2765 'k23' => '(heart)',
2766 'v23' => 'heart',
2767 'k24' => '(y)',
2768 'v24' => 'yes',
2769 'k25' => '(n)',
2770 'v25' => 'no',
2771 'k26' => '(martin)',
2772 'v26' => 'martin',
2773 'k27' => '( )',
2774 'v27' => 'egg');
2775 parent::admin_setting($name, $visiblename, $description, $defaults);
2778 function get_setting() {
2779 global $CFG;
2780 $result = $this->config_read($this->name);
2781 if (is_null($result)) {
2782 return NULL;
2784 $i = 0;
2785 $currentsetting = array();
2786 $items = explode('{;}', $result);
2787 foreach ($items as $item) {
2788 $item = explode('{:}', $item);
2789 $currentsetting['k'.$i] = $item[0];
2790 $currentsetting['v'.$i] = $item[1];
2791 $i++;
2793 return $currentsetting;
2796 function write_setting($data) {
2798 // there miiight be an easier way to do this :)
2799 // if this is changed, make sure the $defaults array above is modified so that this
2800 // function processes it correctly
2802 $keys = array();
2803 $values = array();
2805 foreach ($data as $key => $value) {
2806 if (substr($key,0,1) == 'k') {
2807 $keys[substr($key,1)] = $value;
2808 } elseif (substr($key,0,1) == 'v') {
2809 $values[substr($key,1)] = $value;
2813 $result = array();
2814 for ($i = 0; $i < count($keys); $i++) {
2815 if (($keys[$i] !== '') && ($values[$i] !== '')) {
2816 $result[] = clean_param($keys[$i],PARAM_NOTAGS).'{:}'.clean_param($values[$i], PARAM_NOTAGS);
2820 return ($this->config_write($this->name, implode('{;}', $result)) ? '' : get_string('errorsetting', 'admin').$this->visiblename.'<br />');
2823 function output_html($data, $query='') {
2824 $fullname = $this->get_full_name();
2825 $return = '<div class="form-group">';
2826 for ($i = 0; $i < count($data) / 2; $i++) {
2827 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
2828 $return .= '&nbsp;&nbsp;';
2829 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
2831 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
2832 $return .= '&nbsp;&nbsp;';
2833 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2834 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
2835 $return .= '&nbsp;&nbsp;';
2836 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
2837 $return .= '</div>';
2839 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2845 * Setting for spellchecker language selection.
2847 class admin_setting_special_editordictionary extends admin_setting_configselect {
2849 function admin_setting_special_editordictionary() {
2850 $name = 'editordictionary';
2851 $visiblename = get_string('editordictionary','admin');
2852 $description = get_string('configeditordictionary', 'admin');
2853 parent::admin_setting_configselect($name, $visiblename, $description, '', NULL);
2856 function load_choices() {
2857 // function borrowed from the old moodle/admin/editor.php, slightly modified
2858 // Get all installed dictionaries in the system
2859 if (is_array($this->choices)) {
2860 return true;
2863 $this->choices = array();
2865 global $CFG;
2867 clearstatcache();
2869 // If aspellpath isn't set don't even bother ;-)
2870 if (empty($CFG->aspellpath)) {
2871 $this->choices['error'] = 'Empty aspell path!';
2872 return true;
2875 // Do we have access to popen function?
2876 if (!function_exists('popen')) {
2877 $this->choices['error'] = 'Popen function disabled!';
2878 return true;
2881 $cmd = $CFG->aspellpath;
2882 $output = '';
2883 $dictionaries = array();
2885 if(!($handle = @popen(escapeshellarg($cmd).' dump dicts', 'r'))) {
2886 $this->choices['error'] = 'Couldn\'t create handle!';
2889 while(!feof($handle)) {
2890 $output .= fread($handle, 1024);
2892 @pclose($handle);
2894 $dictionaries = explode(chr(10), $output);
2895 foreach ($dictionaries as $dict) {
2896 if (empty($dict)) {
2897 continue;
2899 $this->choices[$dict] = $dict;
2902 if (empty($this->choices)) {
2903 $this->choices['error'] = 'Error! Check your aspell installation!';
2905 return true;
2910 class admin_setting_special_editorhidebuttons extends admin_setting {
2911 var $items;
2913 function admin_setting_special_editorhidebuttons() {
2914 parent::admin_setting('editorhidebuttons', get_string('editorhidebuttons', 'admin'),
2915 get_string('confeditorhidebuttons', 'admin'), array());
2916 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
2917 $this->items = array('fontname' => '',
2918 'fontsize' => '',
2919 'formatblock' => '',
2920 'bold' => 'ed_format_bold.gif',
2921 'italic' => 'ed_format_italic.gif',
2922 'underline' => 'ed_format_underline.gif',
2923 'strikethrough' => 'ed_format_strike.gif',
2924 'subscript' => 'ed_format_sub.gif',
2925 'superscript' => 'ed_format_sup.gif',
2926 'copy' => 'ed_copy.gif',
2927 'cut' => 'ed_cut.gif',
2928 'paste' => 'ed_paste.gif',
2929 'clean' => 'ed_wordclean.gif',
2930 'undo' => 'ed_undo.gif',
2931 'redo' => 'ed_redo.gif',
2932 'justifyleft' => 'ed_align_left.gif',
2933 'justifycenter' => 'ed_align_center.gif',
2934 'justifyright' => 'ed_align_right.gif',
2935 'justifyfull' => 'ed_align_justify.gif',
2936 'lefttoright' => 'ed_left_to_right.gif',
2937 'righttoleft' => 'ed_right_to_left.gif',
2938 'insertorderedlist' => 'ed_list_num.gif',
2939 'insertunorderedlist' => 'ed_list_bullet.gif',
2940 'outdent' => 'ed_indent_less.gif',
2941 'indent' => 'ed_indent_more.gif',
2942 'forecolor' => 'ed_color_fg.gif',
2943 'hilitecolor' => 'ed_color_bg.gif',
2944 'inserthorizontalrule' => 'ed_hr.gif',
2945 'createanchor' => 'ed_anchor.gif',
2946 'createlink' => 'ed_link.gif',
2947 'unlink' => 'ed_unlink.gif',
2948 'insertimage' => 'ed_image.gif',
2949 'inserttable' => 'insert_table.gif',
2950 'insertsmile' => 'em.icon.smile.gif',
2951 'insertchar' => 'icon_ins_char.gif',
2952 'spellcheck' => 'spell-check.gif',
2953 'htmlmode' => 'ed_html.gif',
2954 'popupeditor' => 'fullscreen_maximize.gif',
2955 'search_replace' => 'ed_replace.gif');
2958 function get_setting() {
2959 $result = $this->config_read($this->name);
2960 if (is_null($result)) {
2961 return NULL;
2963 if ($result === '') {
2964 return array();
2966 return explode(' ', $result);
2969 function write_setting($data) {
2970 if (!is_array($data)) {
2971 return ''; // ignore it
2973 unset($data['xxxxx']);
2974 $result = array();
2976 foreach ($data as $key => $value) {
2977 if (!isset($this->items[$key])) {
2978 return get_string('errorsetting', 'admin');
2980 if ($value == '1') {
2981 $result[] = $key;
2984 return ($this->config_write($this->name, implode(' ', $result)) ? '' : get_string('errorsetting', 'admin'));
2987 function output_html($data, $query='') {
2989 global $CFG;
2991 // checkboxes with input name="$this->name[$key]" value="1"
2992 // we do 15 fields per column
2994 $return = '<div class="form-group">';
2995 $return .= '<table><tr><td valign="top" align="right">';
2996 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2998 $count = 0;
3000 foreach($this->items as $key => $value) {
3001 if ($count % 15 == 0 and $count != 0) {
3002 $return .= '</td><td valign="top" align="right">';
3005 $return .= '<label for="'.$this->get_id().$key.'">';
3006 $return .= ($value == '' ? get_string($key,'editor') : '<img width="18" height="18" src="'.$CFG->wwwroot.'/lib/editor/htmlarea/images/'.$value.'" alt="'.get_string($key,'editor').'" title="'.get_string($key,'editor').'" />').'&nbsp;';
3007 $return .= '<input type="checkbox" class="form-checkbox" value="1" id="'.$this->get_id().$key.'" name="'.$this->get_full_name().'['.$key.']"'.(in_array($key,$data) ? ' checked="checked"' : '').' />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
3008 $return .= '</label>';
3009 $count++;
3010 if ($count % 15 != 0) {
3011 $return .= '<br /><br />';
3015 $return .= '</td></tr>';
3016 $return .= '</table>';
3017 $return .= '</div>';
3019 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3024 * Special setting for limiting of the list of available languages.
3026 class admin_setting_langlist extends admin_setting_configtext {
3027 function admin_setting_langlist() {
3028 parent::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
3031 function write_setting($data) {
3032 $return = parent::write_setting($data);
3033 get_list_of_languages(true);//refresh the list
3034 return $return;
3039 * Course category selection
3041 class admin_settings_coursecat_select extends admin_setting_configselect {
3042 function admin_settings_coursecat_select($name, $visiblename, $description, $defaultsetting) {
3043 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, NULL);
3046 function load_choices() {
3047 global $CFG;
3048 require_once($CFG->dirroot.'/course/lib.php');
3049 if (is_array($this->choices)) {
3050 return true;
3052 $this->choices = make_categories_options();
3053 return true;
3057 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
3058 function admin_setting_special_backupdays() {
3059 parent::admin_setting_configmulticheckbox2('backup_sche_weekdays', get_string('schedule'), get_string('backupschedulehelp'), array(), NULL);
3060 $this->plugin = 'backup';
3063 function load_choices() {
3064 if (is_array($this->choices)) {
3065 return true;
3067 $this->choices = array();
3068 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3069 foreach ($days as $day) {
3070 $this->choices[$day] = get_string($day, 'calendar');
3072 return true;
3077 * Special debug setting
3079 class admin_setting_special_debug extends admin_setting_configselect {
3080 function admin_setting_special_debug() {
3081 parent::admin_setting_configselect('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
3084 function load_choices() {
3085 if (is_array($this->choices)) {
3086 return true;
3088 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
3089 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
3090 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
3091 DEBUG_ALL => get_string('debugall', 'admin'),
3092 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
3093 return true;
3098 class admin_setting_special_calendar_weekend extends admin_setting {
3099 function admin_setting_special_calendar_weekend() {
3100 $name = 'calendar_weekend';
3101 $visiblename = get_string('calendar_weekend', 'admin');
3102 $description = get_string('helpweekenddays', 'admin');
3103 $default = array ('0', '6'); // Saturdays and Sundays
3104 parent::admin_setting($name, $visiblename, $description, $default);
3107 function get_setting() {
3108 $result = $this->config_read($this->name);
3109 if (is_null($result)) {
3110 return NULL;
3112 if ($result === '') {
3113 return array();
3115 $settings = array();
3116 for ($i=0; $i<7; $i++) {
3117 if ($result & (1 << $i)) {
3118 $setting[] = $i;
3121 return $setting;
3124 function write_setting($data) {
3125 if (!is_array($data)) {
3126 return '';
3128 unset($data['xxxxx']);
3129 $result = 0;
3130 foreach($data as $index) {
3131 $result |= 1 << $index;
3133 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
3136 function output_html($data, $query='') {
3137 // The order matters very much because of the implied numeric keys
3138 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3139 $return = '<table><thead><tr>';
3140 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3141 foreach($days as $index => $day) {
3142 $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>';
3144 $return .= '</tr></thead><tbody><tr>';
3145 foreach($days as $index => $day) {
3146 $return .= '<td><input type="checkbox" class="form-checkbox" id="'.$this->get_id().$index.'" name="'.$this->get_full_name().'[]" value="'.$index.'" '.(in_array("$index", $data) ? 'checked="checked"' : '').' /></td>';
3148 $return .= '</tr></tbody></table>';
3150 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3157 * Graded roles in gradebook
3159 class admin_setting_special_gradebookroles extends admin_setting_configmulticheckbox {
3160 function admin_setting_special_gradebookroles() {
3161 parent::admin_setting_configmulticheckbox('gradebookroles', get_string('gradebookroles', 'admin'),
3162 get_string('configgradebookroles', 'admin'), NULL, NULL);
3165 function load_choices() {
3166 global $CFG;
3167 if (empty($CFG->rolesactive)) {
3168 return false;
3170 if (is_array($this->choices)) {
3171 return true;
3173 if ($roles = get_records('role')) {
3174 $this->choices = array();
3175 foreach($roles as $role) {
3176 $this->choices[$role->id] = format_string($role->name);
3178 return true;
3179 } else {
3180 return false;
3184 function get_defaultsetting() {
3185 global $CFG;
3186 if (empty($CFG->rolesactive)) {
3187 return NULL;
3189 $result = array();
3190 if ($studentroles = get_roles_with_capability('moodle/legacy:student', CAP_ALLOW)) {
3191 foreach ($studentroles as $studentrole) {
3192 $result[$studentrole->id] = '1';
3195 return $result;
3199 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
3200 function write_setting($data) {
3201 global $CFG;
3203 $oldvalue = $this->config_read($this->name);
3204 $return = parent::write_setting($data);
3205 $newvalue = $this->config_read($this->name);
3207 if ($oldvalue !== $newvalue) {
3208 // force full regrading
3209 set_field('grade_items', 'needsupdate', 1, 'needsupdate', 0);
3212 return $return;
3217 * Which roles to show on course decription page
3219 class admin_setting_special_coursemanager extends admin_setting_configmulticheckbox {
3220 function admin_setting_special_coursemanager() {
3221 parent::admin_setting_configmulticheckbox('coursemanager', get_string('coursemanager', 'admin'),
3222 get_string('configcoursemanager', 'admin'), NULL, NULL);
3225 function load_choices() {
3226 if (is_array($this->choices)) {
3227 return true;
3229 if ($roles = get_records('role')) {
3230 $this->choices = array();
3231 foreach($roles as $role) {
3232 $this->choices[$role->id] = format_string($role->name);
3234 return true;
3236 return false;
3239 function get_defaultsetting() {
3240 global $CFG;
3241 if (empty($CFG->rolesactive)) {
3242 return NULL;
3244 $result = array();
3245 if ($teacherroles = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW)) {
3246 foreach ($teacherroles as $teacherrole) {
3247 $result[$teacherrole->id] = '1';
3250 return $result;
3255 * Primary grade export plugin - has state tracking.
3257 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
3258 function admin_setting_special_gradeexport() {
3259 parent::admin_setting_configmulticheckbox('gradeexport', get_string('gradeexport', 'admin'),
3260 get_string('configgradeexport', 'admin'), array(), NULL);
3263 function load_choices() {
3264 if (is_array($this->choices)) {
3265 return true;
3267 $this->choices = array();
3269 if ($plugins = get_list_of_plugins('grade/export')) {
3270 foreach($plugins as $plugin) {
3271 $this->choices[$plugin] = get_string('modulename', 'gradeexport_'.$plugin);
3274 return true;
3279 * Grade category settings
3281 class admin_setting_gradecat_combo extends admin_setting {
3283 var $choices;
3285 function admin_setting_gradecat_combo($name, $visiblename, $description, $defaultsetting, $choices) {
3286 $this->choices = $choices;
3287 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
3290 function get_setting() {
3291 global $CFG;
3293 $value = $this->config_read($this->name);
3294 $flag = $this->config_read($this->name.'_flag');
3296 if (is_null($value) or is_null($flag)) {
3297 return NULL;
3300 $flag = (int)$flag;
3301 $forced = (boolean)(1 & $flag); // first bit
3302 $adv = (boolean)(2 & $flag); // second bit
3304 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
3307 function write_setting($data) {
3308 global $CFG;
3310 $value = $data['value'];
3311 $forced = empty($data['forced']) ? 0 : 1;
3312 $adv = empty($data['adv']) ? 0 : 2;
3313 $flag = ($forced | $adv); //bitwise or
3315 if (!in_array($value, array_keys($this->choices))) {
3316 return 'Error setting ';
3319 $oldvalue = $this->config_read($this->name);
3320 $oldflag = (int)$this->config_read($this->name.'_flag');
3321 $oldforced = (1 & $oldflag); // first bit
3323 $result1 = $this->config_write($this->name, $value);
3324 $result2 = $this->config_write($this->name.'_flag', $flag);
3326 // force regrade if needed
3327 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
3328 require_once($CFG->libdir.'/gradelib.php');
3329 grade_category::updated_forced_settings();
3332 if ($result1 and $result2) {
3333 return '';
3334 } else {
3335 return get_string('errorsetting', 'admin');
3339 function output_html($data, $query='') {
3340 $value = $data['value'];
3341 $forced = !empty($data['forced']);
3342 $adv = !empty($data['adv']);
3344 $default = $this->get_defaultsetting();
3345 if (!is_null($default)) {
3346 $defaultinfo = array();
3347 if (isset($this->choices[$default['value']])) {
3348 $defaultinfo[] = $this->choices[$default['value']];
3350 if (!empty($default['forced'])) {
3351 $defaultinfo[] = get_string('force');
3353 if (!empty($default['adv'])) {
3354 $defaultinfo[] = get_string('advanced');
3356 $defaultinfo = implode(', ', $defaultinfo);
3358 } else {
3359 $defaultinfo = NULL;
3363 $return = '<div class="form-group">';
3364 $return .= '<select class="form-select" id="'.$this->get_id().'" name="'.$this->get_full_name().'[value]">';
3365 foreach ($this->choices as $key => $val) {
3366 // the string cast is needed because key may be integer - 0 is equal to most strings!
3367 $return .= '<option value="'.$key.'"'.((string)$key==$value ? ' selected="selected"' : '').'>'.$val.'</option>';
3369 $return .= '</select>';
3370 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'force" name="'.$this->get_full_name().'[forced]" value="1" '.($forced ? 'checked="checked"' : '').' />'
3371 .'<label for="'.$this->get_id().'force">'.get_string('force').'</label>';
3372 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'adv" name="'.$this->get_full_name().'[adv]" value="1" '.($adv ? 'checked="checked"' : '').' />'
3373 .'<label for="'.$this->get_id().'adv">'.get_string('advanced').'</label>';
3374 $return .= '</div>';
3376 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
3382 * Selection of grade report in user profiles
3384 class admin_setting_grade_profilereport extends admin_setting_configselect {
3385 function admin_setting_grade_profilereport() {
3386 parent::admin_setting_configselect('grade_profilereport', get_string('profilereport', 'grades'), get_string('configprofilereport', 'grades'), 'user', null);
3389 function load_choices() {
3390 if (is_array($this->choices)) {
3391 return true;
3393 $this->choices = array();
3395 global $CFG;
3396 require_once($CFG->libdir.'/gradelib.php');
3398 foreach (get_list_of_plugins('grade/report') as $plugin) {
3399 if (file_exists($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php')) {
3400 require_once($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php');
3401 $functionname = 'grade_report_'.$plugin.'_profilereport';
3402 if (function_exists($functionname)) {
3403 $this->choices[$plugin] = get_string('modulename', 'gradereport_'.$plugin, NULL, $CFG->dirroot.'/grade/report/'.$plugin.'/lang/');
3407 return true;
3412 * Special class for register auth selection
3414 class admin_setting_special_registerauth extends admin_setting_configselect {
3415 function admin_setting_special_registerauth() {
3416 parent::admin_setting_configselect('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), 'email', null);
3419 function get_defaultsettings() {
3420 $this->load_choices();
3421 if (array_key_exists($this->defaultsetting, $this->choices)) {
3422 return $this->defaultsetting;
3423 } else {
3424 return '';
3428 function load_choices() {
3429 global $CFG;
3431 if (is_array($this->choices)) {
3432 return true;
3434 $this->choices = array();
3435 $this->choices[''] = get_string('disable');
3437 $authsenabled = get_enabled_auth_plugins(true);
3439 foreach ($authsenabled as $auth) {
3440 $authplugin = get_auth_plugin($auth);
3441 if (!$authplugin->can_signup()) {
3442 continue;
3444 // Get the auth title (from core or own auth lang files)
3445 $authtitle = $authplugin->get_title();
3446 $this->choices[$auth] = $authtitle;
3448 return true;
3453 * Module manage page
3455 class admin_page_managemods extends admin_externalpage {
3456 function admin_page_managemods() {
3457 global $CFG;
3458 parent::admin_externalpage('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
3461 function search($query) {
3462 if ($result = parent::search($query)) {
3463 return $result;
3466 $found = false;
3467 if ($modules = get_records('modules')) {
3468 $textlib = textlib_get_instance();
3469 foreach ($modules as $module) {
3470 if (strpos($module->name, $query) !== false) {
3471 $found = true;
3472 break;
3474 $strmodulename = get_string('modulename', $module->name);
3475 if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
3476 $found = true;
3477 break;
3481 if ($found) {
3482 $result = new object();
3483 $result->page = $this;
3484 $result->settings = array();
3485 return array($this->name => $result);
3486 } else {
3487 return array();
3493 * Blocks manage page
3495 class admin_page_manageblocks extends admin_externalpage {
3496 function admin_page_manageblocks() {
3497 global $CFG;
3498 parent::admin_externalpage('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
3501 function search($query) {
3502 global $CFG;
3503 if ($result = parent::search($query)) {
3504 return $result;
3507 $found = false;
3508 if (!empty($CFG->blocks_version) and $blocks = get_records('block')) {
3509 $textlib = textlib_get_instance();
3510 foreach ($blocks as $block) {
3511 if (strpos($block->name, $query) !== false) {
3512 $found = true;
3513 break;
3515 $strblockname = get_string('blockname', 'block_'.$block->name);
3516 if (strpos($textlib->strtolower($strblockname), $query) !== false) {
3517 $found = true;
3518 break;
3522 if ($found) {
3523 $result = new object();
3524 $result->page = $this;
3525 $result->settings = array();
3526 return array($this->name => $result);
3527 } else {
3528 return array();
3534 * Special class for authentication administration.
3536 class admin_setting_manageauths extends admin_setting {
3537 function admin_setting_manageauths() {
3538 parent::admin_setting('authsui', get_string('authsettings', 'admin'), '', '');
3541 function get_setting() {
3542 return true;
3545 function get_defaultsetting() {
3546 return true;
3549 function write_setting($data) {
3550 // do not write any setting
3551 return '';
3554 function is_related($query) {
3555 if (parent::is_related($query)) {
3556 return true;
3559 $textlib = textlib_get_instance();
3560 $authsavailable = get_list_of_plugins('auth');
3561 foreach ($authsavailable as $auth) {
3562 if (strpos($auth, $query) !== false) {
3563 return true;
3565 $authplugin = get_auth_plugin($auth);
3566 $authtitle = $authplugin->get_title();
3567 if (strpos($textlib->strtolower($authtitle), $query) !== false) {
3568 return true;
3571 return false;
3574 function output_html($data, $query='') {
3575 global $CFG;
3578 // display strings
3579 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
3580 'settings', 'edit', 'name', 'enable', 'disable',
3581 'up', 'down', 'none'));
3582 $txt->updown = "$txt->up/$txt->down";
3584 $authsavailable = get_list_of_plugins('auth');
3585 get_enabled_auth_plugins(true); // fix the list of enabled auths
3586 if (empty($CFG->auth)) {
3587 $authsenabled = array();
3588 } else {
3589 $authsenabled = explode(',', $CFG->auth);
3592 // construct the display array, with enabled auth plugins at the top, in order
3593 $displayauths = array();
3594 $registrationauths = array();
3595 $registrationauths[''] = $txt->disable;
3596 foreach ($authsenabled as $auth) {
3597 $authplugin = get_auth_plugin($auth);
3598 /// Get the auth title (from core or own auth lang files)
3599 $authtitle = $authplugin->get_title();
3600 /// Apply titles
3601 $displayauths[$auth] = $authtitle;
3602 if ($authplugin->can_signup()) {
3603 $registrationauths[$auth] = $authtitle;
3607 foreach ($authsavailable as $auth) {
3608 if (array_key_exists($auth, $displayauths)) {
3609 continue; //already in the list
3611 $authplugin = get_auth_plugin($auth);
3612 /// Get the auth title (from core or own auth lang files)
3613 $authtitle = $authplugin->get_title();
3614 /// Apply titles
3615 $displayauths[$auth] = $authtitle;
3616 if ($authplugin->can_signup()) {
3617 $registrationauths[$auth] = $authtitle;
3621 $return = print_heading(get_string('actauthhdr', 'auth'), '', 3, 'main', true);
3622 $return .= print_box_start('generalbox authsui', '', true);
3624 $table = new object();
3625 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings);
3626 $table->align = array('left', 'center', 'center', 'center');
3627 $table->width = '90%';
3628 $table->data = array();
3630 //add always enabled plugins first
3631 $displayname = "<span>".$displayauths['manual']."</span>";
3632 $settings = "<a href=\"auth_config.php?auth=manual\">{$txt->settings}</a>";
3633 //$settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
3634 $table->data[] = array($displayname, '', '', $settings);
3635 $displayname = "<span>".$displayauths['nologin']."</span>";
3636 $settings = "<a href=\"auth_config.php?auth=nologin\">{$txt->settings}</a>";
3637 $table->data[] = array($displayname, '', '', $settings);
3640 // iterate through auth plugins and add to the display table
3641 $updowncount = 1;
3642 $authcount = count($authsenabled);
3643 $url = "auth.php?sesskey=" . sesskey();
3644 foreach ($displayauths as $auth => $name) {
3645 if ($auth == 'manual' or $auth == 'nologin') {
3646 continue;
3648 // hide/show link
3649 if (in_array($auth, $authsenabled)) {
3650 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
3651 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"disable\" /></a>";
3652 // $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\"><input type=\"checkbox\" checked /></a>";
3653 $enabled = true;
3654 $displayname = "<span>$name</span>";
3656 else {
3657 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
3658 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"enable\" /></a>";
3659 // $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\"><input type=\"checkbox\" /></a>";
3660 $enabled = false;
3661 $displayname = "<span class=\"dimmed_text\">$name</span>";
3664 // up/down link (only if auth is enabled)
3665 $updown = '';
3666 if ($enabled) {
3667 if ($updowncount > 1) {
3668 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
3669 $updown .= "<img src=\"{$CFG->pixpath}/t/up.gif\" alt=\"up\" /></a>&nbsp;";
3671 else {
3672 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
3674 if ($updowncount < $authcount) {
3675 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
3676 $updown .= "<img src=\"{$CFG->pixpath}/t/down.gif\" alt=\"down\" /></a>";
3678 else {
3679 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />";
3681 ++ $updowncount;
3684 // settings link
3685 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
3686 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
3687 } else {
3688 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
3691 // add a row to the table
3692 $table->data[] =array($displayname, $hideshow, $updown, $settings);
3694 $return .= print_table($table, true);
3695 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
3696 $return .= print_box_end(true);
3697 return highlight($query, $return);
3701 * Special class for filter administration.
3703 class admin_setting_managefilters extends admin_setting {
3704 function admin_setting_managefilters() {
3705 parent::admin_setting('filtersui', get_string('filtersettings', 'admin'), '', '');
3708 function get_setting() {
3709 return true;
3712 function get_defaultsetting() {
3713 return true;
3716 function write_setting($data) {
3717 // do not write any setting
3718 return '';
3721 function is_related($query) {
3722 if (parent::is_related($query)) {
3723 return true;
3726 $textlib = textlib_get_instance();
3727 $filterlocations = array('mod','filter');
3728 foreach ($filterlocations as $filterlocation) {
3729 $plugins = get_list_of_plugins($filterlocation);
3730 foreach ($plugins as $plugin) {
3731 if (strpos($plugin, $query) !== false) {
3732 return true;
3734 $name = get_string('filtername', $plugin);
3735 if (strpos($textlib->strtolower($name), $query) !== false) {
3736 return true;
3740 return false;
3743 function output_html($data, $query='') {
3744 global $CFG;
3746 $strname = get_string('name');
3747 $strhide = get_string('disable');
3748 $strshow = get_string('enable');
3749 $strhideshow = "$strhide/$strshow";
3750 $strsettings = get_string('settings');
3751 $strup = get_string('up');
3752 $strdown = get_string('down');
3753 $strupdown = "$strup/$strdown";
3755 // get a list of possible filters (and translate name if possible)
3756 // note filters can be in the dedicated filters area OR in their
3757 // associated modules
3758 $installedfilters = array();
3759 $filtersettings_new = array();
3760 $filtersettings_old = array();
3761 $filterlocations = array('mod','filter');
3762 foreach ($filterlocations as $filterlocation) {
3763 $plugins = get_list_of_plugins($filterlocation);
3764 foreach ($plugins as $plugin) {
3765 $pluginpath = "$CFG->dirroot/$filterlocation/$plugin/filter.php";
3766 $settingspath_new = "$CFG->dirroot/$filterlocation/$plugin/filtersettings.php";
3767 $settingspath_old = "$CFG->dirroot/$filterlocation/$plugin/filterconfig.html";
3768 if (is_readable($pluginpath)) {
3769 $name = trim(get_string("filtername", $plugin));
3770 if (empty($name) or ($name == '[[filtername]]')) {
3771 $textlib = textlib_get_instance();
3772 $name = $textlib->strtotitle($plugin);
3774 $installedfilters["$filterlocation/$plugin"] = $name;
3775 if (is_readable($settingspath_new)) {
3776 $filtersettings_new[] = "$filterlocation/$plugin";
3777 } else if (is_readable($settingspath_old)) {
3778 $filtersettings_old[] = "$filterlocation/$plugin";
3784 // get all the currently selected filters
3785 if (!empty($CFG->textfilters)) {
3786 $oldactivefilters = explode(',', $CFG->textfilters);
3787 $oldactivefilters = array_unique($oldactivefilters);
3788 } else {
3789 $oldactivefilters = array();
3792 // take this opportunity to clean up filters
3793 $activefilters = array();
3794 foreach ($oldactivefilters as $oldactivefilter) {
3795 if (!empty($oldactivefilter) and array_key_exists($oldactivefilter, $installedfilters)) {
3796 $activefilters[] = $oldactivefilter;
3800 // construct the display array with installed filters
3801 // at the top in the right order
3802 $displayfilters = array();
3803 foreach ($activefilters as $activefilter) {
3804 $name = $installedfilters[$activefilter];
3805 $displayfilters[$activefilter] = $name;
3807 foreach ($installedfilters as $key => $filter) {
3808 if (!array_key_exists($key, $displayfilters)) {
3809 $displayfilters[$key] = $filter;
3813 $return = print_heading(get_string('actfilterhdr', 'filters'), '', 3, 'main', true);
3814 $return .= print_box_start('generalbox filtersui', '', true);
3816 $table = new object();
3817 $table->head = array($strname, $strhideshow, $strupdown, $strsettings);
3818 $table->align = array('left', 'center', 'center', 'center');
3819 $table->width = '90%';
3820 $table->data = array();
3822 $filtersurl = "$CFG->wwwroot/$CFG->admin/filters.php?sesskey=".sesskey();
3823 $imgurl = "$CFG->pixpath/t";
3825 // iterate through filters adding to display table
3826 $updowncount = 1;
3827 $activefilterscount = count($activefilters);
3828 foreach ($displayfilters as $path => $name) {
3829 $upath = urlencode($path);
3830 // get hide/show link
3831 if (in_array($path, $activefilters)) {
3832 $hideshow = "<a href=\"$filtersurl&amp;action=hide&amp;filterpath=$upath\">";
3833 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"$strhide\" /></a>";
3834 $hidden = false;
3835 $displayname = "<span>$name</span>";
3837 else {
3838 $hideshow = "<a href=\"$filtersurl&amp;action=show&amp;filterpath=$upath\">";
3839 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"$strshow\" /></a>";
3840 $hidden = true;
3841 $displayname = "<span class=\"dimmed_text\">$name</span>";
3844 // get up/down link (only if not hidden)
3845 $updown = '';
3846 if (!$hidden) {
3847 if ($updowncount>1) {
3848 $updown .= "<a href=\"$filtersurl&amp;action=up&amp;filterpath=$upath\">";
3849 $updown .= "<img src=\"$imgurl/up.gif\" alt=\"$strup\" /></a>&nbsp;";
3851 else {
3852 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
3854 if ($updowncount<$activefilterscount) {
3855 $updown .= "<a href=\"$filtersurl&amp;action=down&amp;filterpath=$upath\">";
3856 $updown .= "<img src=\"$imgurl/down.gif\" alt=\"$strdown\" /></a>";
3858 else {
3859 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />";
3861 ++$updowncount;
3864 // settings link (if defined)
3865 $settings = '';
3866 if (in_array($path, $filtersettings_new)) {
3867 $settings = "<a href=\"settings.php?section=filtersetting".str_replace('/', '',$path)."\">$strsettings</a>";
3868 } else if (in_array($path, $filtersettings_old)) {
3869 $settings = "<a href=\"filter.php?filter=".urlencode($path)."\">$strsettings</a>";
3872 // write data into the table object
3873 $table->data[] = array($displayname, $hideshow, $updown, $settings);
3875 $return .= print_table($table, true);
3876 $return .= get_string('tablenosave', 'filters');
3877 $return .= print_box_end(true);
3878 return highlight($query, $return);
3883 * Initialise admin page - this function does require login and permission
3884 * checks specified in page definition.
3885 * This function must be called on each admin page before other code.
3886 * @param string $section name of page
3888 function admin_externalpage_setup($section) {
3890 global $CFG, $PAGE, $USER;
3891 require_once($CFG->libdir.'/blocklib.php');
3892 require_once($CFG->dirroot.'/'.$CFG->admin.'/pagelib.php');
3894 if ($site = get_site()) {
3895 require_login();
3896 } else {
3897 redirect($CFG->wwwroot.'/'.$CFG->admin.'/index.php');
3898 die;
3901 $adminroot =& admin_get_root(false, false); // settings not required for external pages
3902 $extpage =& $adminroot->locate($section);
3904 if (empty($extpage) or !is_a($extpage, 'admin_externalpage')) {
3905 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
3906 die;
3909 // this eliminates our need to authenticate on the actual pages
3910 if (!($extpage->check_access())) {
3911 print_error('accessdenied', 'admin');
3912 die;
3915 page_map_class(PAGE_ADMIN, 'page_admin');
3916 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
3917 $PAGE->init_extra($section); // hack alert!
3919 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
3921 if (!isset($USER->adminediting)) {
3922 $USER->adminediting = false;
3925 if ($PAGE->user_allowed_editing()) {
3926 if ($adminediting == 1) {
3927 $USER->adminediting = true;
3928 } elseif ($adminediting == 0) {
3929 $USER->adminediting = false;
3935 * Print header for admin page
3936 * @param string $focus focus element
3938 function admin_externalpage_print_header($focus='') {
3940 if (!is_string($focus)) {
3941 $focus = ''; // BC compatibility, there used to be adminroot parameter
3944 global $CFG, $PAGE, $SITE, $THEME;
3946 define('ADMIN_EXT_HEADER_PRINTED', 'true');
3948 if (!empty($SITE->fullname)) {
3949 $pageblocks = blocks_setup($PAGE);
3951 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
3952 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
3953 BLOCK_L_MAX_WIDTH);
3954 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
3955 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
3956 BLOCK_R_MAX_WIDTH);
3958 $PAGE->print_header('', $focus);
3959 echo '<table id="layout-table" summary=""><tr>';
3961 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
3962 foreach ($lt as $column) {
3963 $lt1[] = $column;
3964 if ($column == 'middle') break;
3966 foreach ($lt1 as $column) {
3967 switch ($column) {
3968 case 'left':
3969 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
3970 print_container_start();
3971 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
3972 print_container_end();
3973 echo '</td>';
3974 break;
3976 case 'middle':
3977 echo '<td id="middle-column">';
3978 print_container_start(true);
3979 $THEME->open_header_containers++; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
3980 break;
3982 case 'right':
3983 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
3984 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
3985 print_container_start();
3986 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
3987 print_container_end();
3988 echo '</td>';
3990 break;
3993 } else {
3994 print_header();
3999 * Print footer on admin page - please use normal print_footer() instead
4001 function admin_externalpage_print_footer() {
4003 global $CFG, $PAGE, $SITE, $THEME;
4005 define('ADMIN_EXT_FOOTER_PRINTED', 'true');
4007 if (!empty($SITE->fullname)) {
4008 $pageblocks = blocks_setup($PAGE);
4009 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
4010 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
4011 BLOCK_L_MAX_WIDTH);
4012 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
4013 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
4014 BLOCK_R_MAX_WIDTH);
4016 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
4017 foreach ($lt as $column) {
4018 if ($column != 'middle') {
4019 array_shift($lt);
4020 } else if ($column == 'middle') {
4021 break;
4024 foreach ($lt as $column) {
4025 switch ($column) {
4026 case 'left':
4027 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
4028 print_container_start();
4029 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
4030 print_container_end();
4031 echo '</td>';
4032 break;
4034 case 'middle':
4035 print_container_end();
4036 $THEME->open_header_containers--; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
4037 echo '</td>';
4038 break;
4040 case 'right':
4041 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
4042 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
4043 print_container_start();
4044 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
4045 print_container_end();
4046 echo '</td>';
4048 break;
4051 echo '</tr></table>';
4053 print_footer();
4057 * Returns the reference to admin tree root
4058 * @return reference
4060 function &admin_get_root($reload=false, $requirefulltree=true) {
4061 global $CFG;
4063 static $ADMIN = NULL;
4065 if (!is_null($ADMIN)) {
4066 $olderrors = $ADMIN->errors;
4067 $oldsearch = $ADMIN->search;
4068 $oldfulltree = $ADMIN->fulltree;
4069 } else {
4070 $olderrors = array();
4071 $oldsearch = '';
4072 $oldfulltree = false;
4075 if ($reload or ($requirefulltree and !$oldfulltree)) {
4076 $ADMIN = NULL;
4079 if (is_null($ADMIN)) {
4080 // start the admin tree!
4081 $ADMIN = new admin_root();
4082 // array of error messages and search query
4083 $ADMIN->errors = $olderrors;
4084 $ADMIN->search = $oldsearch;
4085 if ($requirefulltree) {
4086 $ADMIN->fulltree = true;
4087 } else {
4088 $ADMIN->fulltree = $oldfulltree;
4091 // we process this file first to create categories first and in correct order
4092 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
4094 // now we process all other files in admin/settings to build the admin tree
4095 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
4096 if ($file != $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
4097 include($file);
4100 if (file_exists($CFG->dirroot.'/local/settings.php')) {
4101 include_once($CFG->dirroot.'/local/settings.php');
4105 return $ADMIN;
4108 /// settings utility functions
4111 * This function applies default settings.
4112 * @param object $node, NULL means complete tree
4113 * @param bool $uncoditional if true overrides all values with defaults
4114 * @return void
4116 function admin_apply_default_settings($node=NULL, $unconditional=true) {
4117 global $CFG;
4119 if (is_null($node)) {
4120 $node =& admin_get_root();
4123 if (is_a($node, 'admin_category')) {
4124 $entries = array_keys($node->children);
4125 foreach ($entries as $entry) {
4126 admin_apply_default_settings($node->children[$entry], $unconditional);
4129 } else if (is_a($node, 'admin_settingpage')) {
4130 foreach ($node->settings as $setting) {
4131 if (!$unconditional and !is_null($setting->get_setting())) {
4132 //do not override existing defaults
4133 continue;
4135 $defaultsetting = $setting->get_defaultsetting();
4136 if (is_null($defaultsetting)) {
4137 // no value yet - default maybe applied after admin user creation or in upgradesettings
4138 continue;
4140 $setting->write_setting($defaultsetting);
4146 * Store changed settings, this function updates the errors variable in $ADMIN
4147 * @param object $formdata from form (without magic quotes)
4148 * @return int number of changed settings
4150 function admin_write_settings($formdata) {
4151 global $CFG, $SITE, $COURSE;
4153 $olddbsessions = !empty($CFG->dbsessions);
4154 $formdata = (array)stripslashes_recursive($formdata);
4156 $data = array();
4157 foreach ($formdata as $fullname=>$value) {
4158 if (strpos($fullname, 's_') !== 0) {
4159 continue; // not a config value
4161 $data[$fullname] = $value;
4164 $adminroot =& admin_get_root();
4165 $settings = admin_find_write_settings($adminroot, $data);
4167 $count = 0;
4168 foreach ($settings as $fullname=>$setting) {
4169 $original = serialize($setting->get_setting()); // comparison must work for arrays too
4170 $error = $setting->write_setting($data[$fullname]);
4171 if ($error !== '') {
4172 $adminroot->errors[$fullname] = new object();
4173 $adminroot->errors[$fullname]->data = $data[$fullname];
4174 $adminroot->errors[$fullname]->id = $setting->get_id();
4175 $adminroot->errors[$fullname]->error = $error;
4177 if ($original !== serialize($setting->get_setting())) {
4178 $count++;
4179 $callbackfunction = $setting->updatedcallback;
4180 if (function_exists($callbackfunction)) {
4181 $callbackfunction($fullname);
4186 if ($olddbsessions != !empty($CFG->dbsessions)) {
4187 require_logout();
4190 // now update $SITE - it might have been changed
4191 $SITE = get_record('course', 'id', $SITE->id);
4192 $COURSE = clone($SITE);
4194 // now reload all settings - some of them might depend on the changed
4195 admin_get_root(true);
4196 return $count;
4200 * Internal recursive function - finds all settings from submitted form
4202 function admin_find_write_settings($node, $data) {
4203 $return = array();
4205 if (empty($data)) {
4206 return $return;
4209 if (is_a($node, 'admin_category')) {
4210 $entries = array_keys($node->children);
4211 foreach ($entries as $entry) {
4212 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
4215 } else if (is_a($node, 'admin_settingpage')) {
4216 foreach ($node->settings as $setting) {
4217 $fullname = $setting->get_full_name();
4218 if (array_key_exists($fullname, $data)) {
4219 $return[$fullname] = $setting;
4225 return $return;
4229 * Internal function - prints the search results
4231 function admin_search_settings_html($query) {
4232 global $CFG;
4234 $textlib = textlib_get_instance();
4235 if ($textlib->strlen($query) < 2) {
4236 return '';
4238 $query = $textlib->strtolower($query);
4240 $adminroot =& admin_get_root();
4241 $findings = $adminroot->search($query);
4242 $return = '';
4243 $savebutton = false;
4245 foreach ($findings as $found) {
4246 $page = $found->page;
4247 $settings = $found->settings;
4248 if ($page->is_hidden()) {
4249 // hidden pages are not displayed in search results
4250 continue;
4252 if (is_a($page, 'admin_externalpage')) {
4253 $return .= print_heading(get_string('searchresults','admin').' - <a href="'.$page->url.'">'.highlight($query, $page->visiblename).'</a>', '', 2, 'main', true);
4254 } else if (is_a($page, 'admin_settingpage')) {
4255 $return .= print_heading(get_string('searchresults','admin').' - <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section='.$page->name.'">'.highlight($query, $page->visiblename).'</a>', '', 2, 'main', true);
4256 } else {
4257 continue;
4259 if (!empty($settings)) {
4260 $savebutton = true;
4261 $return .= '<fieldset class="adminsettings">'."\n";
4262 foreach ($settings as $setting) {
4263 $return .= '<div class="clearer"><!-- --></div>'."\n";
4264 $fullname = $setting->get_full_name();
4265 if (array_key_exists($fullname, $adminroot->errors)) {
4266 $data = $adminroot->errors[$fullname]->data;
4267 } else {
4268 $data = $setting->get_setting();
4269 if (is_null($data)) {
4270 $data = $setting->get_defaultsetting();
4273 $return .= $setting->output_html($data, $query);
4275 $return .= '</fieldset>';
4279 if ($savebutton) {
4280 $return .= '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges','admin').'" /></div>';
4283 return $return;
4287 * Internal function - prints list of uninitialised settings
4289 function admin_output_new_settings_by_page($node) {
4290 $return = '';
4292 if (is_a($node, 'admin_category')) {
4293 $entries = array_keys($node->children);
4294 foreach ($entries as $entry) {
4295 $return .= admin_output_new_settings_by_page($node->children[$entry]);
4298 } else if (is_a($node, 'admin_settingpage')) {
4299 $newsettings = array();
4300 foreach ($node->settings as $setting) {
4301 if (is_null($setting->get_setting())) {
4302 $newsettings[] = $setting;
4305 if (count($newsettings) > 0) {
4306 $adminroot =& admin_get_root();
4307 $return .= print_heading(get_string('upgradesettings','admin').' - '.$node->visiblename, '', 2, 'main', true);
4308 $return .= '<fieldset class="adminsettings">'."\n";
4309 foreach ($newsettings as $setting) {
4310 $fullname = $setting->get_full_name();
4311 if (array_key_exists($fullname, $adminroot->errors)) {
4312 $data = $adminroot->errors[$fullname]->data;
4313 } else {
4314 $data = $setting->get_setting();
4315 if (is_null($data)) {
4316 $data = $setting->get_defaultsetting();
4319 $return .= '<div class="clearer"><!-- --></div>'."\n";
4320 $return .= $setting->output_html($data);
4322 $return .= '</fieldset>';
4326 return $return;
4330 * Unconditionally applies default admin settings in main config table
4331 * @param array $defaults array of string values
4333 function apply_default_exception_settings($defaults) {
4334 foreach($defaults as $key => $value) {
4335 set_config($key, $value, NULL);
4340 * Format admin settings
4341 * @param string $object setting
4342 * @param string $title label element
4343 * @param string $form form fragment, html code - not highlighed automaticaly
4344 * @param string $description
4345 * @param bool $label link label to id
4346 * @param string $warning warning text
4347 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string
4348 * @param string $query search query to be highlighted
4350 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
4351 global $CFG;
4353 $name = $setting->name;
4354 $fullname = $setting->get_full_name();
4356 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
4357 if ($label) {
4358 $labelfor = 'for = "'.$setting->get_id().'"';
4359 } else {
4360 $labelfor = '';
4363 if (empty($setting->plugin) and array_key_exists($name, $CFG->config_php_settings)) {
4364 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
4365 } else {
4366 $override = '';
4369 if ($warning !== '') {
4370 $warning = '<div class="form-warning">'.$warning.'</div>';
4373 if (is_null($defaultinfo)) {
4374 $defaultinfo = '';
4375 } else {
4376 if ($defaultinfo === '') {
4377 $defaultinfo = get_string('emptysettingvalue', 'admin');
4379 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
4380 $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>';
4384 $str = '
4385 <div class="form-item clearfix" id="admin-'.$setting->name.'">
4386 <div class="form-label">
4387 <label '.$labelfor.'>'.highlightfast($query, $title).'<span class="form-shortname">'.highlightfast($query, $name).'</span>
4388 '.$override.$warning.'
4389 </label>
4390 </div>
4391 <div class="form-setting">'.$form.$defaultinfo.'</div>
4392 <div class="form-description">'.highlight($query, $description).'</div>
4393 </div>';
4395 $adminroot =& admin_get_root();
4396 if (array_key_exists($fullname, $adminroot->errors)) {
4397 $str = '<fieldset class="error"><legend>'.$adminroot->errors[$fullname]->error.'</legend>'.$str.'</fieldset>';
4400 return $str;
4404 * Try to upgrade the given language pack (or current language)
4405 * If it doesn't work, fail silently and return false
4407 function upgrade_language_pack($lang='') {
4408 global $CFG;
4410 if (empty($lang)) {
4411 $lang = current_language();
4414 if ($lang == 'en_utf8') {
4415 return true; // Nothing to do
4418 notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
4420 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
4421 @mkdir ($CFG->dataroot.'/lang/');
4423 require_once($CFG->libdir.'/componentlib.class.php');
4425 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
4426 $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
4428 if ($status == COMPONENT_INSTALLED) {
4429 debugging('Downloading successful: '.$lang);
4430 @unlink($CFG->dataroot.'/cache/languages');
4431 return true;
4435 return false;
4439 * Based on find_new_settings{@link ()} in upgradesettings.php
4440 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
4442 * @param string $node The node at which to start searching.
4443 * @return boolen true if any settings haven't been initialised, false if they all have
4445 function any_new_admin_settings($node) {
4447 if (is_a($node, 'admin_category')) {
4448 $entries = array_keys($node->children);
4449 foreach ($entries as $entry) {
4450 if (any_new_admin_settings($node->children[$entry])){
4451 return true;
4455 } else if (is_a($node, 'admin_settingpage')) {
4456 foreach ($node->settings as $setting) {
4457 if ($setting->get_setting() === NULL) {
4458 return true;
4463 return false;
4468 * Moved from admin/replace.php so that we can use this in cron
4469 * @param string $search - string to look for (with magic quotes)
4470 * @param string $replace - string to replace (with magic quotes)
4471 * @return bool - success or fail
4473 function db_replace($search, $replace) {
4475 global $db, $CFG;
4477 /// Turn off time limits, sometimes upgrades can be slow.
4478 @set_time_limit(0);
4479 @ob_implicit_flush(true);
4480 while(@ob_end_flush());
4482 if (!$tables = $db->Metatables() ) { // No tables yet at all.
4483 return false;
4485 foreach ($tables as $table) {
4487 if (in_array($table, array($CFG->prefix.'config'))) { // Don't process these
4488 continue;
4491 if ($columns = $db->MetaColumns($table, false)) {
4492 foreach ($columns as $column => $data) {
4493 if (in_array($data->type, array('text','mediumtext','longtext','varchar'))) { // Text stuff only
4494 $db->debug = true;
4495 execute_sql("UPDATE $table SET $column = REPLACE($column, '$search', '$replace');");
4496 $db->debug = false;
4502 return true;
4506 * Prints tables of detected plugins, one table per plugin type,
4507 * and prints whether they are part of the standard Moodle
4508 * distribution or not.
4510 function print_plugin_tables() {
4511 $plugins_standard = array();
4512 $plugins_standard['mod'] = array('assignment',
4513 'chat',
4514 'choice',
4515 'data',
4516 'exercise',
4517 'forum',
4518 'glossary',
4519 'hotpot',
4520 'journal',
4521 'label',
4522 'lams',
4523 'lesson',
4524 'quiz',
4525 'resource',
4526 'scorm',
4527 'survey',
4528 'wiki',
4529 'workshop');
4531 $plugins_standard['blocks'] = array('activity_modules',
4532 'admin',
4533 'admin_bookmarks',
4534 'admin_tree',
4535 'blog_menu',
4536 'blog_tags',
4537 'calendar_month',
4538 'calendar_upcoming',
4539 'course_list',
4540 'course_summary',
4541 'glossary_random',
4542 'html',
4543 'loancalc',
4544 'login',
4545 'mentees',
4546 'messages',
4547 'mnet_hosts',
4548 'news_items',
4549 'online_users',
4550 'participants',
4551 'quiz_results',
4552 'recent_activity',
4553 'rss_client',
4554 'search',
4555 'search_forums',
4556 'section_links',
4557 'site_main_menu',
4558 'social_activities',
4559 'tag_flickr',
4560 'tag_youtube',
4561 'tags');
4563 $plugins_standard['filter'] = array('activitynames',
4564 'algebra',
4565 'censor',
4566 'emailprotect',
4567 'filter',
4568 'mediaplugin',
4569 'multilang',
4570 'tex',
4571 'tidy');
4573 $plugins_installed = array();
4574 $installed_mods = get_records_list('modules', '', '', '', 'name');
4575 $installed_blocks = get_records_list('block', '', '', '', 'name');
4577 foreach($installed_mods as $mod) {
4578 $plugins_installed['mod'][] = $mod->name;
4581 foreach($installed_blocks as $block) {
4582 $plugins_installed['blocks'][] = $block->name;
4585 $plugins_ondisk = array();
4586 $plugins_ondisk['mod'] = get_list_of_plugins('mod', 'db');
4587 $plugins_ondisk['blocks'] = get_list_of_plugins('blocks', 'db');
4588 $plugins_ondisk['filter'] = get_list_of_plugins('filter', 'db');
4590 $strstandard = get_string('standard');
4591 $strnonstandard = get_string('nonstandard');
4592 $strmissingfromdisk = '(' . get_string('missingfromdisk') . ')';
4593 $strabouttobeinstalled = '(' . get_string('abouttobeinstalled') . ')';
4595 $html = '';
4597 $html .= '<table class="generaltable plugincheckwrapper" cellspacing="4" cellpadding="1"><tr valign="top">';
4599 foreach ($plugins_ondisk as $cat => $list_ondisk) {
4600 $strcaption = get_string($cat);
4601 if ($cat == 'mod') {
4602 $strcaption = get_string('activitymodule');
4603 } elseif ($cat == 'filter') {
4604 $strcaption = get_string('managefilters');
4607 $html .= '<td><table class="plugincompattable generaltable boxaligncenter" cellspacing="1" cellpadding="5" '
4608 . 'id="' . $cat . 'compattable" summary="compatibility table"><caption>' . $strcaption . '</caption>' . "\n";
4609 $html .= '<tr class="r0"><th class="header c0">' . get_string('directory') . "</th>\n"
4610 . '<th class="header c1">' . get_string('name') . "</th>\n"
4611 . '<th class="header c2">' . get_string('status') . "</th>\n</tr>\n";
4613 $row = 1;
4615 foreach ($list_ondisk as $k => $plugin) {
4616 $status = 'ok';
4617 $standard = 'standard';
4618 $note = '';
4620 if (!in_array($plugin, $plugins_standard[$cat])) {
4621 $standard = 'nonstandard';
4622 $status = 'warning';
4625 // Get real name and full path of plugin
4626 $plugin_name = "[[$plugin]]";
4628 $plugin_path = "$cat/$plugin";
4630 $plugin_name = get_plugin_name($plugin, $cat);
4632 // Determine if the plugin is about to be installed
4633 if ($cat != 'filter' && !in_array($plugin, $plugins_installed[$cat])) {
4634 $note = $strabouttobeinstalled;
4635 $plugin_name = $plugin;
4638 $html .= "<tr class=\"r$row\">\n"
4639 . "<td class=\"cell c0\">$plugin_path</td>\n"
4640 . "<td class=\"cell c1\">$plugin_name</td>\n"
4641 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $note</td>\n</tr>\n";
4642 $row++;
4644 // If the plugin was both on disk and in the db, unset the value from the installed plugins list
4645 if ($key = array_search($plugin, $plugins_installed[$cat])) {
4646 unset($plugins_installed[$cat][$key]);
4650 // If there are plugins left in the plugins_installed list, it means they are missing from disk
4651 foreach ($plugins_installed[$cat] as $k => $missing_plugin) {
4652 // Make sure the plugin really is missing from disk
4653 if (!in_array($missing_plugin, $plugins_ondisk[$cat])) {
4654 $standard = 'standard';
4655 $status = 'warning';
4657 if (!in_array($missing_plugin, $plugins_standard[$cat])) {
4658 $standard = 'nonstandard';
4661 $plugin_name = $missing_plugin;
4662 $html .= "<tr class=\"r$row\">\n"
4663 . "<td class=\"cell c0\">?</td>\n"
4664 . "<td class=\"cell c1\">$plugin_name</td>\n"
4665 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $strmissingfromdisk</td>\n</tr>\n";
4666 $row++;
4670 $html .= '</table></td>';
4673 $html .= '</tr></table><br />';
4675 echo $html;