Fixes to the PaintWeb cron task.
[moodle/mihaisucan.git] / lib / adminlib.php
bloba8e12774ac4f48000c15fa3ba0642b43dc8ef3cc
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 define('INSECURE_DATAROOT_WARNING', 1);
13 define('INSECURE_DATAROOT_ERROR', 2);
15 function upgrade_main_savepoint($result, $version) {
16 global $CFG;
18 if ($result) {
19 if ($CFG->version >= $version) {
20 // something really wrong is going on in main upgrade script
21 error("Upgrade savepoint: Can not upgrade main version from $CFG->version to $version.");
23 set_config('version', $version);
24 } else {
25 notify ("Upgrade savepoint: Error during main upgrade to version $version");
29 function upgrade_mod_savepoint($result, $version, $type) {
30 //TODO
33 function upgrade_plugin_savepoint($result, $version, $type, $dir) {
34 //TODO
37 function upgrade_backup_savepoint($result, $version) {
38 //TODO
41 function upgrade_blocks_savepoint($result, $version, $type) {
42 //TODO
45 /**
46 * Upgrade plugins
48 * @uses $db
49 * @uses $CFG
50 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
51 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
52 * @param string $return The url to prompt the user to continue to
54 function upgrade_plugins($type, $dir, $return) {
55 global $CFG, $db;
57 /// Let's know if the header has been printed, so the funcion is being called embedded in an outer page
58 $embedded = defined('HEADER_PRINTED');
60 $plugs = get_list_of_plugins($dir);
61 $updated_plugins = false;
62 $strpluginsetup = get_string('pluginsetup');
64 foreach ($plugs as $plug) {
66 $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
68 unset($plugin);
70 if (is_readable($fullplug .'/version.php')) {
71 include_once($fullplug .'/version.php'); // defines $plugin with version etc
72 } else {
73 continue; // Nothing to do.
76 $oldupgrade = false;
77 $newupgrade = false;
78 if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) {
79 include_once($fullplug . '/db/'. $CFG->dbtype . '.php'); // defines old upgrading function
80 $oldupgrade = true;
82 if (is_readable($fullplug . '/db/upgrade.php')) {
83 include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
84 $newupgrade = true;
87 if (!isset($plugin)) {
88 continue;
91 if (!empty($plugin->requires)) {
92 if ($plugin->requires > $CFG->version) {
93 $info = new object();
94 $info->pluginname = $plug;
95 $info->pluginversion = $plugin->version;
96 $info->currentmoodle = $CFG->version;
97 $info->requiremoodle = $plugin->requires;
98 if (!$updated_plugins && !$embedded) {
99 print_header($strpluginsetup, $strpluginsetup,
100 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
101 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
103 upgrade_log_start();
104 notify(get_string('pluginrequirementsnotmet', 'error', $info));
105 $updated_plugins = true;
106 continue;
110 $plugin->name = $plug; // The name MUST match the directory
112 $pluginversion = $type.'_'.$plug.'_version';
114 if (!isset($CFG->$pluginversion)) {
115 set_config($pluginversion, 0);
118 if ($CFG->$pluginversion == $plugin->version) {
119 // do nothing
120 } else if ($CFG->$pluginversion < $plugin->version) {
121 if (!$updated_plugins && !$embedded) {
122 print_header($strpluginsetup, $strpluginsetup,
123 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
124 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
126 $updated_plugins = true;
127 upgrade_log_start();
128 print_heading($dir.'/'. $plugin->name .' plugin needs upgrading');
129 $db->debug = true;
130 @set_time_limit(0); // To allow slow databases to complete the long SQL
132 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
133 /// Both old .sql files and new install.xml are supported
134 /// but we priorize install.xml (XMLDB) if present
135 $status = false;
136 if (file_exists($fullplug . '/db/install.xml')) {
137 $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
138 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
139 $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
140 } else {
141 $status = true;
144 $db->debug = false;
145 /// Continue with the instalation, roles and other stuff
146 if ($status) {
147 /// OK so far, now update the plugins record
148 set_config($pluginversion, $plugin->version);
150 /// Install capabilities
151 if (!update_capabilities($type.'/'.$plug)) {
152 error('Could not set up the capabilities for '.$plugin->name.'!');
154 /// Install events
155 events_update_definition($type.'/'.$plug);
157 /// Run local install function if there is one
158 if (is_readable($fullplug .'/lib.php')) {
159 include_once($fullplug .'/lib.php');
160 $installfunction = $plugin->name.'_install';
161 if (function_exists($installfunction)) {
162 if (! $installfunction() ) {
163 notify('Encountered a problem running install function for '.$plugin->name.'!');
168 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
169 } else {
170 notify('Installing '. $plugin->name .' FAILED!');
172 } else { // Upgrade existing install
173 /// Run de old and new upgrade functions for the module
174 $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade';
175 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
177 /// First, the old function if exists
178 $oldupgrade_status = true;
179 if ($oldupgrade && function_exists($oldupgrade_function)) {
180 $db->debug = true;
181 $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
182 } else if ($oldupgrade) {
183 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
184 $fullplug . '/db/' . $CFG->dbtype . '.php');
187 /// Then, the new function if exists and the old one was ok
188 $newupgrade_status = true;
189 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
190 $db->debug = true;
191 $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
192 } else if ($newupgrade) {
193 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
194 $fullplug . '/db/upgrade.php');
197 $db->debug=false;
198 /// Now analyze upgrade results
199 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
200 // OK so far, now update the plugins record
201 set_config($pluginversion, $plugin->version);
202 if (!update_capabilities($type.'/'.$plug)) {
203 error('Could not update '.$plugin->name.' capabilities!');
205 events_update_definition($type.'/'.$plug);
206 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
207 } else {
208 notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
211 echo '<hr />';
212 } else {
213 upgrade_log_start();
214 error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
218 upgrade_log_finish();
220 if ($updated_plugins && !$embedded) {
221 print_continue($return);
222 print_footer('none');
223 die;
228 * Find and check all modules and load them up or upgrade them if necessary
230 * @uses $db
231 * @uses $CFG
232 * @param string $return The url to prompt the user to continue to
233 * @todo Finish documenting this function
235 function upgrade_activity_modules($return) {
237 global $CFG, $db;
239 if (!$mods = get_list_of_plugins('mod') ) {
240 error('No modules installed!');
243 $updated_modules = false;
244 $strmodulesetup = get_string('modulesetup');
246 foreach ($mods as $mod) {
248 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
249 continue;
252 $fullmod = $CFG->dirroot .'/mod/'. $mod;
254 unset($module);
256 if ( is_readable($fullmod .'/version.php')) {
257 include_once($fullmod .'/version.php'); // defines $module with version etc
258 } else {
259 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
260 continue;
263 $oldupgrade = false;
264 $newupgrade = false;
265 if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
266 include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function
267 $oldupgrade = true;
269 if ( is_readable($fullmod . '/db/upgrade.php')) {
270 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
271 $newupgrade = true;
274 if (!isset($module)) {
275 continue;
278 if (!empty($module->requires)) {
279 if ($module->requires > $CFG->version) {
280 $info = new object();
281 $info->modulename = $mod;
282 $info->moduleversion = $module->version;
283 $info->currentmoodle = $CFG->version;
284 $info->requiremoodle = $module->requires;
285 if (!$updated_modules) {
286 print_header($strmodulesetup, $strmodulesetup,
287 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
288 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
290 upgrade_log_start();
291 notify(get_string('modulerequirementsnotmet', 'error', $info));
292 $updated_modules = true;
293 continue;
297 $module->name = $mod; // The name MUST match the directory
299 include_once($fullmod.'/lib.php'); // defines upgrading and/or installing functions
301 if ($currmodule = get_record('modules', 'name', $module->name)) {
302 if ($currmodule->version == $module->version) {
303 // do nothing
304 } else if ($currmodule->version < $module->version) {
305 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
306 if (!$oldupgrade && !$newupgrade) {
307 notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' .
308 $fullmod . '/db/upgrade.php were not readable');
309 continue;
311 if (!$updated_modules) {
312 print_header($strmodulesetup, $strmodulesetup,
313 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
314 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
316 upgrade_log_start();
317 print_heading($module->name .' module needs upgrading');
319 /// Run de old and new upgrade functions for the module
320 $oldupgrade_function = $module->name . '_upgrade';
321 $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
323 /// First, the old function if exists
324 $oldupgrade_status = true;
325 if ($oldupgrade && function_exists($oldupgrade_function)) {
326 $db->debug = true;
327 $oldupgrade_status = $oldupgrade_function($currmodule->version, $module);
328 if (!$oldupgrade_status) {
329 notify ('Upgrade function ' . $oldupgrade_function .
330 ' did not complete successfully.');
332 } else if ($oldupgrade) {
333 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
334 $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php');
337 /// Then, the new function if exists and the old one was ok
338 $newupgrade_status = true;
339 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
340 $db->debug = true;
341 $newupgrade_status = $newupgrade_function($currmodule->version, $module);
342 } else if ($newupgrade && $oldupgrade_status) {
343 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
344 $mod . ': ' . $fullmod . '/db/upgrade.php');
347 $db->debug=false;
348 /// Now analyze upgrade results
349 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
350 // OK so far, now update the modules record
351 $module->id = $currmodule->id;
352 if (! update_record('modules', $module)) {
353 error('Could not update '. $module->name .' record in modules table!');
355 remove_dir($CFG->dataroot . '/cache', true); // flush cache
356 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
357 echo '<hr />';
358 } else {
359 notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
362 /// Update the capabilities table?
363 if (!update_capabilities('mod/'.$module->name)) {
364 error('Could not update '.$module->name.' capabilities!');
366 events_update_definition('mod/'.$module->name);
368 $updated_modules = true;
370 } else {
371 upgrade_log_start();
372 error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
375 } else { // module not installed yet, so install it
376 if (!$updated_modules) {
377 print_header($strmodulesetup, $strmodulesetup,
378 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
379 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
381 upgrade_log_start();
382 print_heading($module->name);
383 $updated_modules = true;
384 $db->debug = true;
385 @set_time_limit(0); // To allow slow databases to complete the long SQL
387 /// Both old .sql files and new install.xml are supported
388 /// but we priorize install.xml (XMLDB) if present
389 if (file_exists($fullmod . '/db/install.xml')) {
390 $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
391 } else {
392 $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method
395 $db->debug = false;
397 /// Continue with the installation, roles and other stuff
398 if ($status) {
399 if ($module->id = insert_record('modules', $module)) {
401 /// Capabilities
402 if (!update_capabilities('mod/'.$module->name)) {
403 error('Could not set up the capabilities for '.$module->name.'!');
406 /// Events
407 events_update_definition('mod/'.$module->name);
409 /// Run local install function if there is one
410 $installfunction = $module->name.'_install';
411 if (function_exists($installfunction)) {
412 if (! $installfunction() ) {
413 notify('Encountered a problem running install function for '.$module->name.'!');
417 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
418 echo '<hr />';
419 } else {
420 error($module->name .' module could not be added to the module list!');
422 } else {
423 error($module->name .' tables could NOT be set up successfully!');
427 /// Check submodules of this module if necessary
429 $submoduleupgrade = $module->name.'_upgrade_submodules';
430 if (function_exists($submoduleupgrade)) {
431 $submoduleupgrade();
435 /// Run any defaults or final code that is necessary for this module
437 if ( is_readable($fullmod .'/defaults.php')) {
438 // Insert default values for any important configuration variables
439 unset($defaults);
440 include($fullmod .'/defaults.php'); // include here means execute, not library include
441 if (!empty($defaults)) {
442 foreach ($defaults as $name => $value) {
443 if (!isset($CFG->$name)) {
444 set_config($name, $value);
451 upgrade_log_finish(); // finish logging if started
453 if ($updated_modules) {
454 print_continue($return);
455 print_footer('none');
456 die;
461 * Try to obtain or release the cron lock.
463 * @param string $name name of lock
464 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionaly
465 * @param bool $ignorecurrent ignore current lock state, usually entend previous lock
466 * @return bool true if lock obtained
468 function set_cron_lock($name, $until, $ignorecurrent=false) {
469 if (empty($name)) {
470 debugging("Tried to get a cron lock for a null fieldname");
471 return false;
474 // remove lock by force == remove from config table
475 if (is_null($until)) {
476 set_config($name, null);
477 return true;
480 if (!$ignorecurrent) {
481 // read value from db - other processes might have changed it
482 $value = get_field('config', 'value', 'name', $name);
484 if ($value and $value > time()) {
485 //lock active
486 return false;
490 set_config($name, $until);
491 return true;
494 function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
495 static $thisbarid;
496 static $starttime;
497 static $lasttime;
499 if ($total < 2) { // No need to show anything
500 return;
503 // Are we done?
504 if ($done >= $total) {
505 $done = $total;
506 if (!empty($thisbarid)) {
507 $donetext .= ' ('.$done.'/'.$total.') '.get_string('success');
508 print_progress_redraw($thisbarid, $done, $total, 500, $donetext);
509 $thisbarid = $starttime = $lasttime = NULL;
511 return;
514 if (empty($starttime)) {
515 $starttime = $lasttime = time();
516 $lasttime = $starttime - $updatetime;
517 $thisbarid = uniqid();
518 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
519 echo '<div id="bar'.$thisbarid.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
520 echo '<div id="slider'.$thisbarid.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
521 echo '</div>';
522 echo '<div id="text'.$thisbarid.'" align="center" style="width:500px;"></div>';
523 echo '</td></tr></table>';
524 echo '</div>';
527 $now = time();
529 if ($done && (($now - $lasttime) >= $updatetime)) {
530 $elapsedtime = $now - $starttime;
531 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
532 $percentage = round((float)$done / (float)$total, 2);
533 $width = (int)(500 * $percentage);
535 if ($projectedtime > 10) {
536 $projectedtext = ' Ending: '.format_time($projectedtime);
537 } else {
538 $projectedtext = '';
541 $donetext .= ' ('.$done.'/'.$total.') '.$projectedtext;
542 print_progress_redraw($thisbarid, $done, $total, $width, $donetext);
544 $lasttime = $now;
548 // Don't call this function directly, it's called from print_progress.
549 function print_progress_redraw($thisbarid, $done, $total, $width, $donetext='') {
550 if (empty($thisbarid)) {
551 return;
553 echo '<script>';
554 echo 'document.getElementById("text'.$thisbarid.'").innerHTML = "'.addslashes($donetext).'";'."\n";
555 echo 'document.getElementById("slider'.$thisbarid.'").style.width = \''.$width.'px\';'."\n";
556 echo '</script>';
559 function upgrade_get_javascript() {
560 global $CFG;
562 if (!empty($_SESSION['installautopilot'])) {
563 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
564 } else {
565 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
567 $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>';
569 return $linktoscrolltoerrors;
572 function create_admin_user() {
573 global $CFG, $USER;
575 if (empty($CFG->rolesactive)) { // No admin user yet.
577 $user = new object();
578 $user->auth = 'manual';
579 $user->firstname = get_string('admin');
580 $user->lastname = get_string('user');
581 $user->username = 'admin';
582 $user->password = hash_internal_user_password('admin');
583 $user->email = 'root@localhost';
584 $user->confirmed = 1;
585 $user->mnethostid = $CFG->mnet_localhost_id;
586 $user->lang = $CFG->lang;
587 $user->maildisplay = 1;
588 $user->timemodified = time();
590 if (!$user->id = insert_record('user', $user)) {
591 error('SERIOUS ERROR: Could not create admin user record !!!');
594 if (!$user = get_record('user', 'id', $user->id)) { // Double check.
595 error('User ID was incorrect (can\'t find it)');
598 // Assign the default admin roles to the new user.
599 if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW)) {
600 error('No admin role could be found');
602 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
603 foreach ($adminroles as $adminrole) {
604 role_assign($adminrole->id, $user->id, 0, $sitecontext->id);
607 set_config('rolesactive', 1);
609 // Log the user in.
610 $USER = get_complete_user_data('username', 'admin');
611 $USER->newadminuser = 1;
612 load_all_capabilities();
614 redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id"); // Edit thyself
615 } else {
616 error('Can not create admin!');
620 ////////////////////////////////////////////////
621 /// upgrade logging functions
622 ////////////////////////////////////////////////
624 $upgradeloghandle = false;
625 $upgradelogbuffer = '';
626 // I did not find out how to use static variable in callback function,
627 // the problem was that I could not flush the static buffer :-(
628 global $upgradeloghandle, $upgradelogbuffer;
631 * Check if upgrade is already running.
633 * If anything goes wrong due to missing call to upgrade_log_finish()
634 * just restart the browser.
636 * @param string warning message indicating upgrade is already running
637 * @param int page reload timeout
639 function upgrade_check_running($message, $timeout) {
640 if (!empty($_SESSION['upgraderunning'])) {
641 print_header();
642 redirect(me(), $message, $timeout);
647 * Start logging of output into file (if not disabled) and
648 * prevent aborting and concurrent execution of upgrade script.
650 * Please note that you can not write into session variables after calling this function!
652 * This function may be called repeatedly.
654 function upgrade_log_start() {
655 global $CFG, $upgradeloghandle;
657 if (!empty($_SESSION['upgraderunning'])) {
658 return; // logging already started
661 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
662 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
663 if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
664 session_write_close(); // from now on user can reload page - will be displayed warning
666 make_upload_directory('upgradelogs');
667 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
668 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
672 * Terminate logging of output, flush all data, allow script aborting
673 * and reopen session for writing. Function error() does terminate the logging too.
675 * Please make sure that each upgrade_log_start() is properly terminated by
676 * this function or error().
678 * This function may be called repeatedly.
680 function upgrade_log_finish() {
681 global $CFG, $upgradeloghandle, $upgradelogbuffer;
683 if (empty($_SESSION['upgraderunning'])) {
684 return; // logging already terminated
687 @ob_end_flush();
688 if ($upgradelogbuffer !== '') {
689 @fwrite($upgradeloghandle, $upgradelogbuffer);
690 $upgradelogbuffer = '';
692 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
693 @fclose($upgradeloghandle);
694 $upgradeloghandle = false;
696 if (empty($CFG->dbsessions)) {
697 @session_start(); // ignore header errors, we only need to reopen session
699 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
700 if (connection_aborted()) {
701 die;
703 @ignore_user_abort(false);
707 * Callback function for logging into files. Not more than one file is created per minute,
708 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
710 * This function must not output any characters or throw warnigns and errors!
712 function upgrade_log_callback($string) {
713 global $CFG, $upgradeloghandle, $upgradelogbuffer;
715 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
716 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
717 $upgradelogbuffer .= $string;
718 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
719 @fwrite($upgradeloghandle, $upgradelogbuffer);
720 $upgradelogbuffer = '';
722 } else {
723 $upgradeloghandle = 'error';
726 return $string;
730 * Test if and critical warnings are present
731 * @return bool
733 function admin_critical_warnings_present() {
734 global $SESSION;
736 if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) {
737 return 0;
740 if (!isset($SESSION->admin_critical_warning)) {
741 $SESSION->admin_critical_warning = 0;
742 if (ini_get_bool('register_globals')) {
743 $SESSION->admin_critical_warning = 1;
744 } else if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) {
745 $SESSION->admin_critical_warning = 1;
749 return $SESSION->admin_critical_warning;
753 * Detects if float support at least 10 deciman digits
754 * and also if float-->string conversion works as expected.
755 * @return bool true if problem found
757 function is_float_problem() {
758 $num1 = 2009010200.01;
759 $num2 = 2009010200.02;
761 return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1);
765 * Try to verify that dataroot is not accessible from web.
766 * It is not 100% correct but might help to reduce number of vulnerable sites.
768 * Protection from httpd.conf and .htaccess is not detected properly.
769 * @param bool $fetchtest try to test public access by fetching file
770 * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING migth be problematic
772 function is_dataroot_insecure($fetchtest=false) {
773 global $CFG;
775 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
777 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
778 $rp = strrev(trim($rp, '/'));
779 $rp = explode('/', $rp);
780 foreach($rp as $r) {
781 if (strpos($siteroot, '/'.$r.'/') === 0) {
782 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
783 } else {
784 break; // probably alias root
788 $siteroot = strrev($siteroot);
789 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
791 if (strpos($dataroot, $siteroot) !== 0) {
792 return false;
795 if (!$fetchtest) {
796 return INSECURE_DATAROOT_WARNING;
799 // now try all methods to fetch a test file using http protocol
801 $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/'));
802 preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches);
803 $httpdocroot = $matches[1];
804 $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot));
805 if (make_upload_directory('diag', false) === false) {
806 return INSECURE_DATAROOT_WARNING;
808 $testfile = $CFG->dataroot.'/diag/public.txt';
809 if (!file_exists($testfile)) {
810 file_put_contents($testfile, 'test file, do not delete');
812 $teststr = trim(file_get_contents($testfile));
813 if (empty($teststr)) {
814 // hmm, strange
815 return INSECURE_DATAROOT_WARNING;
818 $testurl = $datarooturl.'/diag/public.txt';
819 if (extension_loaded('curl') and
820 !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and
821 !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and
822 ($ch = @curl_init($testurl)) !== false) {
823 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
824 curl_setopt($ch, CURLOPT_HEADER, false);
825 $data = curl_exec($ch);
826 if (!curl_errno($ch)) {
827 $data = trim($data);
828 if ($data === $teststr) {
829 curl_close($ch);
830 return INSECURE_DATAROOT_ERROR;
833 curl_close($ch);
836 if ($data = @file_get_contents($testurl)) {
837 $data = trim($data);
838 if ($data === $teststr) {
839 return INSECURE_DATAROOT_ERROR;
843 preg_match('|https?://([^/]+)|i', $testurl, $matches);
844 $sitename = $matches[1];
845 $error = 0;
846 if ($fp = @fsockopen($sitename, 80, $error)) {
847 preg_match('|https?://[^/]+(.*)|i', $testurl, $matches);
848 $localurl = $matches[1];
849 $out = "GET $localurl HTTP/1.1\r\n";
850 $out .= "Host: $sitename\r\n";
851 $out .= "Connection: Close\r\n\r\n";
852 fwrite($fp, $out);
853 $data = '';
854 $incoming = false;
855 while (!feof($fp)) {
856 if ($incoming) {
857 $data .= fgets($fp, 1024);
858 } else if (@fgets($fp, 1024) === "\r\n") {
859 $incoming = true;
862 fclose($fp);
863 $data = trim($data);
864 if ($data === $teststr) {
865 return INSECURE_DATAROOT_ERROR;
869 return INSECURE_DATAROOT_WARNING;
872 /// =============================================================================================================
873 /// administration tree classes and functions
876 // n.b. documentation is still in progress for this code
878 /// INTRODUCTION
880 /// This file performs the following tasks:
881 /// -it defines the necessary objects and interfaces to build the Moodle
882 /// admin hierarchy
883 /// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
884 /// and admin_externalpage_print_footer() functions used on admin pages
886 /// ADMIN_SETTING OBJECTS
888 /// Moodle settings are represented by objects that inherit from the admin_setting
889 /// class. These objects encapsulate how to read a setting, how to write a new value
890 /// to a setting, and how to appropriately display the HTML to modify the setting.
892 /// ADMIN_SETTINGPAGE OBJECTS
894 /// The admin_setting objects are then grouped into admin_settingpages. The latter
895 /// appear in the Moodle admin tree block. All interaction with admin_settingpage
896 /// objects is handled by the admin/settings.php file.
898 /// ADMIN_EXTERNALPAGE OBJECTS
900 /// There are some settings in Moodle that are too complex to (efficiently) handle
901 /// with admin_settingpages. (Consider, for example, user management and displaying
902 /// lists of users.) In this case, we use the admin_externalpage object. This object
903 /// places a link to an external PHP file in the admin tree block.
905 /// If you're using an admin_externalpage object for some settings, you can take
906 /// advantage of the admin_externalpage_* functions. For example, suppose you wanted
907 /// to add a foo.php file into admin. First off, you add the following line to
908 /// admin/settings/first.php (at the end of the file) or to some other file in
909 /// admin/settings:
911 /// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
912 /// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
914 /// Next, in foo.php, your file structure would resemble the following:
916 /// require_once('.../config.php');
917 /// require_once($CFG->libdir.'/adminlib.php');
918 /// admin_externalpage_setup('foo');
919 /// // functionality like processing form submissions goes here
920 /// admin_externalpage_print_header();
921 /// // your HTML goes here
922 /// admin_externalpage_print_footer();
924 /// The admin_externalpage_setup() function call ensures the user is logged in,
925 /// and makes sure that they have the proper role permission to access the page.
927 /// The admin_externalpage_print_header() function prints the header (it figures
928 /// out what category and subcategories the page is classified under) and ensures
929 /// that you're using the admin pagelib (which provides the admin tree block and
930 /// the admin bookmarks block).
932 /// The admin_externalpage_print_footer() function properly closes the tables
933 /// opened up by the admin_externalpage_print_header() function and prints the
934 /// standard Moodle footer.
936 /// ADMIN_CATEGORY OBJECTS
938 /// Above and beyond all this, we have admin_category objects. These objects
939 /// appear as folders in the admin tree block. They contain admin_settingpage's,
940 /// admin_externalpage's, and other admin_category's.
942 /// OTHER NOTES
944 /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
945 /// from part_of_admin_tree (a pseudointerface). This interface insists that
946 /// a class has a check_access method for access permissions, a locate method
947 /// used to find a specific node in the admin tree and find parent path.
949 /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
950 /// interface ensures that the class implements a recursive add function which
951 /// accepts a part_of_admin_tree object and searches for the proper place to
952 /// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
954 /// Please note that the $this->name field of any part_of_admin_tree must be
955 /// UNIQUE throughout the ENTIRE admin tree.
957 /// The $this->name field of an admin_setting object (which is *not* part_of_
958 /// admin_tree) must be unique on the respective admin_settingpage where it is
959 /// used.
962 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
965 * Pseudointerface for anything appearing in the admin tree
967 * The pseudointerface that is implemented by anything that appears in the admin tree
968 * block. It forces inheriting classes to define a method for checking user permissions
969 * and methods for finding something in the admin tree.
971 * @author Vincenzo K. Marcovecchio
972 * @package admin
974 class part_of_admin_tree {
977 * Finds a named part_of_admin_tree.
979 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
980 * and not parentable_part_of_admin_tree, then this function should only check if
981 * $this->name matches $name. If it does, it should return a reference to $this,
982 * otherwise, it should return a reference to NULL.
984 * If a class inherits parentable_part_of_admin_tree, this method should be called
985 * recursively on all child objects (assuming, of course, the parent object's name
986 * doesn't match the search criterion).
988 * @param string $name The internal name of the part_of_admin_tree we're searching for.
989 * @return mixed An object reference or a NULL reference.
991 function &locate($name) {
992 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
993 return;
997 * Removes named part_of_admin_tree.
999 * @param string $name The internal name of the part_of_admin_tree we want to remove.
1000 * @return bool success.
1002 function prune($name) {
1003 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
1004 return;
1008 * Search using query
1009 * @param strin query
1010 * @return mixed array-object structure of found settings and pages
1012 function search($query) {
1013 trigger_error('Admin class does not implement method <strong>search()</strong>', E_USER_WARNING);
1014 return;
1018 * Verifies current user's access to this part_of_admin_tree.
1020 * Used to check if the current user has access to this part of the admin tree or
1021 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
1022 * then this method is usually just a call to has_capability() in the site context.
1024 * If a class inherits parentable_part_of_admin_tree, this method should return the
1025 * logical OR of the return of check_access() on all child objects.
1027 * @return bool True if the user has access, false if she doesn't.
1029 function check_access() {
1030 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
1031 return;
1035 * Mostly usefull for removing of some parts of the tree in admin tree block.
1037 * @return True is hidden from normal list view
1039 function is_hidden() {
1040 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
1041 return;
1046 * Pseudointerface implemented by any part_of_admin_tree that has children.
1048 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
1049 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
1050 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
1051 * include an add method for adding other part_of_admin_tree objects as children.
1053 * @author Vincenzo K. Marcovecchio
1054 * @package admin
1056 class parentable_part_of_admin_tree extends part_of_admin_tree {
1059 * Adds a part_of_admin_tree object to the admin tree.
1061 * Used to add a part_of_admin_tree object to this object or a child of this
1062 * object. $something should only be added if $destinationname matches
1063 * $this->name. If it doesn't, add should be called on child objects that are
1064 * also parentable_part_of_admin_tree's.
1066 * @param string $destinationname The internal name of the new parent for $something.
1067 * @param part_of_admin_tree &$something The object to be added.
1068 * @return bool True on success, false on failure.
1070 function add($destinationname, $something) {
1071 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
1072 return;
1078 * The object used to represent folders (a.k.a. categories) in the admin tree block.
1080 * Each admin_category object contains a number of part_of_admin_tree objects.
1082 * @author Vincenzo K. Marcovecchio
1083 * @package admin
1085 class admin_category extends parentable_part_of_admin_tree {
1088 * @var mixed An array of part_of_admin_tree objects that are this object's children
1090 var $children;
1093 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
1095 var $name;
1098 * @var string The displayed name for this category. Usually obtained through get_string()
1100 var $visiblename;
1103 * @var bool Should this category be hidden in admin tree block?
1105 var $hidden;
1108 * paths
1110 var $path;
1111 var $visiblepath;
1114 * Constructor for an empty admin category
1116 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
1117 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
1118 * @param bool $hidden hide category in admin tree block
1120 function admin_category($name, $visiblename, $hidden=false) {
1121 $this->children = array();
1122 $this->name = $name;
1123 $this->visiblename = $visiblename;
1124 $this->hidden = $hidden;
1128 * Returns a reference to the part_of_admin_tree object with internal name $name.
1130 * @param string $name The internal name of the object we want.
1131 * @param bool $findpath initialize path and visiblepath arrays
1132 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1134 function &locate($name, $findpath=false) {
1135 if ($this->name == $name) {
1136 if ($findpath) {
1137 $this->visiblepath[] = $this->visiblename;
1138 $this->path[] = $this->name;
1140 return $this;
1143 $return = NULL;
1144 foreach($this->children as $childid=>$unused) {
1145 if ($return =& $this->children[$childid]->locate($name, $findpath)) {
1146 break;
1150 if (!is_null($return) and $findpath) {
1151 $return->visiblepath[] = $this->visiblename;
1152 $return->path[] = $this->name;
1155 return $return;
1159 * Search using query
1160 * @param strin query
1161 * @return mixed array-object structure of found settings and pages
1163 function search($query) {
1164 $result = array();
1165 foreach ($this->children as $child) {
1166 $subsearch = $child->search($query);
1167 if (!is_array($subsearch)) {
1168 debugging('Incorrect search result from '.$child->name);
1169 continue;
1171 $result = array_merge($result, $subsearch);
1173 return $result;
1177 * Removes part_of_admin_tree object with internal name $name.
1179 * @param string $name The internal name of the object we want to remove.
1180 * @return bool success
1182 function prune($name) {
1184 if ($this->name == $name) {
1185 return false; //can not remove itself
1188 foreach($this->children as $precedence => $child) {
1189 if ($child->name == $name) {
1190 // found it!
1191 unset($this->children[$precedence]);
1192 return true;
1194 if ($this->children[$precedence]->prune($name)) {
1195 return true;
1198 return false;
1202 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1204 * @param string $destinationame The internal name of the immediate parent that we want for $something.
1205 * @param mixed $something A part_of_admin_tree or setting instanceto be added.
1206 * @return bool True if successfully added, false if $something can not be added.
1208 function add($parentname, $something) {
1209 $parent =& $this->locate($parentname);
1210 if (is_null($parent)) {
1211 debugging('parent does not exist!');
1212 return false;
1215 if (is_a($something, 'part_of_admin_tree')) {
1216 if (!is_a($parent, 'parentable_part_of_admin_tree')) {
1217 debugging('error - parts of tree can be inserted only into parentable parts');
1218 return false;
1220 $parent->children[] = $something;
1221 return true;
1223 } else {
1224 debugging('error - can not add this element');
1225 return false;
1231 * Checks if the user has access to anything in this category.
1233 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1235 function check_access() {
1236 foreach ($this->children as $child) {
1237 if ($child->check_access()) {
1238 return true;
1241 return false;
1245 * Is this category hidden in admin tree block?
1247 * @return bool True if hidden
1249 function is_hidden() {
1250 return $this->hidden;
1254 class admin_root extends admin_category {
1256 * list of errors
1258 var $errors;
1261 * search query
1263 var $search;
1266 * full tree flag - true means all settings required, false onlypages required
1268 var $fulltree;
1271 function admin_root() {
1272 parent::admin_category('root', get_string('administration'), false);
1273 $this->errors = array();
1274 $this->search = '';
1275 $this->fulltree = true;
1280 * Links external PHP pages into the admin tree.
1282 * See detailed usage example at the top of this document (adminlib.php)
1284 * @author Vincenzo K. Marcovecchio
1285 * @package admin
1287 class admin_externalpage extends part_of_admin_tree {
1290 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1292 var $name;
1295 * @var string The displayed name for this external page. Usually obtained through get_string().
1297 var $visiblename;
1300 * @var string The external URL that we should link to when someone requests this external page.
1302 var $url;
1305 * @var string The role capability/permission a user must have to access this external page.
1307 var $req_capability;
1310 * @var object The context in which capability/permission should be checked, default is site context.
1312 var $context;
1315 * @var bool hidden in admin tree block.
1317 var $hidden;
1320 * visible path
1322 var $path;
1323 var $visiblepath;
1326 * Constructor for adding an external page into the admin tree.
1328 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1329 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1330 * @param string $url The external URL that we should link to when someone requests this external page.
1331 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1332 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1333 * @param context $context The context the page relates to. Not sure what happens
1334 * if you specify something other than system or front page. Defaults to system.
1336 function admin_externalpage($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1337 $this->name = $name;
1338 $this->visiblename = $visiblename;
1339 $this->url = $url;
1340 if (is_array($req_capability)) {
1341 $this->req_capability = $req_capability;
1342 } else {
1343 $this->req_capability = array($req_capability);
1345 $this->hidden = $hidden;
1346 $this->context = $context;
1350 * Returns a reference to the part_of_admin_tree object with internal name $name.
1352 * @param string $name The internal name of the object we want.
1353 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1355 function &locate($name, $findpath=false) {
1356 if ($this->name == $name) {
1357 if ($findpath) {
1358 $this->visiblepath = array($this->visiblename);
1359 $this->path = array($this->name);
1361 return $this;
1362 } else {
1363 $return = NULL;
1364 return $return;
1368 function prune($name) {
1369 return false;
1373 * Search using query
1374 * @param strin query
1375 * @return mixed array-object structure of found settings and pages
1377 function search($query) {
1378 $textlib = textlib_get_instance();
1380 $found = false;
1381 if (strpos(strtolower($this->name), $query) !== false) {
1382 $found = true;
1383 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1384 $found = true;
1386 if ($found) {
1387 $result = new object();
1388 $result->page = $this;
1389 $result->settings = array();
1390 return array($this->name => $result);
1391 } else {
1392 return array();
1397 * Determines if the current user has access to this external page based on $this->req_capability.
1398 * @return bool True if user has access, false otherwise.
1400 function check_access() {
1401 if (!get_site()) {
1402 return true; // no access check before site is fully set up
1404 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1405 foreach($this->req_capability as $cap) {
1406 if (is_valid_capability($cap) and has_capability($cap, $context)) {
1407 return true;
1410 return false;
1414 * Is this external page hidden in admin tree block?
1416 * @return bool True if hidden
1418 function is_hidden() {
1419 return $this->hidden;
1425 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1427 * @author Vincenzo K. Marcovecchio
1428 * @package admin
1430 class admin_settingpage extends part_of_admin_tree {
1433 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1435 var $name;
1438 * @var string The displayed name for this external page. Usually obtained through get_string().
1440 var $visiblename;
1442 * @var mixed An array of admin_setting objects that are part of this setting page.
1444 var $settings;
1447 * @var string The role capability/permission a user must have to access this external page.
1449 var $req_capability;
1452 * @var object The context in which capability/permission should be checked, default is site context.
1454 var $context;
1457 * @var bool hidden in admin tree block.
1459 var $hidden;
1462 * paths
1464 var $path;
1465 var $visiblepath;
1467 // see admin_externalpage
1468 function admin_settingpage($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1469 $this->settings = new object();
1470 $this->name = $name;
1471 $this->visiblename = $visiblename;
1472 if (is_array($req_capability)) {
1473 $this->req_capability = $req_capability;
1474 } else {
1475 $this->req_capability = array($req_capability);
1477 $this->hidden = $hidden;
1478 $this->context = $context;
1481 // see admin_category
1482 function &locate($name, $findpath=false) {
1483 if ($this->name == $name) {
1484 if ($findpath) {
1485 $this->visiblepath = array($this->visiblename);
1486 $this->path = array($this->name);
1488 return $this;
1489 } else {
1490 $return = NULL;
1491 return $return;
1495 function search($query) {
1496 $found = array();
1498 foreach ($this->settings as $setting) {
1499 if ($setting->is_related($query)) {
1500 $found[] = $setting;
1504 if ($found) {
1505 $result = new object();
1506 $result->page = $this;
1507 $result->settings = $found;
1508 return array($this->name => $result);
1511 $textlib = textlib_get_instance();
1513 $found = false;
1514 if (strpos(strtolower($this->name), $query) !== false) {
1515 $found = true;
1516 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1517 $found = true;
1519 if ($found) {
1520 $result = new object();
1521 $result->page = $this;
1522 $result->settings = array();
1523 return array($this->name => $result);
1524 } else {
1525 return array();
1529 function prune($name) {
1530 return false;
1534 * 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
1535 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1536 * @param object $setting is the admin_setting object you want to add
1537 * @return true if successful, false if not
1539 function add($setting) {
1540 if (!is_a($setting, 'admin_setting')) {
1541 debugging('error - not a setting instance');
1542 return false;
1545 $this->settings->{$setting->name} = $setting;
1546 return true;
1549 // see admin_externalpage
1550 function check_access() {
1551 if (!get_site()) {
1552 return true; // no access check before site is fully set up
1554 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1555 foreach($this->req_capability as $cap) {
1556 if (is_valid_capability($cap) and has_capability($cap, $context)) {
1557 return true;
1560 return false;
1564 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1565 * returns a string of the html
1567 function output_html() {
1568 $adminroot =& admin_get_root();
1569 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
1570 foreach($this->settings as $setting) {
1571 $fullname = $setting->get_full_name();
1572 if (array_key_exists($fullname, $adminroot->errors)) {
1573 $data = $adminroot->errors[$fullname]->data;
1574 } else {
1575 $data = $setting->get_setting();
1576 if (is_null($data)) {
1577 $data = $setting->get_defaultsetting();
1580 $return .= $setting->output_html($data);
1582 $return .= '</fieldset>';
1583 return $return;
1587 * Is this settigns page hidden in admin tree block?
1589 * @return bool True if hidden
1591 function is_hidden() {
1592 return $this->hidden;
1599 * Admin settings class. Only exists on setting pages.
1600 * Read & write happens at this level; no authentication.
1602 class admin_setting {
1604 var $name;
1605 var $visiblename;
1606 var $description;
1607 var $defaultsetting;
1608 var $updatedcallback;
1609 var $plugin; // null means main config table
1612 * Constructor
1613 * @param $name string unique ascii name
1614 * @param $visiblename string localised name
1615 * @param strin $description localised long description
1616 * @param mixed $defaultsetting string or array depending on implementation
1618 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1619 $this->parse_setting_name($name);
1620 $this->visiblename = $visiblename;
1621 $this->description = $description;
1622 $this->defaultsetting = $defaultsetting;
1626 * Set up $this->name and possibly $this->plugin based on whether $name looks
1627 * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking
1628 * on the names, that is, output a developer debug warning if the name
1629 * contains anything other than [a-zA-Z0-9_]+.
1631 * @param string $name the setting name passed in to the constructor.
1633 function parse_setting_name($name) {
1634 $bits = explode('/', $name);
1635 if (count($bits) > 2) {
1636 print_error('invalidadminsettingname', '', '', $name);
1638 $this->name = array_pop($bits);
1639 if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) {
1640 print_error('invalidadminsettingname', '', '', $name);
1642 if (!empty($bits)) {
1643 $this->plugin = array_pop($bits);
1644 if ($this->plugin === 'moodle') {
1645 $this->plugin = null;
1646 } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) {
1647 print_error('invalidadminsettingname', '', '', $name);
1652 function get_full_name() {
1653 return 's_'.$this->plugin.'_'.$this->name;
1656 function get_id() {
1657 return 'id_s_'.$this->plugin.'_'.$this->name;
1660 function config_read($name) {
1661 global $CFG;
1662 if ($this->plugin === 'backup') {
1663 require_once($CFG->dirroot.'/backup/lib.php');
1664 $backupconfig = backup_get_config();
1665 if (isset($backupconfig->$name)) {
1666 return $backupconfig->$name;
1667 } else {
1668 return NULL;
1671 } else if (!empty($this->plugin)) {
1672 $value = get_config($this->plugin, $name);
1673 return $value === false ? NULL : $value;
1675 } else {
1676 if (isset($CFG->$name)) {
1677 return $CFG->$name;
1678 } else {
1679 return NULL;
1684 function config_write($name, $value) {
1685 global $CFG;
1686 if ($this->plugin === 'backup') {
1687 require_once($CFG->dirroot.'/backup/lib.php');
1688 return (boolean)backup_set_config($name, $value);
1689 } else {
1690 return (boolean)set_config($name, $value, $this->plugin);
1695 * Returns current value of this setting
1696 * @return mixed array or string depending on instance, NULL means not set yet
1698 function get_setting() {
1699 // has to be overridden
1700 return NULL;
1704 * Returns default setting if exists
1705 * @return mixed array or string depending on instance; NULL means no default, user must supply
1707 function get_defaultsetting() {
1708 return $this->defaultsetting;
1712 * Store new setting
1713 * @param mixed string or array, must not be NULL
1714 * @return '' if ok, string error message otherwise
1716 function write_setting($data) {
1717 // should be overridden
1718 return '';
1722 * Return part of form with setting
1723 * @param mixed data array or string depending on setting
1724 * @return string
1726 function output_html($data, $query='') {
1727 // should be overridden
1728 return;
1732 * function called if setting updated - cleanup, cache reset, etc.
1734 function set_updatedcallback($functionname) {
1735 $this->updatedcallback = $functionname;
1739 * Is setting related to query text - used when searching
1740 * @param string $query
1741 * @return bool
1743 function is_related($query) {
1744 if (strpos(strtolower($this->name), $query) !== false) {
1745 return true;
1747 $textlib = textlib_get_instance();
1748 if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1749 return true;
1751 if (strpos($textlib->strtolower($this->description), $query) !== false) {
1752 return true;
1754 $current = $this->get_setting();
1755 if (!is_null($current)) {
1756 if (is_string($current)) {
1757 if (strpos($textlib->strtolower($current), $query) !== false) {
1758 return true;
1762 $default = $this->get_defaultsetting();
1763 if (!is_null($default)) {
1764 if (is_string($default)) {
1765 if (strpos($textlib->strtolower($default), $query) !== false) {
1766 return true;
1770 return false;
1775 * No setting - just heading and text.
1777 class admin_setting_heading extends admin_setting {
1779 * not a setting, just text
1780 * @param string $name of setting
1781 * @param string $heading heading
1782 * @param string $information text in box
1784 function admin_setting_heading($name, $heading, $information) {
1785 parent::admin_setting($name, $heading, $information, '');
1788 function get_setting() {
1789 return true;
1792 function get_defaultsetting() {
1793 return true;
1796 function write_setting($data) {
1797 // do not write any setting
1798 return '';
1801 function output_html($data, $query='') {
1802 $return = '';
1803 if ($this->visiblename != '') {
1804 $return .= print_heading('<a name="'.$this->name.'">'.highlightfast($query, $this->visiblename).'</a>', '', 3, 'main', true);
1806 if ($this->description != '') {
1807 $return .= print_box(highlight($query, $this->description), 'generalbox formsettingheading', '', true);
1809 return $return;
1814 * The most flexibly setting, user is typing text
1816 class admin_setting_configtext extends admin_setting {
1818 var $paramtype;
1819 var $size;
1822 * config text contructor
1823 * @param string $name of setting
1824 * @param string $visiblename localised
1825 * @param string $description long localised info
1826 * @param string $defaultsetting
1827 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
1828 * @param int $size default field size
1830 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
1831 $this->paramtype = $paramtype;
1832 if (!is_null($size)) {
1833 $this->size = $size;
1834 } else {
1835 $this->size = ($paramtype == PARAM_INT) ? 5 : 30;
1837 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1840 function get_setting() {
1841 return $this->config_read($this->name);
1844 function write_setting($data) {
1845 if ($this->paramtype === PARAM_INT and $data === '') {
1846 // do not complain if '' used instead of 0
1847 $data = 0;
1849 // $data is a string
1850 $validated = $this->validate($data);
1851 if ($validated !== true) {
1852 return $validated;
1854 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
1858 * Validate data before storage
1859 * @param string data
1860 * @return mixed true if ok string if error found
1862 function validate($data) {
1863 if (is_string($this->paramtype)) {
1864 if (preg_match($this->paramtype, $data)) {
1865 return true;
1866 } else {
1867 return get_string('validateerror', 'admin');
1870 } else if ($this->paramtype === PARAM_RAW) {
1871 return true;
1873 } else {
1874 $cleaned = stripslashes(clean_param(addslashes($data), $this->paramtype));
1875 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
1876 return true;
1877 } else {
1878 return get_string('validateerror', 'admin');
1883 function output_html($data, $query='') {
1884 $default = $this->get_defaultsetting();
1886 return format_admin_setting($this, $this->visiblename,
1887 '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>',
1888 $this->description, true, '', $default, $query);
1893 * General text area without html editor.
1895 class admin_setting_configtextarea extends admin_setting_configtext {
1896 var $rows;
1897 var $cols;
1899 function admin_setting_configtextarea($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
1900 $this->rows = $rows;
1901 $this->cols = $cols;
1902 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1905 function output_html($data, $query='') {
1906 $default = $this->get_defaultsetting();
1908 $defaultinfo = $default;
1909 if (!is_null($default) and $default !== '') {
1910 $defaultinfo = "\n".$default;
1913 return format_admin_setting($this, $this->visiblename,
1914 '<div class="form-textarea form-textarea-advanced" ><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'">'. s($data) .'</textarea></div>',
1915 $this->description, true, '', $defaultinfo, $query);
1920 * Password field, allows unmasking of password
1922 class admin_setting_configpasswordunmask extends admin_setting_configtext {
1924 * Constructor
1925 * @param string $name of setting
1926 * @param string $visiblename localised
1927 * @param string $description long localised info
1928 * @param string $defaultsetting default password
1930 function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting) {
1931 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
1934 function output_html($data, $query='') {
1935 $id = $this->get_id();
1936 $unmask = get_string('unmaskpassword', 'form');
1937 $unmaskjs = '<script type="text/javascript">
1938 //<![CDATA[
1939 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>\');
1940 document.getElementById("'.$this->get_id().'").setAttribute("autocomplete", "off");
1941 //]]>
1942 </script>';
1943 return format_admin_setting($this, $this->visiblename,
1944 '<div class="form-password"><input type="password" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$unmaskjs.'</div>',
1945 $this->description, true, '', NULL, $query);
1950 * Path to directory
1952 class admin_setting_configfile extends admin_setting_configtext {
1954 * Constructor
1955 * @param string $name of setting
1956 * @param string $visiblename localised
1957 * @param string $description long localised info
1958 * @param string $defaultdirectory default directory location
1960 function admin_setting_configfile($name, $visiblename, $description, $defaultdirectory) {
1961 parent::admin_setting_configtext($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
1964 function output_html($data, $query='') {
1965 $default = $this->get_defaultsetting();
1967 if ($data) {
1968 if (file_exists($data)) {
1969 $executable = '<span class="pathok">&#x2714;</span>';
1970 } else {
1971 $executable = '<span class="patherror">&#x2718;</span>';
1973 } else {
1974 $executable = '';
1977 return format_admin_setting($this, $this->visiblename,
1978 '<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>',
1979 $this->description, true, '', $default, $query);
1984 * Path to executable file
1986 class admin_setting_configexecutable extends admin_setting_configfile {
1988 function output_html($data, $query='') {
1989 $default = $this->get_defaultsetting();
1991 if ($data) {
1992 if (file_exists($data) and is_executable($data)) {
1993 $executable = '<span class="pathok">&#x2714;</span>';
1994 } else {
1995 $executable = '<span class="patherror">&#x2718;</span>';
1997 } else {
1998 $executable = '';
2001 return format_admin_setting($this, $this->visiblename,
2002 '<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>',
2003 $this->description, true, '', $default, $query);
2008 * Path to directory
2010 class admin_setting_configdirectory extends admin_setting_configfile {
2011 function output_html($data, $query='') {
2012 $default = $this->get_defaultsetting();
2014 if ($data) {
2015 if (file_exists($data) and is_dir($data)) {
2016 $executable = '<span class="pathok">&#x2714;</span>';
2017 } else {
2018 $executable = '<span class="patherror">&#x2718;</span>';
2020 } else {
2021 $executable = '';
2024 return format_admin_setting($this, $this->visiblename,
2025 '<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>',
2026 $this->description, true, '', $default, $query);
2031 * Checkbox
2033 class admin_setting_configcheckbox extends admin_setting {
2034 var $yes;
2035 var $no;
2038 * Constructor
2039 * @param string $name of setting
2040 * @param string $visiblename localised
2041 * @param string $description long localised info
2042 * @param string $defaultsetting
2043 * @param string $yes value used when checked
2044 * @param string $no value used when not checked
2046 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
2047 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2048 $this->yes = (string)$yes;
2049 $this->no = (string)$no;
2052 function get_setting() {
2053 return $this->config_read($this->name);
2056 function write_setting($data) {
2057 if ((string)$data === $this->yes) { // convert to strings before comparison
2058 $data = $this->yes;
2059 } else {
2060 $data = $this->no;
2062 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2065 function output_html($data, $query='') {
2066 $default = $this->get_defaultsetting();
2068 if (!is_null($default)) {
2069 if ((string)$default === $this->yes) {
2070 $defaultinfo = get_string('checkboxyes', 'admin');
2071 } else {
2072 $defaultinfo = get_string('checkboxno', 'admin');
2074 } else {
2075 $defaultinfo = NULL;
2078 if ((string)$data === $this->yes) { // convert to strings before comparison
2079 $checked = 'checked="checked"';
2080 } else {
2081 $checked = '';
2084 return format_admin_setting($this, $this->visiblename,
2085 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
2086 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
2087 $this->description, true, '', $defaultinfo, $query);
2092 * Multiple checkboxes, each represents different value, stored in csv format
2094 class admin_setting_configmulticheckbox extends admin_setting {
2095 var $choices;
2098 * Constructor
2099 * @param string $name of setting
2100 * @param string $visiblename localised
2101 * @param string $description long localised info
2102 * @param array $defaultsetting array of selected
2103 * @param array $choices array of $value=>$label for each checkbox
2105 function admin_setting_configmulticheckbox($name, $visiblename, $description, $defaultsetting, $choices) {
2106 $this->choices = $choices;
2107 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2111 * This function may be used in ancestors for lazy loading of choices
2112 * @return true if loaded, false if error
2114 function load_choices() {
2116 if (is_array($this->choices)) {
2117 return true;
2119 .... load choices here
2121 return true;
2125 * Is setting related to query text - used when searching
2126 * @param string $query
2127 * @return bool
2129 function is_related($query) {
2130 if (!$this->load_choices() or empty($this->choices)) {
2131 return false;
2133 if (parent::is_related($query)) {
2134 return true;
2137 $textlib = textlib_get_instance();
2138 foreach ($this->choices as $desc) {
2139 if (strpos($textlib->strtolower($desc), $query) !== false) {
2140 return true;
2143 return false;
2146 function get_setting() {
2147 $result = $this->config_read($this->name);
2148 if (is_null($result)) {
2149 return NULL;
2151 if ($result === '') {
2152 return array();
2154 return explode(',', $result);
2157 function write_setting($data) {
2158 if (!is_array($data)) {
2159 return ''; // ignore it
2161 if (!$this->load_choices() or empty($this->choices)) {
2162 return '';
2164 unset($data['xxxxx']);
2165 $result = array();
2166 foreach ($data as $key => $value) {
2167 if ($value and array_key_exists($key, $this->choices)) {
2168 $result[] = $key;
2171 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
2174 function output_html($data, $query='') {
2175 if (!$this->load_choices() or empty($this->choices)) {
2176 return '';
2178 $default = $this->get_defaultsetting();
2179 if (is_null($default)) {
2180 $default = array();
2182 if (is_null($data)) {
2183 foreach ($default as $key=>$value) {
2184 if ($value) {
2185 $current[] = $value;
2190 $options = array();
2191 $defaults = array();
2192 foreach($this->choices as $key=>$description) {
2193 if (in_array($key, $data)) {
2194 $checked = 'checked="checked"';
2195 } else {
2196 $checked = '';
2198 if (!empty($default[$key])) {
2199 $defaults[] = $description;
2202 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
2203 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
2206 if (is_null($default)) {
2207 $defaultinfo = NULL;
2208 } else if (!empty($defaults)) {
2209 $defaultinfo = implode(', ', $defaults);
2210 } else {
2211 $defaultinfo = get_string('none');
2214 $return = '<div class="form-multicheckbox">';
2215 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2216 if ($options) {
2217 $return .= '<ul>';
2218 foreach ($options as $option) {
2219 $return .= '<li>'.$option.'</li>';
2221 $return .= '</ul>';
2223 $return .= '</div>';
2225 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2231 * Multiple checkboxes 2, value stored as string 00101011
2233 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
2234 function get_setting() {
2235 $result = $this->config_read($this->name);
2236 if (is_null($result)) {
2237 return NULL;
2239 if (!$this->load_choices()) {
2240 return NULL;
2242 $result = str_pad($result, count($this->choices), '0');
2243 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2244 $setting = array();
2245 foreach ($this->choices as $key=>$unused) {
2246 $value = array_shift($result);
2247 if ($value) {
2248 $setting[] = $key;
2251 return $setting;
2254 function write_setting($data) {
2255 if (!is_array($data)) {
2256 return ''; // ignore it
2258 if (!$this->load_choices() or empty($this->choices)) {
2259 return '';
2261 $result = '';
2262 foreach ($this->choices as $key=>$unused) {
2263 if (!empty($data[$key])) {
2264 $result .= '1';
2265 } else {
2266 $result .= '0';
2269 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
2274 * Select one value from list
2276 class admin_setting_configselect extends admin_setting {
2277 var $choices;
2280 * Constructor
2281 * @param string $name of setting
2282 * @param string $visiblename localised
2283 * @param string $description long localised info
2284 * @param string $defaultsetting
2285 * @param array $choices array of $value=>$label for each selection
2287 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
2288 $this->choices = $choices;
2289 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2293 * This function may be used in ancestors for lazy loading of choices
2294 * @return true if loaded, false if error
2296 function load_choices() {
2298 if (is_array($this->choices)) {
2299 return true;
2301 .... load choices here
2303 return true;
2306 function is_related($query) {
2307 if (parent::is_related($query)) {
2308 return true;
2310 if (!$this->load_choices()) {
2311 return false;
2313 $textlib = textlib_get_instance();
2314 foreach ($this->choices as $key=>$value) {
2315 if (strpos($textlib->strtolower($key), $query) !== false) {
2316 return true;
2318 if (strpos($textlib->strtolower($value), $query) !== false) {
2319 return true;
2322 return false;
2325 function get_setting() {
2326 return $this->config_read($this->name);
2329 function write_setting($data) {
2330 if (!$this->load_choices() or empty($this->choices)) {
2331 return '';
2333 if (!array_key_exists($data, $this->choices)) {
2334 return ''; // ignore it
2337 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2340 function output_html($data, $query='') {
2341 if (!$this->load_choices() or empty($this->choices)) {
2342 return '';
2344 $default = $this->get_defaultsetting();
2346 if (!is_null($default) and array_key_exists($default, $this->choices)) {
2347 $defaultinfo = $this->choices[$default];
2348 } else {
2349 $defaultinfo = NULL;
2352 $current = $this->get_setting();
2353 $warning = '';
2354 if (is_null($current)) {
2355 //first run
2356 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
2357 // no warning
2358 } else if (!array_key_exists($current, $this->choices)) {
2359 $warning = get_string('warningcurrentsetting', 'admin', s($current));
2360 if (!is_null($default) and $data==$current) {
2361 $data = $default; // use default instead of first value when showing the form
2365 $return = '<div class="form-select defaultsnext"><select id="'.$this->get_id().'" name="'.$this->get_full_name().'">';
2366 foreach ($this->choices as $key => $value) {
2367 // the string cast is needed because key may be integer - 0 is equal to most strings!
2368 $return .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
2370 $return .= '</select></div>';
2372 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
2378 * Select multiple items from list
2380 class admin_setting_configmultiselect extends admin_setting_configselect {
2382 * Constructor
2383 * @param string $name of setting
2384 * @param string $visiblename localised
2385 * @param string $description long localised info
2386 * @param array $defaultsetting array of selected items
2387 * @param array $choices array of $value=>$label for each list item
2389 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
2390 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
2393 function get_setting() {
2394 $result = $this->config_read($this->name);
2395 if (is_null($result)) {
2396 return NULL;
2398 if ($result === '') {
2399 return array();
2401 return explode(',', $result);
2404 function write_setting($data) {
2405 if (!is_array($data)) {
2406 return ''; //ignore it
2408 if (!$this->load_choices() or empty($this->choices)) {
2409 return '';
2412 unset($data['xxxxx']);
2414 $save = array();
2415 foreach ($data as $value) {
2416 if (!array_key_exists($value, $this->choices)) {
2417 continue; // ignore it
2419 $save[] = $value;
2422 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2426 * Is setting related to query text - used when searching
2427 * @param string $query
2428 * @return bool
2430 function is_related($query) {
2431 if (!$this->load_choices() or empty($this->choices)) {
2432 return false;
2434 if (parent::is_related($query)) {
2435 return true;
2438 $textlib = textlib_get_instance();
2439 foreach ($this->choices as $desc) {
2440 if (strpos($textlib->strtolower($desc), $query) !== false) {
2441 return true;
2444 return false;
2447 function output_html($data, $query='') {
2448 if (!$this->load_choices() or empty($this->choices)) {
2449 return '';
2451 $choices = $this->choices;
2452 $default = $this->get_defaultsetting();
2453 if (is_null($default)) {
2454 $default = array();
2456 if (is_null($data)) {
2457 $data = array();
2460 $defaults = array();
2461 $size = min(10, count($this->choices));
2462 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2463 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="'.$size.'" multiple="multiple">';
2464 foreach ($this->choices as $key => $description) {
2465 if (in_array($key, $data)) {
2466 $selected = 'selected="selected"';
2467 } else {
2468 $selected = '';
2470 if (in_array($key, $default)) {
2471 $defaults[] = $description;
2474 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
2477 if (is_null($default)) {
2478 $defaultinfo = NULL;
2479 } if (!empty($defaults)) {
2480 $defaultinfo = implode(', ', $defaults);
2481 } else {
2482 $defaultinfo = get_string('none');
2485 $return .= '</select></div>';
2486 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
2491 * Time selector
2492 * this is a liiitle bit messy. we're using two selects, but we're returning
2493 * them as an array named after $name (so we only use $name2 internally for the setting)
2495 class admin_setting_configtime extends admin_setting {
2496 var $name2;
2499 * Constructor
2500 * @param string $hoursname setting for hours
2501 * @param string $minutesname setting for hours
2502 * @param string $visiblename localised
2503 * @param string $description long localised info
2504 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
2506 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
2507 $this->name2 = $minutesname;
2508 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
2511 function get_setting() {
2512 $result1 = $this->config_read($this->name);
2513 $result2 = $this->config_read($this->name2);
2514 if (is_null($result1) or is_null($result2)) {
2515 return NULL;
2518 return array('h' => $result1, 'm' => $result2);
2521 function write_setting($data) {
2522 if (!is_array($data)) {
2523 return '';
2526 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
2527 return ($result ? '' : get_string('errorsetting', 'admin'));
2530 function output_html($data, $query='') {
2531 $default = $this->get_defaultsetting();
2533 if (is_array($default)) {
2534 $defaultinfo = $default['h'].':'.$default['m'];
2535 } else {
2536 $defaultinfo = NULL;
2539 $return = '<div class="form-time defaultsnext">'.
2540 '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
2541 for ($i = 0; $i < 24; $i++) {
2542 $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2544 $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
2545 for ($i = 0; $i < 60; $i += 5) {
2546 $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2548 $return .= '</select></div>';
2549 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2555 * An admin setting for selecting one or more users, who have a particular capability
2556 * in the system context. Warning, make sure the list will never be too long. There is
2557 * no paging or searching of this list.
2559 * To correctly get a list of users from this config setting, you need to call the
2560 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php.
2562 class admin_setting_users_with_capability extends admin_setting_configmultiselect {
2563 var $capability;
2566 * Constructor.
2568 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2569 * @param string $visiblename localised name
2570 * @param string $description localised long description
2571 * @param array $defaultsetting array of usernames
2572 * @param string $capability string capability name.
2574 function admin_setting_users_with_capability($name, $visiblename, $description, $defaultsetting, $capability) {
2575 $this->capability = $capability;
2576 parent::admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, NULL);
2579 function load_choices() {
2580 if (is_array($this->choices)) {
2581 return true;
2583 $users = get_users_by_capability(get_context_instance(CONTEXT_SYSTEM),
2584 $this->capability, 'u.id,u.username,u.firstname,u.lastname', 'u.lastname,u.firstname');
2585 $this->choices = array(
2586 '$@NONE@$' => get_string('nobody'),
2587 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)),
2589 foreach ($users as $user) {
2590 $this->choices[$user->username] = fullname($user);
2592 return true;
2595 function get_defaultsetting() {
2596 $this->load_choices();
2597 if (empty($this->defaultsetting)) {
2598 return array('$@NONE@$');
2599 } else if (array_key_exists($this->defaultsetting, $this->choices)) {
2600 return $this->defaultsetting;
2601 } else {
2602 return '';
2606 function get_setting() {
2607 $result = parent::get_setting();
2608 if (empty($result)) {
2609 $result = array('$@NONE@$');
2611 return $result;
2614 function write_setting($data) {
2615 // If all is selected, remove any explicit options.
2616 if (in_array('$@ALL@$', $data)) {
2617 $data = array('$@ALL@$');
2619 // None never needs to be writted to the DB.
2620 if (in_array('$@NONE@$', $data)) {
2621 unset($data[array_search('$@NONE@$', $data)]);
2623 return parent::write_setting($data);
2628 * Special checkbox for calendar - resets SESSION vars.
2630 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
2631 function admin_setting_special_adminseesall() {
2632 parent::admin_setting_configcheckbox('calendar_adminseesall', get_string('adminseesall', 'admin'),
2633 get_string('helpadminseesall', 'admin'), '0');
2636 function write_setting($data) {
2637 global $SESSION;
2638 unset($SESSION->cal_courses_shown);
2639 return parent::write_setting($data);
2644 * Special select for settings that are altered in setup.php and can not be altered on the fly
2646 class admin_setting_special_selectsetup extends admin_setting_configselect {
2647 function get_setting() {
2648 // read directly from db!
2649 return get_config(NULL, $this->name);
2652 function write_setting($data) {
2653 global $CFG;
2654 // do not change active CFG setting!
2655 $current = $CFG->{$this->name};
2656 $result = parent::write_setting($data);
2657 $CFG->{$this->name} = $current;
2658 return $result;
2663 * Special select for frontpage - stores data in course table
2665 class admin_setting_sitesetselect extends admin_setting_configselect {
2666 function get_setting() {
2667 $site = get_site();
2668 return $site->{$this->name};
2671 function write_setting($data) {
2672 global $SITE;
2673 if (!in_array($data, array_keys($this->choices))) {
2674 return get_string('errorsetting', 'admin');
2676 $record = new stdClass();
2677 $record->id = SITEID;
2678 $temp = $this->name;
2679 $record->$temp = $data;
2680 $record->timemodified = time();
2681 // update $SITE
2682 $SITE->{$this->name} = $data;
2683 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2688 * Special select - lists on the frontpage - hacky
2690 class admin_setting_courselist_frontpage extends admin_setting {
2691 var $choices;
2693 function admin_setting_courselist_frontpage($loggedin) {
2694 global $CFG;
2695 require_once($CFG->dirroot.'/course/lib.php');
2696 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
2697 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
2698 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
2699 $defaults = array(FRONTPAGECOURSELIST);
2700 parent::admin_setting($name, $visiblename, $description, $defaults);
2703 function load_choices() {
2704 if (is_array($this->choices)) {
2705 return true;
2707 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
2708 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
2709 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
2710 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
2711 'none' => get_string('none'));
2712 if ($this->name == 'frontpage' and count_records('course') > FRONTPAGECOURSELIMIT) {
2713 unset($this->choices[FRONTPAGECOURSELIST]);
2715 return true;
2717 function get_setting() {
2718 $result = $this->config_read($this->name);
2719 if (is_null($result)) {
2720 return NULL;
2722 if ($result === '') {
2723 return array();
2725 return explode(',', $result);
2728 function write_setting($data) {
2729 if (!is_array($data)) {
2730 return '';
2732 $this->load_choices();
2733 $save = array();
2734 foreach($data as $datum) {
2735 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
2736 continue;
2738 $save[$datum] = $datum; // no duplicates
2740 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2743 function output_html($data, $query='') {
2744 $this->load_choices();
2745 $currentsetting = array();
2746 foreach ($data as $key) {
2747 if ($key != 'none' and array_key_exists($key, $this->choices)) {
2748 $currentsetting[] = $key; // already selected first
2752 $return = '<div class="form-group">';
2753 for ($i = 0; $i < count($this->choices) - 1; $i++) {
2754 if (!array_key_exists($i, $currentsetting)) {
2755 $currentsetting[$i] = 'none'; //none
2757 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
2758 foreach ($this->choices as $key => $value) {
2759 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
2761 $return .= '</select>';
2762 if ($i !== count($this->choices) - 2) {
2763 $return .= '<br />';
2766 $return .= '</div>';
2768 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2773 * Special checkbox for frontpage - stores data in course table
2775 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
2776 function get_setting() {
2777 $site = get_site();
2778 return $site->{$this->name};
2781 function write_setting($data) {
2782 global $SITE;
2783 $record = new object();
2784 $record->id = SITEID;
2785 $record->{$this->name} = ($data == '1' ? 1 : 0);
2786 $record->timemodified = time();
2787 // update $SITE
2788 $SITE->{$this->name} = $data;
2789 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2794 * Special text for frontpage - stores data in course table.
2795 * Empty string means not set here. Manual setting is required.
2797 class admin_setting_sitesettext extends admin_setting_configtext {
2798 function get_setting() {
2799 $site = get_site();
2800 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
2803 function validate($data) {
2804 $cleaned = stripslashes(clean_param(addslashes($data), PARAM_MULTILANG));
2805 if ($cleaned === '') {
2806 return get_string('required');
2808 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
2809 return true;
2810 } else {
2811 return get_string('validateerror', 'admin');
2815 function write_setting($data) {
2816 global $SITE;
2817 $data = trim($data);
2818 $validated = $this->validate($data);
2819 if ($validated !== true) {
2820 return $validated;
2823 $record = new object();
2824 $record->id = SITEID;
2825 $record->{$this->name} = addslashes($data);
2826 $record->timemodified = time();
2827 // update $SITE
2828 $SITE->{$this->name} = $data;
2829 return (update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
2834 * Special text editor for site description.
2836 class admin_setting_special_frontpagedesc extends admin_setting {
2837 function admin_setting_special_frontpagedesc() {
2838 parent::admin_setting('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
2841 function get_setting() {
2842 $site = get_site();
2843 return $site->{$this->name};
2846 function write_setting($data) {
2847 global $SITE;
2848 $record = new object();
2849 $record->id = SITEID;
2850 $record->{$this->name} = addslashes($data);
2851 $record->timemodified = time();
2852 $SITE->{$this->name} = $data;
2853 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2856 function output_html($data, $query='') {
2857 global $CFG;
2859 $CFG->adminusehtmleditor = can_use_html_editor();
2860 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true, 'summary') .'</div>';
2862 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2866 class admin_setting_special_editorfontlist extends admin_setting {
2868 var $items;
2870 function admin_setting_special_editorfontlist() {
2871 global $CFG;
2872 $name = 'editorfontlist';
2873 $visiblename = get_string('editorfontlist', 'admin');
2874 $description = get_string('configeditorfontlist', 'admin');
2875 $defaults = array('k0' => 'Trebuchet',
2876 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
2877 'k1' => 'Arial',
2878 'v1' => 'arial,helvetica,sans-serif',
2879 'k2' => 'Courier New',
2880 'v2' => 'courier new,courier,monospace',
2881 'k3' => 'Georgia',
2882 'v3' => 'georgia,times new roman,times,serif',
2883 'k4' => 'Tahoma',
2884 'v4' => 'tahoma,arial,helvetica,sans-serif',
2885 'k5' => 'Times New Roman',
2886 'v5' => 'times new roman,times,serif',
2887 'k6' => 'Verdana',
2888 'v6' => 'verdana,arial,helvetica,sans-serif',
2889 'k7' => 'Impact',
2890 'v7' => 'impact',
2891 'k8' => 'Wingdings',
2892 'v8' => 'wingdings');
2893 parent::admin_setting($name, $visiblename, $description, $defaults);
2896 function get_setting() {
2897 global $CFG;
2898 $result = $this->config_read($this->name);
2899 if (is_null($result)) {
2900 return NULL;
2902 $i = 0;
2903 $currentsetting = array();
2904 $items = explode(';', $result);
2905 foreach ($items as $item) {
2906 $item = explode(':', $item);
2907 $currentsetting['k'.$i] = $item[0];
2908 $currentsetting['v'.$i] = $item[1];
2909 $i++;
2911 return $currentsetting;
2914 function write_setting($data) {
2916 // there miiight be an easier way to do this :)
2917 // if this is changed, make sure the $defaults array above is modified so that this
2918 // function processes it correctly
2920 $keys = array();
2921 $values = array();
2923 foreach ($data as $key => $value) {
2924 if (substr($key,0,1) == 'k') {
2925 $keys[substr($key,1)] = $value;
2926 } elseif (substr($key,0,1) == 'v') {
2927 $values[substr($key,1)] = $value;
2931 $result = array();
2932 for ($i = 0; $i < count($keys); $i++) {
2933 if (($keys[$i] !== '') && ($values[$i] !== '')) {
2934 $result[] = clean_param($keys[$i],PARAM_NOTAGS).':'.clean_param($values[$i], PARAM_NOTAGS);
2938 return ($this->config_write($this->name, implode(';', $result)) ? '' : get_string('errorsetting', 'admin'));
2941 function output_html($data, $query='') {
2942 $fullname = $this->get_full_name();
2943 $return = '<div class="form-group">';
2944 for ($i = 0; $i < count($data) / 2; $i++) {
2945 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
2946 $return .= '&nbsp;&nbsp;';
2947 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
2949 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
2950 $return .= '&nbsp;&nbsp;';
2951 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2952 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
2953 $return .= '&nbsp;&nbsp;';
2954 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
2955 $return .= '</div>';
2957 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2962 class admin_setting_emoticons extends admin_setting {
2964 var $items;
2966 function admin_setting_emoticons() {
2967 global $CFG;
2968 $name = 'emoticons';
2969 $visiblename = get_string('emoticons', 'admin');
2970 $description = get_string('configemoticons', 'admin');
2971 $defaults = array('k0' => ':-)',
2972 'v0' => 'smiley',
2973 'k1' => ':)',
2974 'v1' => 'smiley',
2975 'k2' => ':-D',
2976 'v2' => 'biggrin',
2977 'k3' => ';-)',
2978 'v3' => 'wink',
2979 'k4' => ':-/',
2980 'v4' => 'mixed',
2981 'k5' => 'V-.',
2982 'v5' => 'thoughtful',
2983 'k6' => ':-P',
2984 'v6' => 'tongueout',
2985 'k7' => 'B-)',
2986 'v7' => 'cool',
2987 'k8' => '^-)',
2988 'v8' => 'approve',
2989 'k9' => '8-)',
2990 'v9' => 'wideeyes',
2991 'k10' => ':o)',
2992 'v10' => 'clown',
2993 'k11' => ':-(',
2994 'v11' => 'sad',
2995 'k12' => ':(',
2996 'v12' => 'sad',
2997 'k13' => '8-.',
2998 'v13' => 'shy',
2999 'k14' => ':-I',
3000 'v14' => 'blush',
3001 'k15' => ':-X',
3002 'v15' => 'kiss',
3003 'k16' => '8-o',
3004 'v16' => 'surprise',
3005 'k17' => 'P-|',
3006 'v17' => 'blackeye',
3007 'k18' => '8-[',
3008 'v18' => 'angry',
3009 'k19' => 'xx-P',
3010 'v19' => 'dead',
3011 'k20' => '|-.',
3012 'v20' => 'sleepy',
3013 'k21' => '}-]',
3014 'v21' => 'evil',
3015 'k22' => '(h)',
3016 'v22' => 'heart',
3017 'k23' => '(heart)',
3018 'v23' => 'heart',
3019 'k24' => '(y)',
3020 'v24' => 'yes',
3021 'k25' => '(n)',
3022 'v25' => 'no',
3023 'k26' => '(martin)',
3024 'v26' => 'martin',
3025 'k27' => '( )',
3026 'v27' => 'egg');
3027 parent::admin_setting($name, $visiblename, $description, $defaults);
3030 function get_setting() {
3031 global $CFG;
3032 $result = $this->config_read($this->name);
3033 if (is_null($result)) {
3034 return NULL;
3036 $i = 0;
3037 $currentsetting = array();
3038 $items = explode('{;}', $result);
3039 foreach ($items as $item) {
3040 $item = explode('{:}', $item);
3041 $currentsetting['k'.$i] = $item[0];
3042 $currentsetting['v'.$i] = $item[1];
3043 $i++;
3045 return $currentsetting;
3048 function write_setting($data) {
3050 // there miiight be an easier way to do this :)
3051 // if this is changed, make sure the $defaults array above is modified so that this
3052 // function processes it correctly
3054 $keys = array();
3055 $values = array();
3057 foreach ($data as $key => $value) {
3058 if (substr($key,0,1) == 'k') {
3059 $keys[substr($key,1)] = $value;
3060 } elseif (substr($key,0,1) == 'v') {
3061 $values[substr($key,1)] = $value;
3065 $result = array();
3066 for ($i = 0; $i < count($keys); $i++) {
3067 if (($keys[$i] !== '') && ($values[$i] !== '')) {
3068 $result[] = clean_param($keys[$i],PARAM_NOTAGS).'{:}'.clean_param($values[$i], PARAM_NOTAGS);
3072 return ($this->config_write($this->name, implode('{;}', $result)) ? '' : get_string('errorsetting', 'admin').$this->visiblename.'<br />');
3075 function output_html($data, $query='') {
3076 $fullname = $this->get_full_name();
3077 $return = '<div class="form-group">';
3078 for ($i = 0; $i < count($data) / 2; $i++) {
3079 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
3080 $return .= '&nbsp;&nbsp;';
3081 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
3083 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
3084 $return .= '&nbsp;&nbsp;';
3085 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
3086 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
3087 $return .= '&nbsp;&nbsp;';
3088 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
3089 $return .= '</div>';
3091 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3097 * Setting for spellchecker language selection.
3099 class admin_setting_special_editordictionary extends admin_setting_configselect {
3101 function admin_setting_special_editordictionary() {
3102 $name = 'editordictionary';
3103 $visiblename = get_string('editordictionary','admin');
3104 $description = get_string('configeditordictionary', 'admin');
3105 parent::admin_setting_configselect($name, $visiblename, $description, '', NULL);
3108 function load_choices() {
3109 // function borrowed from the old moodle/admin/editor.php, slightly modified
3110 // Get all installed dictionaries in the system
3111 if (is_array($this->choices)) {
3112 return true;
3115 $this->choices = array();
3117 global $CFG;
3119 clearstatcache();
3121 // If aspellpath isn't set don't even bother ;-)
3122 if (empty($CFG->aspellpath)) {
3123 $this->choices['error'] = 'Empty aspell path!';
3124 return true;
3127 // Do we have access to popen function?
3128 if (!function_exists('popen')) {
3129 $this->choices['error'] = 'Popen function disabled!';
3130 return true;
3133 $cmd = $CFG->aspellpath;
3134 $output = '';
3135 $dictionaries = array();
3137 if(!($handle = @popen(escapeshellarg($cmd).' dump dicts', 'r'))) {
3138 $this->choices['error'] = 'Couldn\'t create handle!';
3141 while(!feof($handle)) {
3142 $output .= fread($handle, 1024);
3144 @pclose($handle);
3146 $dictionaries = explode(chr(10), $output);
3147 foreach ($dictionaries as $dict) {
3148 if (empty($dict)) {
3149 continue;
3151 $this->choices[$dict] = $dict;
3154 if (empty($this->choices)) {
3155 $this->choices['error'] = 'Error! Check your aspell installation!';
3157 return true;
3162 class admin_setting_special_editorhidebuttons extends admin_setting {
3163 var $items;
3165 function admin_setting_special_editorhidebuttons() {
3166 parent::admin_setting('editorhidebuttons', get_string('editorhidebuttons', 'admin'),
3167 get_string('confeditorhidebuttons', 'admin'), array());
3168 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
3169 $this->items = array('fontname' => '',
3170 'fontsize' => '',
3171 'formatblock' => '',
3172 'bold' => 'ed_format_bold.gif',
3173 'italic' => 'ed_format_italic.gif',
3174 'underline' => 'ed_format_underline.gif',
3175 'strikethrough' => 'ed_format_strike.gif',
3176 'subscript' => 'ed_format_sub.gif',
3177 'superscript' => 'ed_format_sup.gif',
3178 'copy' => 'ed_copy.gif',
3179 'cut' => 'ed_cut.gif',
3180 'paste' => 'ed_paste.gif',
3181 'clean' => 'ed_wordclean.gif',
3182 'undo' => 'ed_undo.gif',
3183 'redo' => 'ed_redo.gif',
3184 'justifyleft' => 'ed_align_left.gif',
3185 'justifycenter' => 'ed_align_center.gif',
3186 'justifyright' => 'ed_align_right.gif',
3187 'justifyfull' => 'ed_align_justify.gif',
3188 'lefttoright' => 'ed_left_to_right.gif',
3189 'righttoleft' => 'ed_right_to_left.gif',
3190 'insertorderedlist' => 'ed_list_num.gif',
3191 'insertunorderedlist' => 'ed_list_bullet.gif',
3192 'outdent' => 'ed_indent_less.gif',
3193 'indent' => 'ed_indent_more.gif',
3194 'forecolor' => 'ed_color_fg.gif',
3195 'hilitecolor' => 'ed_color_bg.gif',
3196 'inserthorizontalrule' => 'ed_hr.gif',
3197 'createanchor' => 'ed_anchor.gif',
3198 'createlink' => 'ed_link.gif',
3199 'unlink' => 'ed_unlink.gif',
3200 'insertimage' => 'ed_image.gif',
3201 'inserttable' => 'insert_table.gif',
3202 'insertsmile' => 'em.icon.smile.gif',
3203 'insertchar' => 'icon_ins_char.gif',
3204 'spellcheck' => 'spell-check.gif',
3205 'htmlmode' => 'ed_html.gif',
3206 'popupeditor' => 'fullscreen_maximize.gif',
3207 'search_replace' => 'ed_replace.gif');
3210 function get_setting() {
3211 $result = $this->config_read($this->name);
3212 if (is_null($result)) {
3213 return NULL;
3215 if ($result === '') {
3216 return array();
3218 return explode(' ', $result);
3221 function write_setting($data) {
3222 if (!is_array($data)) {
3223 return ''; // ignore it
3225 unset($data['xxxxx']);
3226 $result = array();
3228 foreach ($data as $key => $value) {
3229 if (!isset($this->items[$key])) {
3230 return get_string('errorsetting', 'admin');
3232 if ($value == '1') {
3233 $result[] = $key;
3236 return ($this->config_write($this->name, implode(' ', $result)) ? '' : get_string('errorsetting', 'admin'));
3239 function output_html($data, $query='') {
3241 global $CFG;
3243 // checkboxes with input name="$this->name[$key]" value="1"
3244 // we do 15 fields per column
3246 $return = '<div class="form-group">';
3247 $return .= '<table><tr><td valign="top" align="right">';
3248 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3250 $count = 0;
3252 foreach($this->items as $key => $value) {
3253 if ($count % 15 == 0 and $count != 0) {
3254 $return .= '</td><td valign="top" align="right">';
3257 $return .= '<label for="'.$this->get_id().$key.'">';
3258 $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;';
3259 $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;';
3260 $return .= '</label>';
3261 $count++;
3262 if ($count % 15 != 0) {
3263 $return .= '<br /><br />';
3267 $return .= '</td></tr>';
3268 $return .= '</table>';
3269 $return .= '</div>';
3271 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3276 * Special setting for limiting of the list of available languages.
3278 class admin_setting_langlist extends admin_setting_configtext {
3279 function admin_setting_langlist() {
3280 parent::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
3283 function write_setting($data) {
3284 $return = parent::write_setting($data);
3285 get_list_of_languages(true);//refresh the list
3286 return $return;
3291 * Course category selection
3293 class admin_settings_coursecat_select extends admin_setting_configselect {
3294 function admin_settings_coursecat_select($name, $visiblename, $description, $defaultsetting) {
3295 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, NULL);
3298 function load_choices() {
3299 global $CFG;
3300 require_once($CFG->dirroot.'/course/lib.php');
3301 if (is_array($this->choices)) {
3302 return true;
3304 $this->choices = make_categories_options();
3305 return true;
3309 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
3310 function admin_setting_special_backupdays() {
3311 parent::admin_setting_configmulticheckbox2('backup_sche_weekdays', get_string('schedule'), get_string('backupschedulehelp'), array(), NULL);
3312 $this->plugin = 'backup';
3315 function load_choices() {
3316 if (is_array($this->choices)) {
3317 return true;
3319 $this->choices = array();
3320 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3321 foreach ($days as $day) {
3322 $this->choices[$day] = get_string($day, 'calendar');
3324 return true;
3329 * Special debug setting
3331 class admin_setting_special_debug extends admin_setting_configselect {
3332 function admin_setting_special_debug() {
3333 parent::admin_setting_configselect('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
3336 function load_choices() {
3337 if (is_array($this->choices)) {
3338 return true;
3340 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
3341 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
3342 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
3343 DEBUG_ALL => get_string('debugall', 'admin'),
3344 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
3345 return true;
3350 class admin_setting_special_calendar_weekend extends admin_setting {
3351 function admin_setting_special_calendar_weekend() {
3352 $name = 'calendar_weekend';
3353 $visiblename = get_string('calendar_weekend', 'admin');
3354 $description = get_string('helpweekenddays', 'admin');
3355 $default = array ('0', '6'); // Saturdays and Sundays
3356 parent::admin_setting($name, $visiblename, $description, $default);
3359 function get_setting() {
3360 $result = $this->config_read($this->name);
3361 if (is_null($result)) {
3362 return NULL;
3364 if ($result === '') {
3365 return array();
3367 $settings = array();
3368 for ($i=0; $i<7; $i++) {
3369 if ($result & (1 << $i)) {
3370 $settings[] = $i;
3373 return $settings;
3376 function write_setting($data) {
3377 if (!is_array($data)) {
3378 return '';
3380 unset($data['xxxxx']);
3381 $result = 0;
3382 foreach($data as $index) {
3383 $result |= 1 << $index;
3385 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
3388 function output_html($data, $query='') {
3389 // The order matters very much because of the implied numeric keys
3390 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3391 $return = '<table><thead><tr>';
3392 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3393 foreach($days as $index => $day) {
3394 $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>';
3396 $return .= '</tr></thead><tbody><tr>';
3397 foreach($days as $index => $day) {
3398 $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>';
3400 $return .= '</tr></tbody></table>';
3402 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3409 * Graded roles in gradebook
3411 class admin_setting_special_gradebookroles extends admin_setting_configmulticheckbox {
3412 function admin_setting_special_gradebookroles() {
3413 parent::admin_setting_configmulticheckbox('gradebookroles', get_string('gradebookroles', 'admin'),
3414 get_string('configgradebookroles', 'admin'), NULL, NULL);
3417 function load_choices() {
3418 global $CFG;
3419 if (empty($CFG->rolesactive)) {
3420 return false;
3422 if (is_array($this->choices)) {
3423 return true;
3425 if ($roles = get_records('role')) {
3426 $this->choices = array();
3427 foreach($roles as $role) {
3428 $this->choices[$role->id] = format_string($role->name);
3430 return true;
3431 } else {
3432 return false;
3436 function get_defaultsetting() {
3437 global $CFG;
3438 if (empty($CFG->rolesactive)) {
3439 return NULL;
3441 $result = array();
3442 if ($studentroles = get_roles_with_capability('moodle/legacy:student', CAP_ALLOW)) {
3443 foreach ($studentroles as $studentrole) {
3444 $result[$studentrole->id] = '1';
3447 return $result;
3451 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
3452 function write_setting($data) {
3453 global $CFG;
3455 $oldvalue = $this->config_read($this->name);
3456 $return = parent::write_setting($data);
3457 $newvalue = $this->config_read($this->name);
3459 if ($oldvalue !== $newvalue) {
3460 // force full regrading
3461 set_field('grade_items', 'needsupdate', 1, 'needsupdate', 0);
3464 return $return;
3469 * Which roles to show on course decription page
3471 class admin_setting_special_coursemanager extends admin_setting_configmulticheckbox {
3472 function admin_setting_special_coursemanager() {
3473 parent::admin_setting_configmulticheckbox('coursemanager', get_string('coursemanager', 'admin'),
3474 get_string('configcoursemanager', 'admin'), NULL, NULL);
3477 function load_choices() {
3478 if (is_array($this->choices)) {
3479 return true;
3481 if ($roles = get_records('role','','','sortorder')) {
3482 $this->choices = array();
3483 foreach($roles as $role) {
3484 $this->choices[$role->id] = format_string($role->name);
3486 return true;
3488 return false;
3491 function get_defaultsetting() {
3492 global $CFG;
3493 if (empty($CFG->rolesactive)) {
3494 return NULL;
3496 $result = array();
3497 if ($teacherroles = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW)) {
3498 foreach ($teacherroles as $teacherrole) {
3499 $result[$teacherrole->id] = '1';
3502 return $result;
3506 class admin_setting_special_gradelimiting extends admin_setting_configcheckbox {
3507 function admin_setting_special_gradelimiting() {
3508 parent::admin_setting_configcheckbox('unlimitedgrades', get_string('unlimitedgrades', 'grades'),
3509 get_string('configunlimitedgrades', 'grades'), '0', '1', '0');
3512 function regrade_all() {
3513 global $CFG;
3514 require_once("$CFG->libdir/gradelib.php");
3515 grade_force_site_regrading();
3518 function write_setting($data) {
3519 $previous = $this->get_setting();
3521 if ($previous === null) {
3522 if ($data) {
3523 $this->regrade_all();
3525 } else {
3526 if ($data != $previous) {
3527 $this->regrade_all();
3530 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
3536 * Primary grade export plugin - has state tracking.
3538 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
3539 function admin_setting_special_gradeexport() {
3540 parent::admin_setting_configmulticheckbox('gradeexport', get_string('gradeexport', 'admin'),
3541 get_string('configgradeexport', 'admin'), array(), NULL);
3544 function load_choices() {
3545 if (is_array($this->choices)) {
3546 return true;
3548 $this->choices = array();
3550 if ($plugins = get_list_of_plugins('grade/export')) {
3551 foreach($plugins as $plugin) {
3552 $this->choices[$plugin] = get_string('modulename', 'gradeexport_'.$plugin);
3555 return true;
3560 * Grade category settings
3562 class admin_setting_gradecat_combo extends admin_setting {
3564 var $choices;
3566 function admin_setting_gradecat_combo($name, $visiblename, $description, $defaultsetting, $choices) {
3567 $this->choices = $choices;
3568 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
3571 function get_setting() {
3572 global $CFG;
3574 $value = $this->config_read($this->name);
3575 $flag = $this->config_read($this->name.'_flag');
3577 if (is_null($value) or is_null($flag)) {
3578 return NULL;
3581 $flag = (int)$flag;
3582 $forced = (boolean)(1 & $flag); // first bit
3583 $adv = (boolean)(2 & $flag); // second bit
3585 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
3588 function write_setting($data) {
3589 global $CFG;
3591 $value = $data['value'];
3592 $forced = empty($data['forced']) ? 0 : 1;
3593 $adv = empty($data['adv']) ? 0 : 2;
3594 $flag = ($forced | $adv); //bitwise or
3596 if (!in_array($value, array_keys($this->choices))) {
3597 return 'Error setting ';
3600 $oldvalue = $this->config_read($this->name);
3601 $oldflag = (int)$this->config_read($this->name.'_flag');
3602 $oldforced = (1 & $oldflag); // first bit
3604 $result1 = $this->config_write($this->name, $value);
3605 $result2 = $this->config_write($this->name.'_flag', $flag);
3607 // force regrade if needed
3608 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
3609 require_once($CFG->libdir.'/gradelib.php');
3610 grade_category::updated_forced_settings();
3613 if ($result1 and $result2) {
3614 return '';
3615 } else {
3616 return get_string('errorsetting', 'admin');
3620 function output_html($data, $query='') {
3621 $value = $data['value'];
3622 $forced = !empty($data['forced']);
3623 $adv = !empty($data['adv']);
3625 $default = $this->get_defaultsetting();
3626 if (!is_null($default)) {
3627 $defaultinfo = array();
3628 if (isset($this->choices[$default['value']])) {
3629 $defaultinfo[] = $this->choices[$default['value']];
3631 if (!empty($default['forced'])) {
3632 $defaultinfo[] = get_string('force');
3634 if (!empty($default['adv'])) {
3635 $defaultinfo[] = get_string('advanced');
3637 $defaultinfo = implode(', ', $defaultinfo);
3639 } else {
3640 $defaultinfo = NULL;
3644 $return = '<div class="form-group">';
3645 $return .= '<select class="form-select" id="'.$this->get_id().'" name="'.$this->get_full_name().'[value]">';
3646 foreach ($this->choices as $key => $val) {
3647 // the string cast is needed because key may be integer - 0 is equal to most strings!
3648 $return .= '<option value="'.$key.'"'.((string)$key==$value ? ' selected="selected"' : '').'>'.$val.'</option>';
3650 $return .= '</select>';
3651 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'force" name="'.$this->get_full_name().'[forced]" value="1" '.($forced ? 'checked="checked"' : '').' />'
3652 .'<label for="'.$this->get_id().'force">'.get_string('force').'</label>';
3653 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'adv" name="'.$this->get_full_name().'[adv]" value="1" '.($adv ? 'checked="checked"' : '').' />'
3654 .'<label for="'.$this->get_id().'adv">'.get_string('advanced').'</label>';
3655 $return .= '</div>';
3657 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
3663 * Selection of grade report in user profiles
3665 class admin_setting_grade_profilereport extends admin_setting_configselect {
3666 function admin_setting_grade_profilereport() {
3667 parent::admin_setting_configselect('grade_profilereport', get_string('profilereport', 'grades'), get_string('configprofilereport', 'grades'), 'user', null);
3670 function load_choices() {
3671 if (is_array($this->choices)) {
3672 return true;
3674 $this->choices = array();
3676 global $CFG;
3677 require_once($CFG->libdir.'/gradelib.php');
3679 foreach (get_list_of_plugins('grade/report') as $plugin) {
3680 if (file_exists($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php')) {
3681 require_once($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php');
3682 $functionname = 'grade_report_'.$plugin.'_profilereport';
3683 if (function_exists($functionname)) {
3684 $this->choices[$plugin] = get_string('modulename', 'gradereport_'.$plugin, NULL, $CFG->dirroot.'/grade/report/'.$plugin.'/lang/');
3688 return true;
3693 * Special class for register auth selection
3695 class admin_setting_special_registerauth extends admin_setting_configselect {
3696 function admin_setting_special_registerauth() {
3697 parent::admin_setting_configselect('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null);
3700 function get_defaultsettings() {
3701 $this->load_choices();
3702 if (array_key_exists($this->defaultsetting, $this->choices)) {
3703 return $this->defaultsetting;
3704 } else {
3705 return '';
3709 function load_choices() {
3710 global $CFG;
3712 if (is_array($this->choices)) {
3713 return true;
3715 $this->choices = array();
3716 $this->choices[''] = get_string('disable');
3718 $authsenabled = get_enabled_auth_plugins(true);
3720 foreach ($authsenabled as $auth) {
3721 $authplugin = get_auth_plugin($auth);
3722 if (!$authplugin->can_signup()) {
3723 continue;
3725 // Get the auth title (from core or own auth lang files)
3726 $authtitle = $authplugin->get_title();
3727 $this->choices[$auth] = $authtitle;
3729 return true;
3734 * Module manage page
3736 class admin_page_managemods extends admin_externalpage {
3737 function admin_page_managemods() {
3738 global $CFG;
3739 parent::admin_externalpage('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
3742 function search($query) {
3743 if ($result = parent::search($query)) {
3744 return $result;
3747 $found = false;
3748 if ($modules = get_records('modules')) {
3749 $textlib = textlib_get_instance();
3750 foreach ($modules as $module) {
3751 if (strpos($module->name, $query) !== false) {
3752 $found = true;
3753 break;
3755 $strmodulename = get_string('modulename', $module->name);
3756 if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
3757 $found = true;
3758 break;
3762 if ($found) {
3763 $result = new object();
3764 $result->page = $this;
3765 $result->settings = array();
3766 return array($this->name => $result);
3767 } else {
3768 return array();
3774 * Enrolment manage page
3776 class admin_enrolment_page extends admin_externalpage {
3777 function admin_enrolment_page() {
3778 global $CFG;
3779 parent::admin_externalpage('enrolment', get_string('enrolments'), $CFG->wwwroot . '/'.$CFG->admin.'/enrol.php');
3782 function search($query) {
3783 if ($result = parent::search($query)) {
3784 return $result;
3787 $found = false;
3789 if ($modules = get_list_of_plugins('enrol')) {
3790 $textlib = textlib_get_instance();
3791 foreach ($modules as $plugin) {
3792 if (strpos($plugin, $query) !== false) {
3793 $found = true;
3794 break;
3796 $strmodulename = get_string('enrolname', "enrol_$plugin");
3797 if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
3798 $found = true;
3799 break;
3803 //ugly harcoded hacks
3804 if (strpos('sendcoursewelcomemessage', $query) !== false) {
3805 $found = true;
3806 } else if (strpos($textlib->strtolower(get_string('sendcoursewelcomemessage', 'admin')), $query) !== false) {
3807 $found = true;
3808 } else if (strpos($textlib->strtolower(get_string('configsendcoursewelcomemessage', 'admin')), $query) !== false) {
3809 $found = true;
3810 } else if (strpos($textlib->strtolower(get_string('configenrolmentplugins', 'admin')), $query) !== false) {
3811 $found = true;
3813 if ($found) {
3814 $result = new object();
3815 $result->page = $this;
3816 $result->settings = array();
3817 return array($this->name => $result);
3818 } else {
3819 return array();
3825 * Blocks manage page
3827 class admin_page_manageblocks extends admin_externalpage {
3828 function admin_page_manageblocks() {
3829 global $CFG;
3830 parent::admin_externalpage('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
3833 function search($query) {
3834 global $CFG;
3835 if ($result = parent::search($query)) {
3836 return $result;
3839 $found = false;
3840 if (!empty($CFG->blocks_version) and $blocks = get_records('block')) {
3841 $textlib = textlib_get_instance();
3842 foreach ($blocks as $block) {
3843 if (strpos($block->name, $query) !== false) {
3844 $found = true;
3845 break;
3847 $strblockname = get_string('blockname', 'block_'.$block->name);
3848 if (strpos($textlib->strtolower($strblockname), $query) !== false) {
3849 $found = true;
3850 break;
3854 if ($found) {
3855 $result = new object();
3856 $result->page = $this;
3857 $result->settings = array();
3858 return array($this->name => $result);
3859 } else {
3860 return array();
3866 * Special class for authentication administration.
3868 class admin_setting_manageauths extends admin_setting {
3869 function admin_setting_manageauths() {
3870 parent::admin_setting('authsui', get_string('authsettings', 'admin'), '', '');
3873 function get_setting() {
3874 return true;
3877 function get_defaultsetting() {
3878 return true;
3881 function write_setting($data) {
3882 // do not write any setting
3883 return '';
3886 function is_related($query) {
3887 if (parent::is_related($query)) {
3888 return true;
3891 $textlib = textlib_get_instance();
3892 $authsavailable = get_list_of_plugins('auth');
3893 foreach ($authsavailable as $auth) {
3894 if (strpos($auth, $query) !== false) {
3895 return true;
3897 $authplugin = get_auth_plugin($auth);
3898 $authtitle = $authplugin->get_title();
3899 if (strpos($textlib->strtolower($authtitle), $query) !== false) {
3900 return true;
3903 return false;
3906 function output_html($data, $query='') {
3907 global $CFG;
3910 // display strings
3911 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
3912 'settings', 'edit', 'name', 'enable', 'disable',
3913 'up', 'down', 'none'));
3914 $txt->updown = "$txt->up/$txt->down";
3916 $authsavailable = get_list_of_plugins('auth');
3917 get_enabled_auth_plugins(true); // fix the list of enabled auths
3918 if (empty($CFG->auth)) {
3919 $authsenabled = array();
3920 } else {
3921 $authsenabled = explode(',', $CFG->auth);
3924 // construct the display array, with enabled auth plugins at the top, in order
3925 $displayauths = array();
3926 $registrationauths = array();
3927 $registrationauths[''] = $txt->disable;
3928 foreach ($authsenabled as $auth) {
3929 $authplugin = get_auth_plugin($auth);
3930 /// Get the auth title (from core or own auth lang files)
3931 $authtitle = $authplugin->get_title();
3932 /// Apply titles
3933 $displayauths[$auth] = $authtitle;
3934 if ($authplugin->can_signup()) {
3935 $registrationauths[$auth] = $authtitle;
3939 foreach ($authsavailable as $auth) {
3940 if (array_key_exists($auth, $displayauths)) {
3941 continue; //already in the list
3943 $authplugin = get_auth_plugin($auth);
3944 /// Get the auth title (from core or own auth lang files)
3945 $authtitle = $authplugin->get_title();
3946 /// Apply titles
3947 $displayauths[$auth] = $authtitle;
3948 if ($authplugin->can_signup()) {
3949 $registrationauths[$auth] = $authtitle;
3953 $return = print_heading(get_string('actauthhdr', 'auth'), '', 3, 'main', true);
3954 $return .= print_box_start('generalbox authsui', '', true);
3956 $table = new object();
3957 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings);
3958 $table->align = array('left', 'center', 'center', 'center');
3959 $table->width = '90%';
3960 $table->data = array();
3962 //add always enabled plugins first
3963 $displayname = "<span>".$displayauths['manual']."</span>";
3964 $settings = "<a href=\"auth_config.php?auth=manual\">{$txt->settings}</a>";
3965 //$settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
3966 $table->data[] = array($displayname, '', '', $settings);
3967 $displayname = "<span>".$displayauths['nologin']."</span>";
3968 $settings = "<a href=\"auth_config.php?auth=nologin\">{$txt->settings}</a>";
3969 $table->data[] = array($displayname, '', '', $settings);
3972 // iterate through auth plugins and add to the display table
3973 $updowncount = 1;
3974 $authcount = count($authsenabled);
3975 $url = "auth.php?sesskey=" . sesskey();
3976 foreach ($displayauths as $auth => $name) {
3977 if ($auth == 'manual' or $auth == 'nologin') {
3978 continue;
3980 // hide/show link
3981 if (in_array($auth, $authsenabled)) {
3982 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
3983 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"disable\" /></a>";
3984 // $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\"><input type=\"checkbox\" checked /></a>";
3985 $enabled = true;
3986 $displayname = "<span>$name</span>";
3988 else {
3989 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
3990 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"enable\" /></a>";
3991 // $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\"><input type=\"checkbox\" /></a>";
3992 $enabled = false;
3993 $displayname = "<span class=\"dimmed_text\">$name</span>";
3996 // up/down link (only if auth is enabled)
3997 $updown = '';
3998 if ($enabled) {
3999 if ($updowncount > 1) {
4000 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
4001 $updown .= "<img src=\"{$CFG->pixpath}/t/up.gif\" alt=\"up\" /></a>&nbsp;";
4003 else {
4004 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
4006 if ($updowncount < $authcount) {
4007 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
4008 $updown .= "<img src=\"{$CFG->pixpath}/t/down.gif\" alt=\"down\" /></a>";
4010 else {
4011 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />";
4013 ++ $updowncount;
4016 // settings link
4017 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
4018 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
4019 } else {
4020 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
4023 // add a row to the table
4024 $table->data[] =array($displayname, $hideshow, $updown, $settings);
4026 $return .= print_table($table, true);
4027 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
4028 $return .= print_box_end(true);
4029 return highlight($query, $return);
4033 * Special class for filter administration.
4035 class admin_setting_managefilters extends admin_setting {
4036 function admin_setting_managefilters() {
4037 parent::admin_setting('filtersui', get_string('filtersettings', 'admin'), '', '');
4040 function get_setting() {
4041 return true;
4044 function get_defaultsetting() {
4045 return true;
4048 function write_setting($data) {
4049 // do not write any setting
4050 return '';
4053 function is_related($query) {
4054 if (parent::is_related($query)) {
4055 return true;
4058 $textlib = textlib_get_instance();
4059 $filterlocations = array('mod','filter');
4060 foreach ($filterlocations as $filterlocation) {
4061 $plugins = get_list_of_plugins($filterlocation);
4062 foreach ($plugins as $plugin) {
4063 if (strpos($plugin, $query) !== false) {
4064 return true;
4066 $name = get_string('filtername', $plugin);
4067 if (strpos($textlib->strtolower($name), $query) !== false) {
4068 return true;
4072 return false;
4075 function output_html($data, $query='') {
4076 global $CFG;
4078 $strname = get_string('name');
4079 $strhide = get_string('disable');
4080 $strshow = get_string('enable');
4081 $strhideshow = "$strhide/$strshow";
4082 $strsettings = get_string('settings');
4083 $strup = get_string('up');
4084 $strdown = get_string('down');
4085 $strupdown = "$strup/$strdown";
4087 // get a list of possible filters (and translate name if possible)
4088 // note filters can be in the dedicated filters area OR in their
4089 // associated modules
4090 $installedfilters = array();
4091 $filtersettings_new = array();
4092 $filtersettings_old = array();
4093 $filterlocations = array('mod','filter');
4094 foreach ($filterlocations as $filterlocation) {
4095 $plugins = get_list_of_plugins($filterlocation);
4096 foreach ($plugins as $plugin) {
4097 $pluginpath = "$CFG->dirroot/$filterlocation/$plugin/filter.php";
4098 $settingspath_new = "$CFG->dirroot/$filterlocation/$plugin/filtersettings.php";
4099 $settingspath_old = "$CFG->dirroot/$filterlocation/$plugin/filterconfig.html";
4100 if (is_readable($pluginpath)) {
4101 $name = trim(get_string("filtername", $plugin));
4102 if (empty($name) or ($name == '[[filtername]]')) {
4103 $textlib = textlib_get_instance();
4104 $name = $textlib->strtotitle($plugin);
4106 $installedfilters["$filterlocation/$plugin"] = $name;
4107 if (is_readable($settingspath_new)) {
4108 $filtersettings_new[] = "$filterlocation/$plugin";
4109 } else if (is_readable($settingspath_old)) {
4110 $filtersettings_old[] = "$filterlocation/$plugin";
4116 // get all the currently selected filters
4117 if (!empty($CFG->textfilters)) {
4118 $oldactivefilters = explode(',', $CFG->textfilters);
4119 $oldactivefilters = array_unique($oldactivefilters);
4120 } else {
4121 $oldactivefilters = array();
4124 // take this opportunity to clean up filters
4125 $activefilters = array();
4126 foreach ($oldactivefilters as $oldactivefilter) {
4127 if (!empty($oldactivefilter) and array_key_exists($oldactivefilter, $installedfilters)) {
4128 $activefilters[] = $oldactivefilter;
4132 // construct the display array with installed filters
4133 // at the top in the right order
4134 $displayfilters = array();
4135 foreach ($activefilters as $activefilter) {
4136 $name = $installedfilters[$activefilter];
4137 $displayfilters[$activefilter] = $name;
4139 foreach ($installedfilters as $key => $filter) {
4140 if (!array_key_exists($key, $displayfilters)) {
4141 $displayfilters[$key] = $filter;
4145 $return = print_heading(get_string('actfilterhdr', 'filters'), '', 3, 'main', true);
4146 $return .= print_box_start('generalbox filtersui', '', true);
4148 $table = new object();
4149 $table->head = array($strname, $strhideshow, $strupdown, $strsettings);
4150 $table->align = array('left', 'center', 'center', 'center');
4151 $table->width = '90%';
4152 $table->data = array();
4154 $filtersurl = "$CFG->wwwroot/$CFG->admin/filters.php?sesskey=".sesskey();
4155 $imgurl = "$CFG->pixpath/t";
4157 // iterate through filters adding to display table
4158 $updowncount = 1;
4159 $activefilterscount = count($activefilters);
4160 foreach ($displayfilters as $path => $name) {
4161 $upath = urlencode($path);
4162 // get hide/show link
4163 if (in_array($path, $activefilters)) {
4164 $hideshow = "<a href=\"$filtersurl&amp;action=hide&amp;filterpath=$upath\">";
4165 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"$strhide\" /></a>";
4166 $hidden = false;
4167 $displayname = "<span>$name</span>";
4169 else {
4170 $hideshow = "<a href=\"$filtersurl&amp;action=show&amp;filterpath=$upath\">";
4171 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"$strshow\" /></a>";
4172 $hidden = true;
4173 $displayname = "<span class=\"dimmed_text\">$name</span>";
4176 // get up/down link (only if not hidden)
4177 $updown = '';
4178 if (!$hidden) {
4179 if ($updowncount>1) {
4180 $updown .= "<a href=\"$filtersurl&amp;action=up&amp;filterpath=$upath\">";
4181 $updown .= "<img src=\"$imgurl/up.gif\" alt=\"$strup\" /></a>&nbsp;";
4183 else {
4184 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
4186 if ($updowncount<$activefilterscount) {
4187 $updown .= "<a href=\"$filtersurl&amp;action=down&amp;filterpath=$upath\">";
4188 $updown .= "<img src=\"$imgurl/down.gif\" alt=\"$strdown\" /></a>";
4190 else {
4191 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />";
4193 ++$updowncount;
4196 // settings link (if defined)
4197 $settings = '';
4198 if (in_array($path, $filtersettings_new)) {
4199 $settings = "<a href=\"settings.php?section=filtersetting".str_replace('/', '',$path)."\">$strsettings</a>";
4200 } else if (in_array($path, $filtersettings_old)) {
4201 $settings = "<a href=\"filter.php?filter=".urlencode($path)."\">$strsettings</a>";
4204 // write data into the table object
4205 $table->data[] = array($displayname, $hideshow, $updown, $settings);
4207 $return .= print_table($table, true);
4208 $return .= get_string('tablenosave', 'filters');
4209 $return .= print_box_end(true);
4210 return highlight($query, $return);
4215 * Initialise admin page - this function does require login and permission
4216 * checks specified in page definition.
4217 * This function must be called on each admin page before other code.
4218 * @param string $section name of page
4219 * @param string $extrabutton extra HTML that is added after the blocks editing on/off button.
4220 * @param string $extraurlparams an array paramname => paramvalue, or parameters that need to be
4221 * added to the turn blocks editing on/off form, so this page reloads correctly.
4222 * @param string $actualurl if the actual page being viewed is not the normal one for this
4223 * page (e.g. admin/roles/allowassin.php, instead of admin/roles/manage.php, you can pass the alternate URL here.
4225 function admin_externalpage_setup($section, $extrabutton='', $extraurlparams=array(), $actualurl='') {
4227 global $CFG, $PAGE, $USER;
4228 require_once($CFG->libdir.'/blocklib.php');
4229 require_once($CFG->dirroot.'/'.$CFG->admin.'/pagelib.php');
4231 if ($site = get_site()) {
4232 require_login();
4233 } else {
4234 redirect($CFG->wwwroot.'/'.$CFG->admin.'/index.php');
4235 die;
4238 $adminroot =& admin_get_root(false, false); // settings not required for external pages
4239 $extpage =& $adminroot->locate($section);
4241 if (empty($extpage) or !is_a($extpage, 'admin_externalpage')) {
4242 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
4243 die;
4246 // this eliminates our need to authenticate on the actual pages
4247 if (!($extpage->check_access())) {
4248 print_error('accessdenied', 'admin');
4249 die;
4252 page_map_class(PAGE_ADMIN, 'page_admin');
4253 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
4254 $PAGE->init_extra($section); // hack alert!
4255 $PAGE->set_extra_button($extrabutton);
4256 $PAGE->set_extra_url_params($extraurlparams, $actualurl);
4258 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
4260 if (!isset($USER->adminediting)) {
4261 $USER->adminediting = false;
4264 if ($PAGE->user_allowed_editing()) {
4265 if ($adminediting == 1) {
4266 $USER->adminediting = true;
4267 } elseif ($adminediting == 0) {
4268 $USER->adminediting = false;
4274 * Print header for admin page
4275 * @param string $focus focus element
4277 function admin_externalpage_print_header($focus='') {
4279 if (!is_string($focus)) {
4280 $focus = ''; // BC compatibility, there used to be adminroot parameter
4283 global $CFG, $PAGE, $SITE, $THEME;
4285 define('ADMIN_EXT_HEADER_PRINTED', 'true');
4287 if (!empty($SITE->fullname)) {
4288 $pageblocks = blocks_setup($PAGE);
4290 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
4291 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
4292 BLOCK_L_MAX_WIDTH);
4293 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
4294 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
4295 BLOCK_R_MAX_WIDTH);
4297 $PAGE->print_header('', $focus);
4298 echo '<table id="layout-table" summary=""><tr>';
4300 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
4301 foreach ($lt as $column) {
4302 $lt1[] = $column;
4303 if ($column == 'middle') break;
4305 foreach ($lt1 as $column) {
4306 switch ($column) {
4307 case 'left':
4308 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
4309 print_container_start();
4310 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
4311 print_container_end();
4312 echo '</td>';
4313 break;
4315 case 'middle':
4316 echo '<td id="middle-column">';
4317 print_container_start(true);
4318 $THEME->open_header_containers++; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
4319 break;
4321 case 'right':
4322 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
4323 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
4324 print_container_start();
4325 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
4326 print_container_end();
4327 echo '</td>';
4329 break;
4332 } else {
4333 print_header();
4338 * Print footer on admin page - please use normal print_footer() instead
4340 function admin_externalpage_print_footer() {
4342 global $CFG, $PAGE, $SITE, $THEME;
4344 define('ADMIN_EXT_FOOTER_PRINTED', 'true');
4346 if (!empty($SITE->fullname)) {
4347 $pageblocks = blocks_setup($PAGE);
4348 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
4349 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
4350 BLOCK_L_MAX_WIDTH);
4351 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
4352 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
4353 BLOCK_R_MAX_WIDTH);
4355 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
4356 foreach ($lt as $column) {
4357 if ($column != 'middle') {
4358 array_shift($lt);
4359 } else if ($column == 'middle') {
4360 break;
4363 foreach ($lt as $column) {
4364 switch ($column) {
4365 case 'left':
4366 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
4367 print_container_start();
4368 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
4369 print_container_end();
4370 echo '</td>';
4371 break;
4373 case 'middle':
4374 print_container_end();
4375 $THEME->open_header_containers--; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
4376 echo '</td>';
4377 break;
4379 case 'right':
4380 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
4381 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
4382 print_container_start();
4383 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
4384 print_container_end();
4385 echo '</td>';
4387 break;
4390 echo '</tr></table>';
4392 print_footer();
4396 * Returns the reference to admin tree root
4397 * @return reference
4399 function &admin_get_root($reload=false, $requirefulltree=true) {
4400 global $CFG;
4402 static $ADMIN = NULL;
4404 if (!is_null($ADMIN)) {
4405 $olderrors = $ADMIN->errors;
4406 $oldsearch = $ADMIN->search;
4407 $oldfulltree = $ADMIN->fulltree;
4408 } else {
4409 $olderrors = array();
4410 $oldsearch = '';
4411 $oldfulltree = false;
4414 if ($reload or ($requirefulltree and !$oldfulltree)) {
4415 $ADMIN = NULL;
4418 if (is_null($ADMIN)) {
4419 // start the admin tree!
4420 $ADMIN = new admin_root();
4421 // array of error messages and search query
4422 $ADMIN->errors = $olderrors;
4423 $ADMIN->search = $oldsearch;
4424 if ($requirefulltree) {
4425 $ADMIN->fulltree = true;
4426 } else {
4427 $ADMIN->fulltree = $oldfulltree;
4430 // we process this file first to create categories first and in correct order
4431 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
4433 // now we process all other files in admin/settings to build the admin tree
4434 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
4435 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
4436 continue;
4438 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') {
4439 // plugins are loaded last - they may insert pages anywhere
4440 continue;
4442 include($file);
4444 include($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php');
4446 if (file_exists($CFG->dirroot.'/local/settings.php')) {
4447 include($CFG->dirroot.'/local/settings.php');
4451 return $ADMIN;
4454 /// settings utility functions
4457 * This function applies default settings.
4458 * @param object $node, NULL means complete tree
4459 * @param bool $uncoditional if true overrides all values with defaults
4460 * @return void
4462 function admin_apply_default_settings($node=NULL, $unconditional=true) {
4463 global $CFG;
4465 if (is_null($node)) {
4466 $node =& admin_get_root();
4469 if (is_a($node, 'admin_category')) {
4470 $entries = array_keys($node->children);
4471 foreach ($entries as $entry) {
4472 admin_apply_default_settings($node->children[$entry], $unconditional);
4475 } else if (is_a($node, 'admin_settingpage')) {
4476 foreach ($node->settings as $setting) {
4477 if (!$unconditional and !is_null($setting->get_setting())) {
4478 //do not override existing defaults
4479 continue;
4481 $defaultsetting = $setting->get_defaultsetting();
4482 if (is_null($defaultsetting)) {
4483 // no value yet - default maybe applied after admin user creation or in upgradesettings
4484 continue;
4486 $setting->write_setting($defaultsetting);
4492 * Store changed settings, this function updates the errors variable in $ADMIN
4493 * @param object $formdata from form (without magic quotes)
4494 * @return int number of changed settings
4496 function admin_write_settings($formdata) {
4497 global $CFG, $SITE, $COURSE;
4499 $olddbsessions = !empty($CFG->dbsessions);
4500 $formdata = (array)stripslashes_recursive($formdata);
4502 $data = array();
4503 foreach ($formdata as $fullname=>$value) {
4504 if (strpos($fullname, 's_') !== 0) {
4505 continue; // not a config value
4507 $data[$fullname] = $value;
4510 $adminroot =& admin_get_root();
4511 $settings = admin_find_write_settings($adminroot, $data);
4513 $count = 0;
4514 foreach ($settings as $fullname=>$setting) {
4515 $original = serialize($setting->get_setting()); // comparison must work for arrays too
4516 $error = $setting->write_setting($data[$fullname]);
4517 if ($error !== '') {
4518 $adminroot->errors[$fullname] = new object();
4519 $adminroot->errors[$fullname]->data = $data[$fullname];
4520 $adminroot->errors[$fullname]->id = $setting->get_id();
4521 $adminroot->errors[$fullname]->error = $error;
4523 if ($original !== serialize($setting->get_setting())) {
4524 $count++;
4525 $callbackfunction = $setting->updatedcallback;
4526 if (function_exists($callbackfunction)) {
4527 $callbackfunction($fullname);
4532 if ($olddbsessions != !empty($CFG->dbsessions)) {
4533 require_logout();
4536 // now update $SITE - it might have been changed
4537 $SITE = get_record('course', 'id', $SITE->id);
4538 $COURSE = clone($SITE);
4540 // now reload all settings - some of them might depend on the changed
4541 admin_get_root(true);
4542 return $count;
4546 * Internal recursive function - finds all settings from submitted form
4548 function admin_find_write_settings($node, $data) {
4549 $return = array();
4551 if (empty($data)) {
4552 return $return;
4555 if (is_a($node, 'admin_category')) {
4556 $entries = array_keys($node->children);
4557 foreach ($entries as $entry) {
4558 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
4561 } else if (is_a($node, 'admin_settingpage')) {
4562 foreach ($node->settings as $setting) {
4563 $fullname = $setting->get_full_name();
4564 if (array_key_exists($fullname, $data)) {
4565 $return[$fullname] = $setting;
4571 return $return;
4575 * Internal function - prints the search results
4577 function admin_search_settings_html($query) {
4578 global $CFG;
4580 $textlib = textlib_get_instance();
4581 if ($textlib->strlen($query) < 2) {
4582 return '';
4584 $query = $textlib->strtolower($query);
4586 $adminroot =& admin_get_root();
4587 $findings = $adminroot->search($query);
4588 $return = '';
4589 $savebutton = false;
4591 foreach ($findings as $found) {
4592 $page = $found->page;
4593 $settings = $found->settings;
4594 if ($page->is_hidden()) {
4595 // hidden pages are not displayed in search results
4596 continue;
4598 if (is_a($page, 'admin_externalpage')) {
4599 $return .= print_heading(get_string('searchresults','admin').' - <a href="'.$page->url.'">'.highlight($query, $page->visiblename).'</a>', '', 2, 'main', true);
4600 } else if (is_a($page, 'admin_settingpage')) {
4601 $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);
4602 } else {
4603 continue;
4605 if (!empty($settings)) {
4606 $savebutton = true;
4607 $return .= '<fieldset class="adminsettings">'."\n";
4608 foreach ($settings as $setting) {
4609 $return .= '<div class="clearer"><!-- --></div>'."\n";
4610 $fullname = $setting->get_full_name();
4611 if (array_key_exists($fullname, $adminroot->errors)) {
4612 $data = $adminroot->errors[$fullname]->data;
4613 } else {
4614 $data = $setting->get_setting();
4615 if (is_null($data)) {
4616 $data = $setting->get_defaultsetting();
4619 $return .= $setting->output_html($data, $query);
4621 $return .= '</fieldset>';
4625 if ($savebutton) {
4626 $return .= '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges','admin').'" /></div>';
4629 return $return;
4633 * Internal function - returns arrays of html pages with uninitialised settings
4635 function admin_output_new_settings_by_page($node) {
4636 $return = array();
4638 if (is_a($node, 'admin_category')) {
4639 $entries = array_keys($node->children);
4640 foreach ($entries as $entry) {
4641 $return += admin_output_new_settings_by_page($node->children[$entry]);
4644 } else if (is_a($node, 'admin_settingpage')) {
4645 $newsettings = array();
4646 foreach ($node->settings as $setting) {
4647 if (is_null($setting->get_setting())) {
4648 $newsettings[] = $setting;
4651 if (count($newsettings) > 0) {
4652 $adminroot =& admin_get_root();
4653 $page = print_heading(get_string('upgradesettings','admin').' - '.$node->visiblename, '', 2, 'main', true);
4654 $page .= '<fieldset class="adminsettings">'."\n";
4655 foreach ($newsettings as $setting) {
4656 $fullname = $setting->get_full_name();
4657 if (array_key_exists($fullname, $adminroot->errors)) {
4658 $data = $adminroot->errors[$fullname]->data;
4659 } else {
4660 $data = $setting->get_setting();
4661 if (is_null($data)) {
4662 $data = $setting->get_defaultsetting();
4665 $page .= '<div class="clearer"><!-- --></div>'."\n";
4666 $page .= $setting->output_html($data);
4668 $page .= '</fieldset>';
4669 $return[$node->name] = $page;
4673 return $return;
4677 * Unconditionally applies default admin settings in main config table
4678 * @param array $defaults array of string values
4680 function apply_default_exception_settings($defaults) {
4681 foreach($defaults as $key => $value) {
4682 set_config($key, $value, NULL);
4687 * Format admin settings
4688 * @param string $object setting
4689 * @param string $title label element
4690 * @param string $form form fragment, html code - not highlighed automaticaly
4691 * @param string $description
4692 * @param bool $label link label to id
4693 * @param string $warning warning text
4694 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string
4695 * @param string $query search query to be highlighted
4697 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
4698 global $CFG;
4700 $name = $setting->name;
4701 $fullname = $setting->get_full_name();
4703 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
4704 if ($label) {
4705 $labelfor = 'for = "'.$setting->get_id().'"';
4706 } else {
4707 $labelfor = '';
4710 if (empty($setting->plugin) and array_key_exists($name, $CFG->config_php_settings)) {
4711 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
4712 } else {
4713 $override = '';
4716 if ($warning !== '') {
4717 $warning = '<div class="form-warning">'.$warning.'</div>';
4720 if (is_null($defaultinfo)) {
4721 $defaultinfo = '';
4722 } else {
4723 if ($defaultinfo === '') {
4724 $defaultinfo = get_string('emptysettingvalue', 'admin');
4726 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
4727 $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>';
4731 $str = '
4732 <div class="form-item clearfix" id="admin-'.$setting->name.'">
4733 <div class="form-label">
4734 <label '.$labelfor.'>'.highlightfast($query, $title).'<span class="form-shortname">'.highlightfast($query, $name).'</span>
4735 '.$override.$warning.'
4736 </label>
4737 </div>
4738 <div class="form-setting">'.$form.$defaultinfo.'</div>
4739 <div class="form-description">'.highlight($query, $description).'</div>
4740 </div>';
4742 $adminroot =& admin_get_root();
4743 if (array_key_exists($fullname, $adminroot->errors)) {
4744 $str = '<fieldset class="error"><legend>'.$adminroot->errors[$fullname]->error.'</legend>'.$str.'</fieldset>';
4747 return $str;
4751 * Try to upgrade the given language pack (or current language)
4752 * If it doesn't work, fail silently and return false
4754 function upgrade_language_pack($lang='') {
4755 global $CFG;
4757 if (empty($lang)) {
4758 $lang = current_language();
4761 if ($lang == 'en_utf8') {
4762 return true; // Nothing to do
4765 notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
4767 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
4768 @mkdir ($CFG->dataroot.'/lang/');
4770 require_once($CFG->libdir.'/componentlib.class.php');
4772 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
4773 $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
4775 if ($status == COMPONENT_INSTALLED) {
4776 debugging('Downloading successful: '.$lang);
4777 @unlink($CFG->dataroot.'/cache/languages');
4778 return true;
4782 return false;
4786 * Based on find_new_settings{@link ()} in upgradesettings.php
4787 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
4789 * @param string $node The node at which to start searching.
4790 * @return boolen true if any settings haven't been initialised, false if they all have
4792 function any_new_admin_settings($node) {
4794 if (is_a($node, 'admin_category')) {
4795 $entries = array_keys($node->children);
4796 foreach ($entries as $entry) {
4797 if (any_new_admin_settings($node->children[$entry])){
4798 return true;
4802 } else if (is_a($node, 'admin_settingpage')) {
4803 foreach ($node->settings as $setting) {
4804 if ($setting->get_setting() === NULL) {
4805 return true;
4810 return false;
4815 * Moved from admin/replace.php so that we can use this in cron
4816 * @param string $search - string to look for (with magic quotes)
4817 * @param string $replace - string to replace (with magic quotes)
4818 * @return bool - success or fail
4820 function db_replace($search, $replace) {
4822 global $db, $CFG;
4824 /// Turn off time limits, sometimes upgrades can be slow.
4825 @set_time_limit(0);
4826 @ob_implicit_flush(true);
4827 while(@ob_end_flush());
4829 if (!$tables = $db->Metatables() ) { // No tables yet at all.
4830 return false;
4832 foreach ($tables as $table) {
4834 if (in_array($table, array($CFG->prefix.'config'))) { // Don't process these
4835 continue;
4838 if ($columns = $db->MetaColumns($table, false)) {
4839 foreach ($columns as $column => $data) {
4840 if (in_array($data->type, array('text','mediumtext','longtext','varchar'))) { // Text stuff only
4841 $db->debug = true;
4842 execute_sql("UPDATE $table SET $column = REPLACE($column, '$search', '$replace')");
4843 $db->debug = false;
4849 return true;
4853 * Prints tables of detected plugins, one table per plugin type,
4854 * and prints whether they are part of the standard Moodle
4855 * distribution or not.
4857 function print_plugin_tables() {
4858 $plugins_standard = array();
4859 $plugins_standard['mod'] = array('assignment',
4860 'chat',
4861 'choice',
4862 'data',
4863 'exercise',
4864 'forum',
4865 'glossary',
4866 'hotpot',
4867 'journal',
4868 'label',
4869 'lams',
4870 'lesson',
4871 'quiz',
4872 'resource',
4873 'scorm',
4874 'survey',
4875 'wiki',
4876 'workshop');
4878 $plugins_standard['blocks'] = array('activity_modules',
4879 'admin',
4880 'admin_bookmarks',
4881 'admin_tree',
4882 'blog_menu',
4883 'blog_tags',
4884 'calendar_month',
4885 'calendar_upcoming',
4886 'course_list',
4887 'course_summary',
4888 'glossary_random',
4889 'html',
4890 'loancalc',
4891 'login',
4892 'mentees',
4893 'messages',
4894 'mnet_hosts',
4895 'news_items',
4896 'online_users',
4897 'participants',
4898 'quiz_results',
4899 'recent_activity',
4900 'rss_client',
4901 'search',
4902 'search_forums',
4903 'section_links',
4904 'site_main_menu',
4905 'social_activities',
4906 'tag_flickr',
4907 'tag_youtube',
4908 'tags');
4910 $plugins_standard['filter'] = array('activitynames',
4911 'algebra',
4912 'censor',
4913 'emailprotect',
4914 'filter',
4915 'mediaplugin',
4916 'multilang',
4917 'tex',
4918 'tidy');
4920 $plugins_installed = array();
4921 $installed_mods = get_records_list('modules', '', '', '', 'name');
4922 $installed_blocks = get_records_list('block', '', '', '', 'name');
4924 foreach($installed_mods as $mod) {
4925 $plugins_installed['mod'][] = $mod->name;
4928 foreach($installed_blocks as $block) {
4929 $plugins_installed['blocks'][] = $block->name;
4932 $plugins_ondisk = array();
4933 $plugins_ondisk['mod'] = get_list_of_plugins('mod', 'db');
4934 $plugins_ondisk['blocks'] = get_list_of_plugins('blocks', 'db');
4935 $plugins_ondisk['filter'] = get_list_of_plugins('filter', 'db');
4937 $strstandard = get_string('standard');
4938 $strnonstandard = get_string('nonstandard');
4939 $strmissingfromdisk = '(' . get_string('missingfromdisk') . ')';
4940 $strabouttobeinstalled = '(' . get_string('abouttobeinstalled') . ')';
4942 $html = '';
4944 $html .= '<table class="generaltable plugincheckwrapper" cellspacing="4" cellpadding="1"><tr valign="top">';
4946 foreach ($plugins_ondisk as $cat => $list_ondisk) {
4947 $strcaption = get_string($cat);
4948 if ($cat == 'mod') {
4949 $strcaption = get_string('activitymodule');
4950 } elseif ($cat == 'filter') {
4951 $strcaption = get_string('managefilters');
4954 $html .= '<td><table class="plugincompattable generaltable boxaligncenter" cellspacing="1" cellpadding="5" '
4955 . 'id="' . $cat . 'compattable" summary="compatibility table"><caption>' . $strcaption . '</caption>' . "\n";
4956 $html .= '<tr class="r0"><th class="header c0">' . get_string('directory') . "</th>\n"
4957 . '<th class="header c1">' . get_string('name') . "</th>\n"
4958 . '<th class="header c2">' . get_string('status') . "</th>\n</tr>\n";
4960 $row = 1;
4962 foreach ($list_ondisk as $k => $plugin) {
4963 $status = 'ok';
4964 $standard = 'standard';
4965 $note = '';
4967 if (!in_array($plugin, $plugins_standard[$cat])) {
4968 $standard = 'nonstandard';
4969 $status = 'warning';
4972 // Get real name and full path of plugin
4973 $plugin_name = "[[$plugin]]";
4975 $plugin_path = "$cat/$plugin";
4977 $plugin_name = get_plugin_name($plugin, $cat);
4979 // Determine if the plugin is about to be installed
4980 if ($cat != 'filter' && !in_array($plugin, $plugins_installed[$cat])) {
4981 $note = $strabouttobeinstalled;
4982 $plugin_name = $plugin;
4985 $html .= "<tr class=\"r$row\">\n"
4986 . "<td class=\"cell c0\">$plugin_path</td>\n"
4987 . "<td class=\"cell c1\">$plugin_name</td>\n"
4988 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $note</td>\n</tr>\n";
4989 $row++;
4991 // If the plugin was both on disk and in the db, unset the value from the installed plugins list
4992 if ($key = array_search($plugin, $plugins_installed[$cat])) {
4993 unset($plugins_installed[$cat][$key]);
4997 // If there are plugins left in the plugins_installed list, it means they are missing from disk
4998 foreach ($plugins_installed[$cat] as $k => $missing_plugin) {
4999 // Make sure the plugin really is missing from disk
5000 if (!in_array($missing_plugin, $plugins_ondisk[$cat])) {
5001 $standard = 'standard';
5002 $status = 'warning';
5004 if (!in_array($missing_plugin, $plugins_standard[$cat])) {
5005 $standard = 'nonstandard';
5008 $plugin_name = $missing_plugin;
5009 $html .= "<tr class=\"r$row\">\n"
5010 . "<td class=\"cell c0\">?</td>\n"
5011 . "<td class=\"cell c1\">$plugin_name</td>\n"
5012 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $strmissingfromdisk</td>\n</tr>\n";
5013 $row++;
5017 $html .= '</table></td>';
5020 $html .= '</tr></table><br />';
5022 echo $html;