MDL-23726 fixed phpdocs - credit goes to Henning Bostelmann
[moodle.git] / lib / adminlib.php
blobfc8e3af0eb9bb81d0d810102c5b6506a1abe9b8d
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" ><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 * General text area with html editor.
1922 class admin_setting_confightmltextarea extends admin_setting_configtext {
1924 function admin_setting_confightmltextarea($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
1925 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1928 function output_html($data, $query='') {
1929 global $CFG;
1931 $CFG->adminusehtmleditor = can_use_html_editor();
1932 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true).'</div>';
1934 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
1939 * Password field, allows unmasking of password
1941 class admin_setting_configpasswordunmask extends admin_setting_configtext {
1943 * Constructor
1944 * @param string $name of setting
1945 * @param string $visiblename localised
1946 * @param string $description long localised info
1947 * @param string $defaultsetting default password
1949 function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting) {
1950 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
1953 function output_html($data, $query='') {
1954 $id = $this->get_id();
1955 $unmask = get_string('unmaskpassword', 'form');
1956 $unmaskjs = '<script type="text/javascript">
1957 //<![CDATA[
1958 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>\');
1959 document.getElementById("'.$this->get_id().'").setAttribute("autocomplete", "off");
1960 //]]>
1961 </script>';
1962 return format_admin_setting($this, $this->visiblename,
1963 '<div class="form-password"><input type="password" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$unmaskjs.'</div>',
1964 $this->description, true, '', NULL, $query);
1969 * Path to directory
1971 class admin_setting_configfile extends admin_setting_configtext {
1973 * Constructor
1974 * @param string $name of setting
1975 * @param string $visiblename localised
1976 * @param string $description long localised info
1977 * @param string $defaultdirectory default directory location
1979 function admin_setting_configfile($name, $visiblename, $description, $defaultdirectory) {
1980 parent::admin_setting_configtext($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
1983 function output_html($data, $query='') {
1984 $default = $this->get_defaultsetting();
1986 if ($data) {
1987 if (file_exists($data)) {
1988 $executable = '<span class="pathok">&#x2714;</span>';
1989 } else {
1990 $executable = '<span class="patherror">&#x2718;</span>';
1992 } else {
1993 $executable = '';
1996 return format_admin_setting($this, $this->visiblename,
1997 '<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>',
1998 $this->description, true, '', $default, $query);
2003 * Path to executable file
2005 class admin_setting_configexecutable extends admin_setting_configfile {
2007 function output_html($data, $query='') {
2008 $default = $this->get_defaultsetting();
2010 if ($data) {
2011 if (file_exists($data) and is_executable($data)) {
2012 $executable = '<span class="pathok">&#x2714;</span>';
2013 } else {
2014 $executable = '<span class="patherror">&#x2718;</span>';
2016 } else {
2017 $executable = '';
2020 return format_admin_setting($this, $this->visiblename,
2021 '<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>',
2022 $this->description, true, '', $default, $query);
2027 * Path to directory
2029 class admin_setting_configdirectory extends admin_setting_configfile {
2030 function output_html($data, $query='') {
2031 $default = $this->get_defaultsetting();
2033 if ($data) {
2034 if (file_exists($data) and is_dir($data)) {
2035 $executable = '<span class="pathok">&#x2714;</span>';
2036 } else {
2037 $executable = '<span class="patherror">&#x2718;</span>';
2039 } else {
2040 $executable = '';
2043 return format_admin_setting($this, $this->visiblename,
2044 '<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>',
2045 $this->description, true, '', $default, $query);
2050 * Checkbox
2052 class admin_setting_configcheckbox extends admin_setting {
2053 var $yes;
2054 var $no;
2057 * Constructor
2058 * @param string $name of setting
2059 * @param string $visiblename localised
2060 * @param string $description long localised info
2061 * @param string $defaultsetting
2062 * @param string $yes value used when checked
2063 * @param string $no value used when not checked
2065 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
2066 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2067 $this->yes = (string)$yes;
2068 $this->no = (string)$no;
2071 function get_setting() {
2072 return $this->config_read($this->name);
2075 function write_setting($data) {
2076 if ((string)$data === $this->yes) { // convert to strings before comparison
2077 $data = $this->yes;
2078 } else {
2079 $data = $this->no;
2081 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2084 function output_html($data, $query='') {
2085 $default = $this->get_defaultsetting();
2087 if (!is_null($default)) {
2088 if ((string)$default === $this->yes) {
2089 $defaultinfo = get_string('checkboxyes', 'admin');
2090 } else {
2091 $defaultinfo = get_string('checkboxno', 'admin');
2093 } else {
2094 $defaultinfo = NULL;
2097 if ((string)$data === $this->yes) { // convert to strings before comparison
2098 $checked = 'checked="checked"';
2099 } else {
2100 $checked = '';
2103 return format_admin_setting($this, $this->visiblename,
2104 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
2105 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
2106 $this->description, true, '', $defaultinfo, $query);
2111 * Multiple checkboxes, each represents different value, stored in csv format
2113 class admin_setting_configmulticheckbox extends admin_setting {
2114 var $choices;
2117 * Constructor
2118 * @param string $name of setting
2119 * @param string $visiblename localised
2120 * @param string $description long localised info
2121 * @param array $defaultsetting array of selected
2122 * @param array $choices array of $value=>$label for each checkbox
2124 function admin_setting_configmulticheckbox($name, $visiblename, $description, $defaultsetting, $choices) {
2125 $this->choices = $choices;
2126 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2130 * This function may be used in ancestors for lazy loading of choices
2131 * @return true if loaded, false if error
2133 function load_choices() {
2135 if (is_array($this->choices)) {
2136 return true;
2138 .... load choices here
2140 return true;
2144 * Is setting related to query text - used when searching
2145 * @param string $query
2146 * @return bool
2148 function is_related($query) {
2149 if (!$this->load_choices() or empty($this->choices)) {
2150 return false;
2152 if (parent::is_related($query)) {
2153 return true;
2156 $textlib = textlib_get_instance();
2157 foreach ($this->choices as $desc) {
2158 if (strpos($textlib->strtolower($desc), $query) !== false) {
2159 return true;
2162 return false;
2165 function get_setting() {
2166 $result = $this->config_read($this->name);
2167 if (is_null($result)) {
2168 return NULL;
2170 if ($result === '') {
2171 return array();
2173 return explode(',', $result);
2176 function write_setting($data) {
2177 if (!is_array($data)) {
2178 return ''; // ignore it
2180 if (!$this->load_choices() or empty($this->choices)) {
2181 return '';
2183 unset($data['xxxxx']);
2184 $result = array();
2185 foreach ($data as $key => $value) {
2186 if ($value and array_key_exists($key, $this->choices)) {
2187 $result[] = $key;
2190 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
2193 function output_html($data, $query='') {
2194 if (!$this->load_choices() or empty($this->choices)) {
2195 return '';
2197 $default = $this->get_defaultsetting();
2198 if (is_null($default)) {
2199 $default = array();
2201 if (is_null($data)) {
2202 foreach ($default as $key=>$value) {
2203 if ($value) {
2204 $current[] = $value;
2209 $options = array();
2210 $defaults = array();
2211 foreach($this->choices as $key=>$description) {
2212 if (in_array($key, $data)) {
2213 $checked = 'checked="checked"';
2214 } else {
2215 $checked = '';
2217 if (!empty($default[$key])) {
2218 $defaults[] = $description;
2221 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
2222 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
2225 if (is_null($default)) {
2226 $defaultinfo = NULL;
2227 } else if (!empty($defaults)) {
2228 $defaultinfo = implode(', ', $defaults);
2229 } else {
2230 $defaultinfo = get_string('none');
2233 $return = '<div class="form-multicheckbox">';
2234 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2235 if ($options) {
2236 $return .= '<ul>';
2237 foreach ($options as $option) {
2238 $return .= '<li>'.$option.'</li>';
2240 $return .= '</ul>';
2242 $return .= '</div>';
2244 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2250 * Multiple checkboxes 2, value stored as string 00101011
2252 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
2253 function get_setting() {
2254 $result = $this->config_read($this->name);
2255 if (is_null($result)) {
2256 return NULL;
2258 if (!$this->load_choices()) {
2259 return NULL;
2261 $result = str_pad($result, count($this->choices), '0');
2262 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2263 $setting = array();
2264 foreach ($this->choices as $key=>$unused) {
2265 $value = array_shift($result);
2266 if ($value) {
2267 $setting[] = $key;
2270 return $setting;
2273 function write_setting($data) {
2274 if (!is_array($data)) {
2275 return ''; // ignore it
2277 if (!$this->load_choices() or empty($this->choices)) {
2278 return '';
2280 $result = '';
2281 foreach ($this->choices as $key=>$unused) {
2282 if (!empty($data[$key])) {
2283 $result .= '1';
2284 } else {
2285 $result .= '0';
2288 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
2293 * Select one value from list
2295 class admin_setting_configselect extends admin_setting {
2296 var $choices;
2299 * Constructor
2300 * @param string $name of setting
2301 * @param string $visiblename localised
2302 * @param string $description long localised info
2303 * @param string $defaultsetting
2304 * @param array $choices array of $value=>$label for each selection
2306 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
2307 $this->choices = $choices;
2308 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2312 * This function may be used in ancestors for lazy loading of choices
2313 * @return true if loaded, false if error
2315 function load_choices() {
2317 if (is_array($this->choices)) {
2318 return true;
2320 .... load choices here
2322 return true;
2325 function is_related($query) {
2326 if (parent::is_related($query)) {
2327 return true;
2329 if (!$this->load_choices()) {
2330 return false;
2332 $textlib = textlib_get_instance();
2333 foreach ($this->choices as $key=>$value) {
2334 if (strpos($textlib->strtolower($key), $query) !== false) {
2335 return true;
2337 if (strpos($textlib->strtolower($value), $query) !== false) {
2338 return true;
2341 return false;
2344 function get_setting() {
2345 return $this->config_read($this->name);
2348 function write_setting($data) {
2349 if (!$this->load_choices() or empty($this->choices)) {
2350 return '';
2352 if (!array_key_exists($data, $this->choices)) {
2353 return ''; // ignore it
2356 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2359 function output_html($data, $query='') {
2360 if (!$this->load_choices() or empty($this->choices)) {
2361 return '';
2363 $default = $this->get_defaultsetting();
2365 if (!is_null($default) and array_key_exists($default, $this->choices)) {
2366 $defaultinfo = $this->choices[$default];
2367 } else {
2368 $defaultinfo = NULL;
2371 $current = $this->get_setting();
2372 $warning = '';
2373 if (is_null($current)) {
2374 //first run
2375 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
2376 // no warning
2377 } else if (!array_key_exists($current, $this->choices)) {
2378 $warning = get_string('warningcurrentsetting', 'admin', s($current));
2379 if (!is_null($default) and $data==$current) {
2380 $data = $default; // use default instead of first value when showing the form
2384 $return = '<div class="form-select defaultsnext"><select id="'.$this->get_id().'" name="'.$this->get_full_name().'">';
2385 foreach ($this->choices as $key => $value) {
2386 // the string cast is needed because key may be integer - 0 is equal to most strings!
2387 $return .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
2389 $return .= '</select></div>';
2391 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
2397 * Select multiple items from list
2399 class admin_setting_configmultiselect extends admin_setting_configselect {
2401 * Constructor
2402 * @param string $name of setting
2403 * @param string $visiblename localised
2404 * @param string $description long localised info
2405 * @param array $defaultsetting array of selected items
2406 * @param array $choices array of $value=>$label for each list item
2408 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
2409 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
2412 function get_setting() {
2413 $result = $this->config_read($this->name);
2414 if (is_null($result)) {
2415 return NULL;
2417 if ($result === '') {
2418 return array();
2420 return explode(',', $result);
2423 function write_setting($data) {
2424 if (!is_array($data)) {
2425 return ''; //ignore it
2427 if (!$this->load_choices() or empty($this->choices)) {
2428 return '';
2431 unset($data['xxxxx']);
2433 $save = array();
2434 foreach ($data as $value) {
2435 if (!array_key_exists($value, $this->choices)) {
2436 continue; // ignore it
2438 $save[] = $value;
2441 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2445 * Is setting related to query text - used when searching
2446 * @param string $query
2447 * @return bool
2449 function is_related($query) {
2450 if (!$this->load_choices() or empty($this->choices)) {
2451 return false;
2453 if (parent::is_related($query)) {
2454 return true;
2457 $textlib = textlib_get_instance();
2458 foreach ($this->choices as $desc) {
2459 if (strpos($textlib->strtolower($desc), $query) !== false) {
2460 return true;
2463 return false;
2466 function output_html($data, $query='') {
2467 if (!$this->load_choices() or empty($this->choices)) {
2468 return '';
2470 $choices = $this->choices;
2471 $default = $this->get_defaultsetting();
2472 if (is_null($default)) {
2473 $default = array();
2475 if (is_null($data)) {
2476 $data = array();
2479 $defaults = array();
2480 $size = min(10, count($this->choices));
2481 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2482 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="'.$size.'" multiple="multiple">';
2483 foreach ($this->choices as $key => $description) {
2484 if (in_array($key, $data)) {
2485 $selected = 'selected="selected"';
2486 } else {
2487 $selected = '';
2489 if (in_array($key, $default)) {
2490 $defaults[] = $description;
2493 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
2496 if (is_null($default)) {
2497 $defaultinfo = NULL;
2498 } if (!empty($defaults)) {
2499 $defaultinfo = implode(', ', $defaults);
2500 } else {
2501 $defaultinfo = get_string('none');
2504 $return .= '</select></div>';
2505 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
2510 * Time selector
2511 * this is a liiitle bit messy. we're using two selects, but we're returning
2512 * them as an array named after $name (so we only use $name2 internally for the setting)
2514 class admin_setting_configtime extends admin_setting {
2515 var $name2;
2518 * Constructor
2519 * @param string $hoursname setting for hours
2520 * @param string $minutesname setting for hours
2521 * @param string $visiblename localised
2522 * @param string $description long localised info
2523 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
2525 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
2526 $this->name2 = $minutesname;
2527 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
2530 function get_setting() {
2531 $result1 = $this->config_read($this->name);
2532 $result2 = $this->config_read($this->name2);
2533 if (is_null($result1) or is_null($result2)) {
2534 return NULL;
2537 return array('h' => $result1, 'm' => $result2);
2540 function write_setting($data) {
2541 if (!is_array($data)) {
2542 return '';
2545 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
2546 return ($result ? '' : get_string('errorsetting', 'admin'));
2549 function output_html($data, $query='') {
2550 $default = $this->get_defaultsetting();
2552 if (is_array($default)) {
2553 $defaultinfo = $default['h'].':'.$default['m'];
2554 } else {
2555 $defaultinfo = NULL;
2558 $return = '<div class="form-time defaultsnext">'.
2559 '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
2560 for ($i = 0; $i < 24; $i++) {
2561 $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2563 $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
2564 for ($i = 0; $i < 60; $i += 5) {
2565 $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2567 $return .= '</select></div>';
2568 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2574 * An admin setting for selecting one or more users, who have a particular capability
2575 * in the system context. Warning, make sure the list will never be too long. There is
2576 * no paging or searching of this list.
2578 * To correctly get a list of users from this config setting, you need to call the
2579 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php.
2581 class admin_setting_users_with_capability extends admin_setting_configmultiselect {
2582 var $capability;
2585 * Constructor.
2587 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2588 * @param string $visiblename localised name
2589 * @param string $description localised long description
2590 * @param array $defaultsetting array of usernames
2591 * @param string $capability string capability name.
2593 function admin_setting_users_with_capability($name, $visiblename, $description, $defaultsetting, $capability) {
2594 $this->capability = $capability;
2595 parent::admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, NULL);
2598 function load_choices() {
2599 if (is_array($this->choices)) {
2600 return true;
2602 $users = get_users_by_capability(get_context_instance(CONTEXT_SYSTEM),
2603 $this->capability, 'u.id,u.username,u.firstname,u.lastname', 'u.lastname,u.firstname');
2604 $this->choices = array(
2605 '$@NONE@$' => get_string('nobody'),
2606 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)),
2608 foreach ($users as $user) {
2609 $this->choices[$user->username] = fullname($user);
2611 return true;
2614 function get_defaultsetting() {
2615 $this->load_choices();
2616 if (empty($this->defaultsetting)) {
2617 return array('$@NONE@$');
2618 } else if (array_key_exists($this->defaultsetting, $this->choices)) {
2619 return $this->defaultsetting;
2620 } else {
2621 return '';
2625 function get_setting() {
2626 $result = parent::get_setting();
2627 if (empty($result)) {
2628 $result = array('$@NONE@$');
2630 return $result;
2633 function write_setting($data) {
2634 // If all is selected, remove any explicit options.
2635 if (in_array('$@ALL@$', $data)) {
2636 $data = array('$@ALL@$');
2638 // None never needs to be writted to the DB.
2639 if (in_array('$@NONE@$', $data)) {
2640 unset($data[array_search('$@NONE@$', $data)]);
2642 return parent::write_setting($data);
2647 * Special checkbox for calendar - resets SESSION vars.
2649 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
2650 function admin_setting_special_adminseesall() {
2651 parent::admin_setting_configcheckbox('calendar_adminseesall', get_string('adminseesall', 'admin'),
2652 get_string('helpadminseesall', 'admin'), '0');
2655 function write_setting($data) {
2656 global $SESSION;
2657 unset($SESSION->cal_courses_shown);
2658 return parent::write_setting($data);
2663 * Special select for settings that are altered in setup.php and can not be altered on the fly
2665 class admin_setting_special_selectsetup extends admin_setting_configselect {
2666 function get_setting() {
2667 // read directly from db!
2668 return get_config(NULL, $this->name);
2671 function write_setting($data) {
2672 global $CFG;
2673 // do not change active CFG setting!
2674 $current = $CFG->{$this->name};
2675 $result = parent::write_setting($data);
2676 $CFG->{$this->name} = $current;
2677 return $result;
2682 * Special select for frontpage - stores data in course table
2684 class admin_setting_sitesetselect extends admin_setting_configselect {
2685 function get_setting() {
2686 $site = get_site();
2687 return $site->{$this->name};
2690 function write_setting($data) {
2691 global $SITE;
2692 if (!in_array($data, array_keys($this->choices))) {
2693 return get_string('errorsetting', 'admin');
2695 $record = new stdClass();
2696 $record->id = SITEID;
2697 $temp = $this->name;
2698 $record->$temp = $data;
2699 $record->timemodified = time();
2700 // update $SITE
2701 $SITE->{$this->name} = $data;
2702 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2707 * Special select - lists on the frontpage - hacky
2709 class admin_setting_courselist_frontpage extends admin_setting {
2710 var $choices;
2712 function admin_setting_courselist_frontpage($loggedin) {
2713 global $CFG;
2714 require_once($CFG->dirroot.'/course/lib.php');
2715 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
2716 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
2717 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
2718 $defaults = array(FRONTPAGECOURSELIST);
2719 parent::admin_setting($name, $visiblename, $description, $defaults);
2722 function load_choices() {
2723 if (is_array($this->choices)) {
2724 return true;
2726 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
2727 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
2728 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
2729 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
2730 'none' => get_string('none'));
2731 if ($this->name == 'frontpage' and count_records('course') > FRONTPAGECOURSELIMIT) {
2732 unset($this->choices[FRONTPAGECOURSELIST]);
2734 return true;
2736 function get_setting() {
2737 $result = $this->config_read($this->name);
2738 if (is_null($result)) {
2739 return NULL;
2741 if ($result === '') {
2742 return array();
2744 return explode(',', $result);
2747 function write_setting($data) {
2748 if (!is_array($data)) {
2749 return '';
2751 $this->load_choices();
2752 $save = array();
2753 foreach($data as $datum) {
2754 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
2755 continue;
2757 $save[$datum] = $datum; // no duplicates
2759 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2762 function output_html($data, $query='') {
2763 $this->load_choices();
2764 $currentsetting = array();
2765 foreach ($data as $key) {
2766 if ($key != 'none' and array_key_exists($key, $this->choices)) {
2767 $currentsetting[] = $key; // already selected first
2771 $return = '<div class="form-group">';
2772 for ($i = 0; $i < count($this->choices) - 1; $i++) {
2773 if (!array_key_exists($i, $currentsetting)) {
2774 $currentsetting[$i] = 'none'; //none
2776 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
2777 foreach ($this->choices as $key => $value) {
2778 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
2780 $return .= '</select>';
2781 if ($i !== count($this->choices) - 2) {
2782 $return .= '<br />';
2785 $return .= '</div>';
2787 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2792 * Special checkbox for frontpage - stores data in course table
2794 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
2795 function get_setting() {
2796 $site = get_site();
2797 return $site->{$this->name};
2800 function write_setting($data) {
2801 global $SITE;
2802 $record = new object();
2803 $record->id = SITEID;
2804 $record->{$this->name} = ($data == '1' ? 1 : 0);
2805 $record->timemodified = time();
2806 // update $SITE
2807 $SITE->{$this->name} = $data;
2808 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2813 * Special text for frontpage - stores data in course table.
2814 * Empty string means not set here. Manual setting is required.
2816 class admin_setting_sitesettext extends admin_setting_configtext {
2817 function get_setting() {
2818 $site = get_site();
2819 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
2822 function validate($data) {
2823 $cleaned = stripslashes(clean_param(addslashes($data), PARAM_MULTILANG));
2824 if ($cleaned === '') {
2825 return get_string('required');
2827 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
2828 return true;
2829 } else {
2830 return get_string('validateerror', 'admin');
2834 function write_setting($data) {
2835 global $SITE;
2836 $data = trim($data);
2837 $validated = $this->validate($data);
2838 if ($validated !== true) {
2839 return $validated;
2842 $record = new object();
2843 $record->id = SITEID;
2844 $record->{$this->name} = addslashes($data);
2845 $record->timemodified = time();
2846 // update $SITE
2847 $SITE->{$this->name} = $data;
2848 return (update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
2853 * Special text editor for site description.
2855 class admin_setting_special_frontpagedesc extends admin_setting {
2856 function admin_setting_special_frontpagedesc() {
2857 parent::admin_setting('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
2860 function get_setting() {
2861 $site = get_site();
2862 return $site->{$this->name};
2865 function write_setting($data) {
2866 global $SITE;
2867 $record = new object();
2868 $record->id = SITEID;
2869 $record->{$this->name} = addslashes($data);
2870 $record->timemodified = time();
2871 $SITE->{$this->name} = $data;
2872 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2875 function output_html($data, $query='') {
2876 global $CFG;
2878 $CFG->adminusehtmleditor = can_use_html_editor();
2879 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true).'</div>';
2881 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2885 class admin_setting_special_editorfontlist extends admin_setting {
2887 var $items;
2889 function admin_setting_special_editorfontlist() {
2890 global $CFG;
2891 $name = 'editorfontlist';
2892 $visiblename = get_string('editorfontlist', 'admin');
2893 $description = get_string('configeditorfontlist', 'admin');
2894 $defaults = array('k0' => 'Trebuchet',
2895 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
2896 'k1' => 'Arial',
2897 'v1' => 'arial,helvetica,sans-serif',
2898 'k2' => 'Courier New',
2899 'v2' => 'courier new,courier,monospace',
2900 'k3' => 'Georgia',
2901 'v3' => 'georgia,times new roman,times,serif',
2902 'k4' => 'Tahoma',
2903 'v4' => 'tahoma,arial,helvetica,sans-serif',
2904 'k5' => 'Times New Roman',
2905 'v5' => 'times new roman,times,serif',
2906 'k6' => 'Verdana',
2907 'v6' => 'verdana,arial,helvetica,sans-serif',
2908 'k7' => 'Impact',
2909 'v7' => 'impact',
2910 'k8' => 'Wingdings',
2911 'v8' => 'wingdings');
2912 parent::admin_setting($name, $visiblename, $description, $defaults);
2915 function get_setting() {
2916 global $CFG;
2917 $result = $this->config_read($this->name);
2918 if (is_null($result)) {
2919 return NULL;
2921 $i = 0;
2922 $currentsetting = array();
2923 $items = explode(';', $result);
2924 foreach ($items as $item) {
2925 $item = explode(':', $item);
2926 $currentsetting['k'.$i] = $item[0];
2927 $currentsetting['v'.$i] = $item[1];
2928 $i++;
2930 return $currentsetting;
2933 function write_setting($data) {
2935 // there miiight be an easier way to do this :)
2936 // if this is changed, make sure the $defaults array above is modified so that this
2937 // function processes it correctly
2939 $keys = array();
2940 $values = array();
2942 foreach ($data as $key => $value) {
2943 if (substr($key,0,1) == 'k') {
2944 $keys[substr($key,1)] = $value;
2945 } elseif (substr($key,0,1) == 'v') {
2946 $values[substr($key,1)] = $value;
2950 $result = array();
2951 for ($i = 0; $i < count($keys); $i++) {
2952 if (($keys[$i] !== '') && ($values[$i] !== '')) {
2953 $result[] = clean_param($keys[$i],PARAM_NOTAGS).':'.clean_param($values[$i], PARAM_NOTAGS);
2957 return ($this->config_write($this->name, implode(';', $result)) ? '' : get_string('errorsetting', 'admin'));
2960 function output_html($data, $query='') {
2961 $fullname = $this->get_full_name();
2962 $return = '<div class="form-group">';
2963 for ($i = 0; $i < count($data) / 2; $i++) {
2964 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
2965 $return .= '&nbsp;&nbsp;';
2966 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
2968 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
2969 $return .= '&nbsp;&nbsp;';
2970 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2971 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
2972 $return .= '&nbsp;&nbsp;';
2973 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
2974 $return .= '</div>';
2976 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2981 class admin_setting_emoticons extends admin_setting {
2983 var $items;
2985 function admin_setting_emoticons() {
2986 global $CFG;
2987 $name = 'emoticons';
2988 $visiblename = get_string('emoticons', 'admin');
2989 $description = get_string('configemoticons', 'admin');
2990 $defaults = array('k0' => ':-)',
2991 'v0' => 'smiley',
2992 'k1' => ':)',
2993 'v1' => 'smiley',
2994 'k2' => ':-D',
2995 'v2' => 'biggrin',
2996 'k3' => ';-)',
2997 'v3' => 'wink',
2998 'k4' => ':-/',
2999 'v4' => 'mixed',
3000 'k5' => 'V-.',
3001 'v5' => 'thoughtful',
3002 'k6' => ':-P',
3003 'v6' => 'tongueout',
3004 'k7' => 'B-)',
3005 'v7' => 'cool',
3006 'k8' => '^-)',
3007 'v8' => 'approve',
3008 'k9' => '8-)',
3009 'v9' => 'wideeyes',
3010 'k10' => ':o)',
3011 'v10' => 'clown',
3012 'k11' => ':-(',
3013 'v11' => 'sad',
3014 'k12' => ':(',
3015 'v12' => 'sad',
3016 'k13' => '8-.',
3017 'v13' => 'shy',
3018 'k14' => ':-I',
3019 'v14' => 'blush',
3020 'k15' => ':-X',
3021 'v15' => 'kiss',
3022 'k16' => '8-o',
3023 'v16' => 'surprise',
3024 'k17' => 'P-|',
3025 'v17' => 'blackeye',
3026 'k18' => '8-[',
3027 'v18' => 'angry',
3028 'k19' => 'xx-P',
3029 'v19' => 'dead',
3030 'k20' => '|-.',
3031 'v20' => 'sleepy',
3032 'k21' => '}-]',
3033 'v21' => 'evil',
3034 'k22' => '(h)',
3035 'v22' => 'heart',
3036 'k23' => '(heart)',
3037 'v23' => 'heart',
3038 'k24' => '(y)',
3039 'v24' => 'yes',
3040 'k25' => '(n)',
3041 'v25' => 'no',
3042 'k26' => '(martin)',
3043 'v26' => 'martin',
3044 'k27' => '( )',
3045 'v27' => 'egg');
3046 parent::admin_setting($name, $visiblename, $description, $defaults);
3049 function get_setting() {
3050 global $CFG;
3051 $result = $this->config_read($this->name);
3052 if (is_null($result)) {
3053 return NULL;
3055 $i = 0;
3056 $currentsetting = array();
3057 $items = explode('{;}', $result);
3058 foreach ($items as $item) {
3059 $item = explode('{:}', $item);
3060 $currentsetting['k'.$i] = $item[0];
3061 $currentsetting['v'.$i] = $item[1];
3062 $i++;
3064 return $currentsetting;
3067 function write_setting($data) {
3069 // there miiight be an easier way to do this :)
3070 // if this is changed, make sure the $defaults array above is modified so that this
3071 // function processes it correctly
3073 $keys = array();
3074 $values = array();
3076 foreach ($data as $key => $value) {
3077 if (substr($key,0,1) == 'k') {
3078 $keys[substr($key,1)] = $value;
3079 } elseif (substr($key,0,1) == 'v') {
3080 $values[substr($key,1)] = $value;
3084 $result = array();
3085 for ($i = 0; $i < count($keys); $i++) {
3086 if (($keys[$i] !== '') && ($values[$i] !== '')) {
3087 $result[] = clean_param($keys[$i],PARAM_NOTAGS).'{:}'.clean_param($values[$i], PARAM_NOTAGS);
3091 return ($this->config_write($this->name, implode('{;}', $result)) ? '' : get_string('errorsetting', 'admin').$this->visiblename.'<br />');
3094 function output_html($data, $query='') {
3095 $fullname = $this->get_full_name();
3096 $return = '<div class="form-group">';
3097 for ($i = 0; $i < count($data) / 2; $i++) {
3098 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
3099 $return .= '&nbsp;&nbsp;';
3100 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
3102 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
3103 $return .= '&nbsp;&nbsp;';
3104 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
3105 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
3106 $return .= '&nbsp;&nbsp;';
3107 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
3108 $return .= '</div>';
3110 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3116 * Setting for spellchecker language selection.
3118 class admin_setting_special_editordictionary extends admin_setting_configselect {
3120 function admin_setting_special_editordictionary() {
3121 $name = 'editordictionary';
3122 $visiblename = get_string('editordictionary','admin');
3123 $description = get_string('configeditordictionary', 'admin');
3124 parent::admin_setting_configselect($name, $visiblename, $description, '', NULL);
3127 function load_choices() {
3128 // function borrowed from the old moodle/admin/editor.php, slightly modified
3129 // Get all installed dictionaries in the system
3130 if (is_array($this->choices)) {
3131 return true;
3134 $this->choices = array();
3136 global $CFG;
3138 clearstatcache();
3140 // If aspellpath isn't set don't even bother ;-)
3141 if (empty($CFG->aspellpath)) {
3142 $this->choices['error'] = 'Empty aspell path!';
3143 return true;
3146 // Do we have access to popen function?
3147 if (!function_exists('popen')) {
3148 $this->choices['error'] = 'Popen function disabled!';
3149 return true;
3152 $cmd = $CFG->aspellpath;
3153 $output = '';
3154 $dictionaries = array();
3156 if(!($handle = @popen(escapeshellarg($cmd).' dump dicts', 'r'))) {
3157 $this->choices['error'] = 'Couldn\'t create handle!';
3160 while(!feof($handle)) {
3161 $output .= fread($handle, 1024);
3163 @pclose($handle);
3165 $dictionaries = explode(chr(10), $output);
3166 foreach ($dictionaries as $dict) {
3167 if (empty($dict)) {
3168 continue;
3170 $this->choices[$dict] = $dict;
3173 if (empty($this->choices)) {
3174 $this->choices['error'] = 'Error! Check your aspell installation!';
3176 return true;
3181 class admin_setting_special_editorhidebuttons extends admin_setting {
3182 var $items;
3184 function admin_setting_special_editorhidebuttons() {
3185 parent::admin_setting('editorhidebuttons', get_string('editorhidebuttons', 'admin'),
3186 get_string('confeditorhidebuttons', 'admin'), array());
3187 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
3188 $this->items = array('fontname' => '',
3189 'fontsize' => '',
3190 'formatblock' => '',
3191 'bold' => 'ed_format_bold.gif',
3192 'italic' => 'ed_format_italic.gif',
3193 'underline' => 'ed_format_underline.gif',
3194 'strikethrough' => 'ed_format_strike.gif',
3195 'subscript' => 'ed_format_sub.gif',
3196 'superscript' => 'ed_format_sup.gif',
3197 'copy' => 'ed_copy.gif',
3198 'cut' => 'ed_cut.gif',
3199 'paste' => 'ed_paste.gif',
3200 'clean' => 'ed_wordclean.gif',
3201 'undo' => 'ed_undo.gif',
3202 'redo' => 'ed_redo.gif',
3203 'justifyleft' => 'ed_align_left.gif',
3204 'justifycenter' => 'ed_align_center.gif',
3205 'justifyright' => 'ed_align_right.gif',
3206 'justifyfull' => 'ed_align_justify.gif',
3207 'lefttoright' => 'ed_left_to_right.gif',
3208 'righttoleft' => 'ed_right_to_left.gif',
3209 'insertorderedlist' => 'ed_list_num.gif',
3210 'insertunorderedlist' => 'ed_list_bullet.gif',
3211 'outdent' => 'ed_indent_less.gif',
3212 'indent' => 'ed_indent_more.gif',
3213 'forecolor' => 'ed_color_fg.gif',
3214 'hilitecolor' => 'ed_color_bg.gif',
3215 'inserthorizontalrule' => 'ed_hr.gif',
3216 'createanchor' => 'ed_anchor.gif',
3217 'createlink' => 'ed_link.gif',
3218 'unlink' => 'ed_unlink.gif',
3219 'insertimage' => 'ed_image.gif',
3220 'inserttable' => 'insert_table.gif',
3221 'insertsmile' => 'em.icon.smile.gif',
3222 'insertchar' => 'icon_ins_char.gif',
3223 'spellcheck' => 'spell-check.gif',
3224 'htmlmode' => 'ed_html.gif',
3225 'popupeditor' => 'fullscreen_maximize.gif',
3226 'search_replace' => 'ed_replace.gif');
3229 function get_setting() {
3230 $result = $this->config_read($this->name);
3231 if (is_null($result)) {
3232 return NULL;
3234 if ($result === '') {
3235 return array();
3237 return explode(' ', $result);
3240 function write_setting($data) {
3241 if (!is_array($data)) {
3242 return ''; // ignore it
3244 unset($data['xxxxx']);
3245 $result = array();
3247 foreach ($data as $key => $value) {
3248 if (!isset($this->items[$key])) {
3249 return get_string('errorsetting', 'admin');
3251 if ($value == '1') {
3252 $result[] = $key;
3255 return ($this->config_write($this->name, implode(' ', $result)) ? '' : get_string('errorsetting', 'admin'));
3258 function output_html($data, $query='') {
3260 global $CFG;
3262 // checkboxes with input name="$this->name[$key]" value="1"
3263 // we do 15 fields per column
3265 $return = '<div class="form-group">';
3266 $return .= '<table><tr><td valign="top" align="right">';
3267 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3269 $count = 0;
3271 foreach($this->items as $key => $value) {
3272 if ($count % 15 == 0 and $count != 0) {
3273 $return .= '</td><td valign="top" align="right">';
3276 $return .= '<label for="'.$this->get_id().$key.'">';
3277 $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;';
3278 $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;';
3279 $return .= '</label>';
3280 $count++;
3281 if ($count % 15 != 0) {
3282 $return .= '<br /><br />';
3286 $return .= '</td></tr>';
3287 $return .= '</table>';
3288 $return .= '</div>';
3290 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3295 * Special setting for limiting of the list of available languages.
3297 class admin_setting_langlist extends admin_setting_configtext {
3298 function admin_setting_langlist() {
3299 parent::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
3302 function write_setting($data) {
3303 $return = parent::write_setting($data);
3304 get_list_of_languages(true);//refresh the list
3305 return $return;
3310 * Course category selection
3312 class admin_settings_coursecat_select extends admin_setting_configselect {
3313 function admin_settings_coursecat_select($name, $visiblename, $description, $defaultsetting) {
3314 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, NULL);
3317 function load_choices() {
3318 global $CFG;
3319 require_once($CFG->dirroot.'/course/lib.php');
3320 if (is_array($this->choices)) {
3321 return true;
3323 $this->choices = make_categories_options();
3324 return true;
3328 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
3329 function admin_setting_special_backupdays() {
3330 parent::admin_setting_configmulticheckbox2('backup_sche_weekdays', get_string('schedule'), get_string('backupschedulehelp'), array(), NULL);
3331 $this->plugin = 'backup';
3334 function load_choices() {
3335 if (is_array($this->choices)) {
3336 return true;
3338 $this->choices = array();
3339 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3340 foreach ($days as $day) {
3341 $this->choices[$day] = get_string($day, 'calendar');
3343 return true;
3348 * Special debug setting
3350 class admin_setting_special_debug extends admin_setting_configselect {
3351 function admin_setting_special_debug() {
3352 parent::admin_setting_configselect('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
3355 function load_choices() {
3356 if (is_array($this->choices)) {
3357 return true;
3359 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
3360 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
3361 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
3362 DEBUG_ALL => get_string('debugall', 'admin'),
3363 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
3364 return true;
3369 class admin_setting_special_calendar_weekend extends admin_setting {
3370 function admin_setting_special_calendar_weekend() {
3371 $name = 'calendar_weekend';
3372 $visiblename = get_string('calendar_weekend', 'admin');
3373 $description = get_string('helpweekenddays', 'admin');
3374 $default = array ('0', '6'); // Saturdays and Sundays
3375 parent::admin_setting($name, $visiblename, $description, $default);
3378 function get_setting() {
3379 $result = $this->config_read($this->name);
3380 if (is_null($result)) {
3381 return NULL;
3383 if ($result === '') {
3384 return array();
3386 $settings = array();
3387 for ($i=0; $i<7; $i++) {
3388 if ($result & (1 << $i)) {
3389 $settings[] = $i;
3392 return $settings;
3395 function write_setting($data) {
3396 if (!is_array($data)) {
3397 return '';
3399 unset($data['xxxxx']);
3400 $result = 0;
3401 foreach($data as $index) {
3402 $result |= 1 << $index;
3404 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
3407 function output_html($data, $query='') {
3408 // The order matters very much because of the implied numeric keys
3409 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3410 $return = '<table><thead><tr>';
3411 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3412 foreach($days as $index => $day) {
3413 $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>';
3415 $return .= '</tr></thead><tbody><tr>';
3416 foreach($days as $index => $day) {
3417 $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>';
3419 $return .= '</tr></tbody></table>';
3421 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3428 * Graded roles in gradebook
3430 class admin_setting_special_gradebookroles extends admin_setting_configmulticheckbox {
3431 function admin_setting_special_gradebookroles() {
3432 parent::admin_setting_configmulticheckbox('gradebookroles', get_string('gradebookroles', 'admin'),
3433 get_string('configgradebookroles', 'admin'), NULL, NULL);
3436 function load_choices() {
3437 global $CFG;
3438 if (empty($CFG->rolesactive)) {
3439 return false;
3441 if (is_array($this->choices)) {
3442 return true;
3444 if ($roles = get_records('role')) {
3445 $this->choices = array();
3446 foreach($roles as $role) {
3447 $this->choices[$role->id] = format_string($role->name);
3449 return true;
3450 } else {
3451 return false;
3455 function get_defaultsetting() {
3456 global $CFG;
3457 if (empty($CFG->rolesactive)) {
3458 return NULL;
3460 $result = array();
3461 if ($studentroles = get_roles_with_capability('moodle/legacy:student', CAP_ALLOW)) {
3462 foreach ($studentroles as $studentrole) {
3463 $result[$studentrole->id] = '1';
3466 return $result;
3470 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
3471 function write_setting($data) {
3472 global $CFG;
3474 $oldvalue = $this->config_read($this->name);
3475 $return = parent::write_setting($data);
3476 $newvalue = $this->config_read($this->name);
3478 if ($oldvalue !== $newvalue) {
3479 // force full regrading
3480 set_field('grade_items', 'needsupdate', 1, 'needsupdate', 0);
3483 return $return;
3488 * Which roles to show on course decription page
3490 class admin_setting_special_coursemanager extends admin_setting_configmulticheckbox {
3491 function admin_setting_special_coursemanager() {
3492 parent::admin_setting_configmulticheckbox('coursemanager', get_string('coursemanager', 'admin'),
3493 get_string('configcoursemanager', 'admin'), NULL, NULL);
3496 function load_choices() {
3497 if (is_array($this->choices)) {
3498 return true;
3500 if ($roles = get_records('role','','','sortorder')) {
3501 $this->choices = array();
3502 foreach($roles as $role) {
3503 $this->choices[$role->id] = format_string($role->name);
3505 return true;
3507 return false;
3510 function get_defaultsetting() {
3511 global $CFG;
3512 if (empty($CFG->rolesactive)) {
3513 return NULL;
3515 $result = array();
3516 if ($teacherroles = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW)) {
3517 foreach ($teacherroles as $teacherrole) {
3518 $result[$teacherrole->id] = '1';
3521 return $result;
3525 class admin_setting_special_gradelimiting extends admin_setting_configcheckbox {
3526 function admin_setting_special_gradelimiting() {
3527 parent::admin_setting_configcheckbox('unlimitedgrades', get_string('unlimitedgrades', 'grades'),
3528 get_string('configunlimitedgrades', 'grades'), '0', '1', '0');
3531 function regrade_all() {
3532 global $CFG;
3533 require_once("$CFG->libdir/gradelib.php");
3534 grade_force_site_regrading();
3537 function write_setting($data) {
3538 $previous = $this->get_setting();
3540 if ($previous === null) {
3541 if ($data) {
3542 $this->regrade_all();
3544 } else {
3545 if ($data != $previous) {
3546 $this->regrade_all();
3549 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
3555 * Primary grade export plugin - has state tracking.
3557 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
3558 function admin_setting_special_gradeexport() {
3559 parent::admin_setting_configmulticheckbox('gradeexport', get_string('gradeexport', 'admin'),
3560 get_string('configgradeexport', 'admin'), array(), NULL);
3563 function load_choices() {
3564 if (is_array($this->choices)) {
3565 return true;
3567 $this->choices = array();
3569 if ($plugins = get_list_of_plugins('grade/export')) {
3570 foreach($plugins as $plugin) {
3571 $this->choices[$plugin] = get_string('modulename', 'gradeexport_'.$plugin);
3574 return true;
3579 * Grade category settings
3581 class admin_setting_gradecat_combo extends admin_setting {
3583 var $choices;
3585 function admin_setting_gradecat_combo($name, $visiblename, $description, $defaultsetting, $choices) {
3586 $this->choices = $choices;
3587 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
3590 function get_setting() {
3591 global $CFG;
3593 $value = $this->config_read($this->name);
3594 $flag = $this->config_read($this->name.'_flag');
3596 if (is_null($value) or is_null($flag)) {
3597 return NULL;
3600 $flag = (int)$flag;
3601 $forced = (boolean)(1 & $flag); // first bit
3602 $adv = (boolean)(2 & $flag); // second bit
3604 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
3607 function write_setting($data) {
3608 global $CFG;
3610 $value = $data['value'];
3611 $forced = empty($data['forced']) ? 0 : 1;
3612 $adv = empty($data['adv']) ? 0 : 2;
3613 $flag = ($forced | $adv); //bitwise or
3615 if (!in_array($value, array_keys($this->choices))) {
3616 return 'Error setting ';
3619 $oldvalue = $this->config_read($this->name);
3620 $oldflag = (int)$this->config_read($this->name.'_flag');
3621 $oldforced = (1 & $oldflag); // first bit
3623 $result1 = $this->config_write($this->name, $value);
3624 $result2 = $this->config_write($this->name.'_flag', $flag);
3626 // force regrade if needed
3627 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
3628 require_once($CFG->libdir.'/gradelib.php');
3629 grade_category::updated_forced_settings();
3632 if ($result1 and $result2) {
3633 return '';
3634 } else {
3635 return get_string('errorsetting', 'admin');
3639 function output_html($data, $query='') {
3640 $value = $data['value'];
3641 $forced = !empty($data['forced']);
3642 $adv = !empty($data['adv']);
3644 $default = $this->get_defaultsetting();
3645 if (!is_null($default)) {
3646 $defaultinfo = array();
3647 if (isset($this->choices[$default['value']])) {
3648 $defaultinfo[] = $this->choices[$default['value']];
3650 if (!empty($default['forced'])) {
3651 $defaultinfo[] = get_string('force');
3653 if (!empty($default['adv'])) {
3654 $defaultinfo[] = get_string('advanced');
3656 $defaultinfo = implode(', ', $defaultinfo);
3658 } else {
3659 $defaultinfo = NULL;
3663 $return = '<div class="form-group">';
3664 $return .= '<select class="form-select" id="'.$this->get_id().'" name="'.$this->get_full_name().'[value]">';
3665 foreach ($this->choices as $key => $val) {
3666 // the string cast is needed because key may be integer - 0 is equal to most strings!
3667 $return .= '<option value="'.$key.'"'.((string)$key==$value ? ' selected="selected"' : '').'>'.$val.'</option>';
3669 $return .= '</select>';
3670 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'force" name="'.$this->get_full_name().'[forced]" value="1" '.($forced ? 'checked="checked"' : '').' />'
3671 .'<label for="'.$this->get_id().'force">'.get_string('force').'</label>';
3672 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'adv" name="'.$this->get_full_name().'[adv]" value="1" '.($adv ? 'checked="checked"' : '').' />'
3673 .'<label for="'.$this->get_id().'adv">'.get_string('advanced').'</label>';
3674 $return .= '</div>';
3676 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
3682 * Selection of grade report in user profiles
3684 class admin_setting_grade_profilereport extends admin_setting_configselect {
3685 function admin_setting_grade_profilereport() {
3686 parent::admin_setting_configselect('grade_profilereport', get_string('profilereport', 'grades'), get_string('configprofilereport', 'grades'), 'user', null);
3689 function load_choices() {
3690 if (is_array($this->choices)) {
3691 return true;
3693 $this->choices = array();
3695 global $CFG;
3696 require_once($CFG->libdir.'/gradelib.php');
3698 foreach (get_list_of_plugins('grade/report') as $plugin) {
3699 if (file_exists($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php')) {
3700 require_once($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php');
3701 $functionname = 'grade_report_'.$plugin.'_profilereport';
3702 if (function_exists($functionname)) {
3703 $this->choices[$plugin] = get_string('modulename', 'gradereport_'.$plugin, NULL, $CFG->dirroot.'/grade/report/'.$plugin.'/lang/');
3707 return true;
3712 * Special class for register auth selection
3714 class admin_setting_special_registerauth extends admin_setting_configselect {
3715 function admin_setting_special_registerauth() {
3716 parent::admin_setting_configselect('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null);
3719 function get_defaultsettings() {
3720 $this->load_choices();
3721 if (array_key_exists($this->defaultsetting, $this->choices)) {
3722 return $this->defaultsetting;
3723 } else {
3724 return '';
3728 function load_choices() {
3729 global $CFG;
3731 if (is_array($this->choices)) {
3732 return true;
3734 $this->choices = array();
3735 $this->choices[''] = get_string('disable');
3737 $authsenabled = get_enabled_auth_plugins(true);
3739 foreach ($authsenabled as $auth) {
3740 $authplugin = get_auth_plugin($auth);
3741 if (!$authplugin->can_signup()) {
3742 continue;
3744 // Get the auth title (from core or own auth lang files)
3745 $authtitle = $authplugin->get_title();
3746 $this->choices[$auth] = $authtitle;
3748 return true;
3753 * Module manage page
3755 class admin_page_managemods extends admin_externalpage {
3756 function admin_page_managemods() {
3757 global $CFG;
3758 parent::admin_externalpage('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
3761 function search($query) {
3762 if ($result = parent::search($query)) {
3763 return $result;
3766 $found = false;
3767 if ($modules = get_records('modules')) {
3768 $textlib = textlib_get_instance();
3769 foreach ($modules as $module) {
3770 if (strpos($module->name, $query) !== false) {
3771 $found = true;
3772 break;
3774 $strmodulename = get_string('modulename', $module->name);
3775 if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
3776 $found = true;
3777 break;
3781 if ($found) {
3782 $result = new object();
3783 $result->page = $this;
3784 $result->settings = array();
3785 return array($this->name => $result);
3786 } else {
3787 return array();
3793 * Enrolment manage page
3795 class admin_enrolment_page extends admin_externalpage {
3796 function admin_enrolment_page() {
3797 global $CFG;
3798 parent::admin_externalpage('enrolment', get_string('enrolments'), $CFG->wwwroot . '/'.$CFG->admin.'/enrol.php');
3801 function search($query) {
3802 if ($result = parent::search($query)) {
3803 return $result;
3806 $found = false;
3808 if ($modules = get_list_of_plugins('enrol')) {
3809 $textlib = textlib_get_instance();
3810 foreach ($modules as $plugin) {
3811 if (strpos($plugin, $query) !== false) {
3812 $found = true;
3813 break;
3815 $strmodulename = get_string('enrolname', "enrol_$plugin");
3816 if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
3817 $found = true;
3818 break;
3822 //ugly harcoded hacks
3823 if (strpos('sendcoursewelcomemessage', $query) !== false) {
3824 $found = true;
3825 } else if (strpos($textlib->strtolower(get_string('sendcoursewelcomemessage', 'admin')), $query) !== false) {
3826 $found = true;
3827 } else if (strpos($textlib->strtolower(get_string('configsendcoursewelcomemessage', 'admin')), $query) !== false) {
3828 $found = true;
3829 } else if (strpos($textlib->strtolower(get_string('configenrolmentplugins', 'admin')), $query) !== false) {
3830 $found = true;
3832 if ($found) {
3833 $result = new object();
3834 $result->page = $this;
3835 $result->settings = array();
3836 return array($this->name => $result);
3837 } else {
3838 return array();
3844 * Blocks manage page
3846 class admin_page_manageblocks extends admin_externalpage {
3847 function admin_page_manageblocks() {
3848 global $CFG;
3849 parent::admin_externalpage('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
3852 function search($query) {
3853 global $CFG;
3854 if ($result = parent::search($query)) {
3855 return $result;
3858 $found = false;
3859 if (!empty($CFG->blocks_version) and $blocks = get_records('block')) {
3860 $textlib = textlib_get_instance();
3861 foreach ($blocks as $block) {
3862 if (strpos($block->name, $query) !== false) {
3863 $found = true;
3864 break;
3866 $strblockname = get_string('blockname', 'block_'.$block->name);
3867 if (strpos($textlib->strtolower($strblockname), $query) !== false) {
3868 $found = true;
3869 break;
3873 if ($found) {
3874 $result = new object();
3875 $result->page = $this;
3876 $result->settings = array();
3877 return array($this->name => $result);
3878 } else {
3879 return array();
3885 * Special class for authentication administration.
3887 class admin_setting_manageauths extends admin_setting {
3888 function admin_setting_manageauths() {
3889 parent::admin_setting('authsui', get_string('authsettings', 'admin'), '', '');
3892 function get_setting() {
3893 return true;
3896 function get_defaultsetting() {
3897 return true;
3900 function write_setting($data) {
3901 // do not write any setting
3902 return '';
3905 function is_related($query) {
3906 if (parent::is_related($query)) {
3907 return true;
3910 $textlib = textlib_get_instance();
3911 $authsavailable = get_list_of_plugins('auth');
3912 foreach ($authsavailable as $auth) {
3913 if (strpos($auth, $query) !== false) {
3914 return true;
3916 $authplugin = get_auth_plugin($auth);
3917 $authtitle = $authplugin->get_title();
3918 if (strpos($textlib->strtolower($authtitle), $query) !== false) {
3919 return true;
3922 return false;
3925 function output_html($data, $query='') {
3926 global $CFG;
3929 // display strings
3930 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
3931 'settings', 'edit', 'name', 'enable', 'disable',
3932 'up', 'down', 'none'));
3933 $txt->updown = "$txt->up/$txt->down";
3935 $authsavailable = get_list_of_plugins('auth');
3936 get_enabled_auth_plugins(true); // fix the list of enabled auths
3937 if (empty($CFG->auth)) {
3938 $authsenabled = array();
3939 } else {
3940 $authsenabled = explode(',', $CFG->auth);
3943 // construct the display array, with enabled auth plugins at the top, in order
3944 $displayauths = array();
3945 $registrationauths = array();
3946 $registrationauths[''] = $txt->disable;
3947 foreach ($authsenabled as $auth) {
3948 $authplugin = get_auth_plugin($auth);
3949 /// Get the auth title (from core or own auth lang files)
3950 $authtitle = $authplugin->get_title();
3951 /// Apply titles
3952 $displayauths[$auth] = $authtitle;
3953 if ($authplugin->can_signup()) {
3954 $registrationauths[$auth] = $authtitle;
3958 foreach ($authsavailable as $auth) {
3959 if (array_key_exists($auth, $displayauths)) {
3960 continue; //already in the list
3962 $authplugin = get_auth_plugin($auth);
3963 /// Get the auth title (from core or own auth lang files)
3964 $authtitle = $authplugin->get_title();
3965 /// Apply titles
3966 $displayauths[$auth] = $authtitle;
3967 if ($authplugin->can_signup()) {
3968 $registrationauths[$auth] = $authtitle;
3972 $return = print_heading(get_string('actauthhdr', 'auth'), '', 3, 'main', true);
3973 $return .= print_box_start('generalbox authsui', '', true);
3975 $table = new object();
3976 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings);
3977 $table->align = array('left', 'center', 'center', 'center');
3978 $table->width = '90%';
3979 $table->data = array();
3981 //add always enabled plugins first
3982 $displayname = "<span>".$displayauths['manual']."</span>";
3983 $settings = "<a href=\"auth_config.php?auth=manual\">{$txt->settings}</a>";
3984 //$settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
3985 $table->data[] = array($displayname, '', '', $settings);
3986 $displayname = "<span>".$displayauths['nologin']."</span>";
3987 $settings = "<a href=\"auth_config.php?auth=nologin\">{$txt->settings}</a>";
3988 $table->data[] = array($displayname, '', '', $settings);
3991 // iterate through auth plugins and add to the display table
3992 $updowncount = 1;
3993 $authcount = count($authsenabled);
3994 $url = "auth.php?sesskey=" . sesskey();
3995 foreach ($displayauths as $auth => $name) {
3996 if ($auth == 'manual' or $auth == 'nologin') {
3997 continue;
3999 // hide/show link
4000 if (in_array($auth, $authsenabled)) {
4001 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
4002 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"disable\" /></a>";
4003 // $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\"><input type=\"checkbox\" checked /></a>";
4004 $enabled = true;
4005 $displayname = "<span>$name</span>";
4007 else {
4008 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
4009 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"enable\" /></a>";
4010 // $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\"><input type=\"checkbox\" /></a>";
4011 $enabled = false;
4012 $displayname = "<span class=\"dimmed_text\">$name</span>";
4015 // up/down link (only if auth is enabled)
4016 $updown = '';
4017 if ($enabled) {
4018 if ($updowncount > 1) {
4019 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
4020 $updown .= "<img src=\"{$CFG->pixpath}/t/up.gif\" alt=\"up\" /></a>&nbsp;";
4022 else {
4023 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
4025 if ($updowncount < $authcount) {
4026 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
4027 $updown .= "<img src=\"{$CFG->pixpath}/t/down.gif\" alt=\"down\" /></a>";
4029 else {
4030 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />";
4032 ++ $updowncount;
4035 // settings link
4036 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
4037 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
4038 } else {
4039 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
4042 // add a row to the table
4043 $table->data[] =array($displayname, $hideshow, $updown, $settings);
4045 $return .= print_table($table, true);
4046 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
4047 $return .= print_box_end(true);
4048 return highlight($query, $return);
4052 * Special class for filter administration.
4054 class admin_setting_managefilters extends admin_setting {
4055 function admin_setting_managefilters() {
4056 parent::admin_setting('filtersui', get_string('filtersettings', 'admin'), '', '');
4059 function get_setting() {
4060 return true;
4063 function get_defaultsetting() {
4064 return true;
4067 function write_setting($data) {
4068 // do not write any setting
4069 return '';
4072 function is_related($query) {
4073 if (parent::is_related($query)) {
4074 return true;
4077 $textlib = textlib_get_instance();
4078 $filterlocations = array('mod','filter');
4079 foreach ($filterlocations as $filterlocation) {
4080 $plugins = get_list_of_plugins($filterlocation);
4081 foreach ($plugins as $plugin) {
4082 if (strpos($plugin, $query) !== false) {
4083 return true;
4085 $name = get_string('filtername', $plugin);
4086 if (strpos($textlib->strtolower($name), $query) !== false) {
4087 return true;
4091 return false;
4094 function output_html($data, $query='') {
4095 global $CFG;
4097 $strname = get_string('name');
4098 $strhide = get_string('disable');
4099 $strshow = get_string('enable');
4100 $strhideshow = "$strhide/$strshow";
4101 $strsettings = get_string('settings');
4102 $strup = get_string('up');
4103 $strdown = get_string('down');
4104 $strupdown = "$strup/$strdown";
4106 // get a list of possible filters (and translate name if possible)
4107 // note filters can be in the dedicated filters area OR in their
4108 // associated modules
4109 $installedfilters = array();
4110 $filtersettings_new = array();
4111 $filtersettings_old = array();
4112 $filterlocations = array('mod','filter');
4113 foreach ($filterlocations as $filterlocation) {
4114 $plugins = get_list_of_plugins($filterlocation);
4115 foreach ($plugins as $plugin) {
4116 $pluginpath = "$CFG->dirroot/$filterlocation/$plugin/filter.php";
4117 $settingspath_new = "$CFG->dirroot/$filterlocation/$plugin/filtersettings.php";
4118 $settingspath_old = "$CFG->dirroot/$filterlocation/$plugin/filterconfig.html";
4119 if (is_readable($pluginpath)) {
4120 $name = trim(get_string("filtername", $plugin));
4121 if (empty($name) or ($name == '[[filtername]]')) {
4122 $textlib = textlib_get_instance();
4123 $name = $textlib->strtotitle($plugin);
4125 $installedfilters["$filterlocation/$plugin"] = $name;
4126 if (is_readable($settingspath_new)) {
4127 $filtersettings_new[] = "$filterlocation/$plugin";
4128 } else if (is_readable($settingspath_old)) {
4129 $filtersettings_old[] = "$filterlocation/$plugin";
4135 // get all the currently selected filters
4136 if (!empty($CFG->textfilters)) {
4137 $oldactivefilters = explode(',', $CFG->textfilters);
4138 $oldactivefilters = array_unique($oldactivefilters);
4139 } else {
4140 $oldactivefilters = array();
4143 // take this opportunity to clean up filters
4144 $activefilters = array();
4145 foreach ($oldactivefilters as $oldactivefilter) {
4146 if (!empty($oldactivefilter) and array_key_exists($oldactivefilter, $installedfilters)) {
4147 $activefilters[] = $oldactivefilter;
4151 // construct the display array with installed filters
4152 // at the top in the right order
4153 $displayfilters = array();
4154 foreach ($activefilters as $activefilter) {
4155 $name = $installedfilters[$activefilter];
4156 $displayfilters[$activefilter] = $name;
4158 foreach ($installedfilters as $key => $filter) {
4159 if (!array_key_exists($key, $displayfilters)) {
4160 $displayfilters[$key] = $filter;
4164 $return = print_heading(get_string('actfilterhdr', 'filters'), '', 3, 'main', true);
4165 $return .= print_box_start('generalbox filtersui', '', true);
4167 $table = new object();
4168 $table->head = array($strname, $strhideshow, $strupdown, $strsettings);
4169 $table->align = array('left', 'center', 'center', 'center');
4170 $table->width = '90%';
4171 $table->data = array();
4173 $filtersurl = "$CFG->wwwroot/$CFG->admin/filters.php?sesskey=".sesskey();
4174 $imgurl = "$CFG->pixpath/t";
4176 // iterate through filters adding to display table
4177 $updowncount = 1;
4178 $activefilterscount = count($activefilters);
4179 foreach ($displayfilters as $path => $name) {
4180 $upath = urlencode($path);
4181 // get hide/show link
4182 if (in_array($path, $activefilters)) {
4183 $hideshow = "<a href=\"$filtersurl&amp;action=hide&amp;filterpath=$upath\">";
4184 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"$strhide\" /></a>";
4185 $hidden = false;
4186 $displayname = "<span>$name</span>";
4188 else {
4189 $hideshow = "<a href=\"$filtersurl&amp;action=show&amp;filterpath=$upath\">";
4190 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"$strshow\" /></a>";
4191 $hidden = true;
4192 $displayname = "<span class=\"dimmed_text\">$name</span>";
4195 // get up/down link (only if not hidden)
4196 $updown = '';
4197 if (!$hidden) {
4198 if ($updowncount>1) {
4199 $updown .= "<a href=\"$filtersurl&amp;action=up&amp;filterpath=$upath\">";
4200 $updown .= "<img src=\"$imgurl/up.gif\" alt=\"$strup\" /></a>&nbsp;";
4202 else {
4203 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
4205 if ($updowncount<$activefilterscount) {
4206 $updown .= "<a href=\"$filtersurl&amp;action=down&amp;filterpath=$upath\">";
4207 $updown .= "<img src=\"$imgurl/down.gif\" alt=\"$strdown\" /></a>";
4209 else {
4210 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />";
4212 ++$updowncount;
4215 // settings link (if defined)
4216 $settings = '';
4217 if (in_array($path, $filtersettings_new)) {
4218 $settings = "<a href=\"settings.php?section=filtersetting".str_replace('/', '',$path)."\">$strsettings</a>";
4219 } else if (in_array($path, $filtersettings_old)) {
4220 $settings = "<a href=\"filter.php?filter=".urlencode($path)."\">$strsettings</a>";
4223 // write data into the table object
4224 $table->data[] = array($displayname, $hideshow, $updown, $settings);
4226 $return .= print_table($table, true);
4227 $return .= get_string('tablenosave', 'filters');
4228 $return .= print_box_end(true);
4229 return highlight($query, $return);
4234 * Initialise admin page - this function does require login and permission
4235 * checks specified in page definition.
4236 * This function must be called on each admin page before other code.
4237 * @param string $section name of page
4238 * @param string $extrabutton extra HTML that is added after the blocks editing on/off button.
4239 * @param string $extraurlparams an array paramname => paramvalue, or parameters that need to be
4240 * added to the turn blocks editing on/off form, so this page reloads correctly.
4241 * @param string $actualurl if the actual page being viewed is not the normal one for this
4242 * page (e.g. admin/roles/allowassin.php, instead of admin/roles/manage.php, you can pass the alternate URL here.
4244 function admin_externalpage_setup($section, $extrabutton='', $extraurlparams=array(), $actualurl='') {
4246 global $CFG, $PAGE, $USER;
4247 require_once($CFG->libdir.'/blocklib.php');
4248 require_once($CFG->dirroot.'/'.$CFG->admin.'/pagelib.php');
4250 if ($site = get_site()) {
4251 require_login();
4252 } else {
4253 redirect($CFG->wwwroot.'/'.$CFG->admin.'/index.php');
4254 die;
4257 $adminroot =& admin_get_root(false, false); // settings not required for external pages
4258 $extpage =& $adminroot->locate($section);
4260 if (empty($extpage) or !is_a($extpage, 'admin_externalpage')) {
4261 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
4262 die;
4265 // this eliminates our need to authenticate on the actual pages
4266 if (!($extpage->check_access())) {
4267 print_error('accessdenied', 'admin');
4268 die;
4271 page_map_class(PAGE_ADMIN, 'page_admin');
4272 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
4273 $PAGE->init_extra($section); // hack alert!
4274 $PAGE->set_extra_button($extrabutton);
4275 $PAGE->set_extra_url_params($extraurlparams, $actualurl);
4277 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
4279 if (!isset($USER->adminediting)) {
4280 $USER->adminediting = false;
4283 if ($PAGE->user_allowed_editing()) {
4284 if ($adminediting == 1) {
4285 $USER->adminediting = true;
4286 } elseif ($adminediting == 0) {
4287 $USER->adminediting = false;
4293 * Print header for admin page
4294 * @param string $focus focus element
4296 function admin_externalpage_print_header($focus='') {
4298 if (!is_string($focus)) {
4299 $focus = ''; // BC compatibility, there used to be adminroot parameter
4302 global $CFG, $PAGE, $SITE, $THEME;
4304 define('ADMIN_EXT_HEADER_PRINTED', 'true');
4306 if (!empty($SITE->fullname)) {
4307 $pageblocks = blocks_setup($PAGE);
4309 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
4310 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
4311 BLOCK_L_MAX_WIDTH);
4312 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
4313 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
4314 BLOCK_R_MAX_WIDTH);
4316 $PAGE->print_header('', $focus);
4317 echo '<table id="layout-table" summary=""><tr>';
4319 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
4320 foreach ($lt as $column) {
4321 $lt1[] = $column;
4322 if ($column == 'middle') break;
4324 foreach ($lt1 as $column) {
4325 switch ($column) {
4326 case 'left':
4327 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
4328 print_container_start();
4329 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
4330 print_container_end();
4331 echo '</td>';
4332 break;
4334 case 'middle':
4335 echo '<td id="middle-column">';
4336 print_container_start(true);
4337 $THEME->open_header_containers++; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
4338 break;
4340 case 'right':
4341 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
4342 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
4343 print_container_start();
4344 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
4345 print_container_end();
4346 echo '</td>';
4348 break;
4351 } else {
4352 print_header();
4357 * Print footer on admin page - please use normal print_footer() instead
4359 function admin_externalpage_print_footer() {
4361 global $CFG, $PAGE, $SITE, $THEME;
4363 define('ADMIN_EXT_FOOTER_PRINTED', 'true');
4365 if (!empty($SITE->fullname)) {
4366 $pageblocks = blocks_setup($PAGE);
4367 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
4368 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
4369 BLOCK_L_MAX_WIDTH);
4370 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
4371 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
4372 BLOCK_R_MAX_WIDTH);
4374 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
4375 foreach ($lt as $column) {
4376 if ($column != 'middle') {
4377 array_shift($lt);
4378 } else if ($column == 'middle') {
4379 break;
4382 foreach ($lt as $column) {
4383 switch ($column) {
4384 case 'left':
4385 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
4386 print_container_start();
4387 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
4388 print_container_end();
4389 echo '</td>';
4390 break;
4392 case 'middle':
4393 print_container_end();
4394 $THEME->open_header_containers--; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
4395 echo '</td>';
4396 break;
4398 case 'right':
4399 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
4400 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
4401 print_container_start();
4402 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
4403 print_container_end();
4404 echo '</td>';
4406 break;
4409 echo '</tr></table>';
4411 print_footer();
4415 * Returns the reference to admin tree root
4416 * @return reference
4418 function &admin_get_root($reload=false, $requirefulltree=true) {
4419 global $CFG;
4421 static $ADMIN = NULL;
4423 if (!is_null($ADMIN)) {
4424 $olderrors = $ADMIN->errors;
4425 $oldsearch = $ADMIN->search;
4426 $oldfulltree = $ADMIN->fulltree;
4427 } else {
4428 $olderrors = array();
4429 $oldsearch = '';
4430 $oldfulltree = false;
4433 if ($reload or ($requirefulltree and !$oldfulltree)) {
4434 $ADMIN = NULL;
4437 if (is_null($ADMIN)) {
4438 // start the admin tree!
4439 $ADMIN = new admin_root();
4440 // array of error messages and search query
4441 $ADMIN->errors = $olderrors;
4442 $ADMIN->search = $oldsearch;
4443 if ($requirefulltree) {
4444 $ADMIN->fulltree = true;
4445 } else {
4446 $ADMIN->fulltree = $oldfulltree;
4449 // we process this file first to create categories first and in correct order
4450 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
4452 // now we process all other files in admin/settings to build the admin tree
4453 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
4454 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
4455 continue;
4457 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') {
4458 // plugins are loaded last - they may insert pages anywhere
4459 continue;
4461 include($file);
4463 include($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php');
4465 if (file_exists($CFG->dirroot.'/local/settings.php')) {
4466 include($CFG->dirroot.'/local/settings.php');
4470 return $ADMIN;
4473 /// settings utility functions
4476 * This function applies default settings.
4477 * @param object $node, NULL means complete tree
4478 * @param bool $uncoditional if true overrides all values with defaults
4479 * @return void
4481 function admin_apply_default_settings($node=NULL, $unconditional=true) {
4482 global $CFG;
4484 if (is_null($node)) {
4485 $node =& admin_get_root();
4488 if (is_a($node, 'admin_category')) {
4489 $entries = array_keys($node->children);
4490 foreach ($entries as $entry) {
4491 admin_apply_default_settings($node->children[$entry], $unconditional);
4494 } else if (is_a($node, 'admin_settingpage')) {
4495 foreach ($node->settings as $setting) {
4496 if (!$unconditional and !is_null($setting->get_setting())) {
4497 //do not override existing defaults
4498 continue;
4500 $defaultsetting = $setting->get_defaultsetting();
4501 if (is_null($defaultsetting)) {
4502 // no value yet - default maybe applied after admin user creation or in upgradesettings
4503 continue;
4505 $setting->write_setting($defaultsetting);
4511 * Store changed settings, this function updates the errors variable in $ADMIN
4512 * @param object $formdata from form (without magic quotes)
4513 * @return int number of changed settings
4515 function admin_write_settings($formdata) {
4516 global $CFG, $SITE, $COURSE;
4518 $olddbsessions = !empty($CFG->dbsessions);
4519 $formdata = (array)stripslashes_recursive($formdata);
4521 $data = array();
4522 foreach ($formdata as $fullname=>$value) {
4523 if (strpos($fullname, 's_') !== 0) {
4524 continue; // not a config value
4526 $data[$fullname] = $value;
4529 $adminroot =& admin_get_root();
4530 $settings = admin_find_write_settings($adminroot, $data);
4532 $count = 0;
4533 foreach ($settings as $fullname=>$setting) {
4534 $original = serialize($setting->get_setting()); // comparison must work for arrays too
4535 $error = $setting->write_setting($data[$fullname]);
4536 if ($error !== '') {
4537 $adminroot->errors[$fullname] = new object();
4538 $adminroot->errors[$fullname]->data = $data[$fullname];
4539 $adminroot->errors[$fullname]->id = $setting->get_id();
4540 $adminroot->errors[$fullname]->error = $error;
4542 if ($original !== serialize($setting->get_setting())) {
4543 $count++;
4544 $callbackfunction = $setting->updatedcallback;
4545 if (function_exists($callbackfunction)) {
4546 $callbackfunction($fullname);
4551 if ($olddbsessions != !empty($CFG->dbsessions)) {
4552 require_logout();
4555 // now update $SITE - it might have been changed
4556 $SITE = get_record('course', 'id', $SITE->id);
4557 $COURSE = clone($SITE);
4559 // now reload all settings - some of them might depend on the changed
4560 admin_get_root(true);
4561 return $count;
4565 * Internal recursive function - finds all settings from submitted form
4567 function admin_find_write_settings($node, $data) {
4568 $return = array();
4570 if (empty($data)) {
4571 return $return;
4574 if (is_a($node, 'admin_category')) {
4575 $entries = array_keys($node->children);
4576 foreach ($entries as $entry) {
4577 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
4580 } else if (is_a($node, 'admin_settingpage')) {
4581 foreach ($node->settings as $setting) {
4582 $fullname = $setting->get_full_name();
4583 if (array_key_exists($fullname, $data)) {
4584 $return[$fullname] = $setting;
4590 return $return;
4594 * Internal function - prints the search results
4596 function admin_search_settings_html($query) {
4597 global $CFG;
4599 $textlib = textlib_get_instance();
4600 if ($textlib->strlen($query) < 2) {
4601 return '';
4603 $query = $textlib->strtolower($query);
4605 $adminroot =& admin_get_root();
4606 $findings = $adminroot->search($query);
4607 $return = '';
4608 $savebutton = false;
4610 foreach ($findings as $found) {
4611 $page = $found->page;
4612 $settings = $found->settings;
4613 if ($page->is_hidden()) {
4614 // hidden pages are not displayed in search results
4615 continue;
4617 if (is_a($page, 'admin_externalpage')) {
4618 $return .= print_heading(get_string('searchresults','admin').' - <a href="'.$page->url.'">'.highlight($query, $page->visiblename).'</a>', '', 2, 'main', true);
4619 } else if (is_a($page, 'admin_settingpage')) {
4620 $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);
4621 } else {
4622 continue;
4624 if (!empty($settings)) {
4625 $savebutton = true;
4626 $return .= '<fieldset class="adminsettings">'."\n";
4627 foreach ($settings as $setting) {
4628 $return .= '<div class="clearer"><!-- --></div>'."\n";
4629 $fullname = $setting->get_full_name();
4630 if (array_key_exists($fullname, $adminroot->errors)) {
4631 $data = $adminroot->errors[$fullname]->data;
4632 } else {
4633 $data = $setting->get_setting();
4634 if (is_null($data)) {
4635 $data = $setting->get_defaultsetting();
4638 $return .= $setting->output_html($data, $query);
4640 $return .= '</fieldset>';
4644 if ($savebutton) {
4645 $return .= '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges','admin').'" /></div>';
4648 return $return;
4652 * Internal function - returns arrays of html pages with uninitialised settings
4654 function admin_output_new_settings_by_page($node) {
4655 $return = array();
4657 if (is_a($node, 'admin_category')) {
4658 $entries = array_keys($node->children);
4659 foreach ($entries as $entry) {
4660 $return += admin_output_new_settings_by_page($node->children[$entry]);
4663 } else if (is_a($node, 'admin_settingpage')) {
4664 $newsettings = array();
4665 foreach ($node->settings as $setting) {
4666 if (is_null($setting->get_setting())) {
4667 $newsettings[] = $setting;
4670 if (count($newsettings) > 0) {
4671 $adminroot =& admin_get_root();
4672 $page = print_heading(get_string('upgradesettings','admin').' - '.$node->visiblename, '', 2, 'main', true);
4673 $page .= '<fieldset class="adminsettings">'."\n";
4674 foreach ($newsettings as $setting) {
4675 $fullname = $setting->get_full_name();
4676 if (array_key_exists($fullname, $adminroot->errors)) {
4677 $data = $adminroot->errors[$fullname]->data;
4678 } else {
4679 $data = $setting->get_setting();
4680 if (is_null($data)) {
4681 $data = $setting->get_defaultsetting();
4684 $page .= '<div class="clearer"><!-- --></div>'."\n";
4685 $page .= $setting->output_html($data);
4687 $page .= '</fieldset>';
4688 $return[$node->name] = $page;
4692 return $return;
4696 * Unconditionally applies default admin settings in main config table
4697 * @param array $defaults array of string values
4699 function apply_default_exception_settings($defaults) {
4700 foreach($defaults as $key => $value) {
4701 set_config($key, $value, NULL);
4706 * Format admin settings
4707 * @param string $object setting
4708 * @param string $title label element
4709 * @param string $form form fragment, html code - not highlighed automaticaly
4710 * @param string $description
4711 * @param bool $label link label to id
4712 * @param string $warning warning text
4713 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string
4714 * @param string $query search query to be highlighted
4716 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
4717 global $CFG;
4719 $name = $setting->name;
4720 $fullname = $setting->get_full_name();
4722 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
4723 if ($label) {
4724 $labelfor = 'for = "'.$setting->get_id().'"';
4725 } else {
4726 $labelfor = '';
4729 if (empty($setting->plugin) and array_key_exists($name, $CFG->config_php_settings)) {
4730 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
4731 } else {
4732 $override = '';
4735 if ($warning !== '') {
4736 $warning = '<div class="form-warning">'.$warning.'</div>';
4739 if (is_null($defaultinfo)) {
4740 $defaultinfo = '';
4741 } else {
4742 if ($defaultinfo === '') {
4743 $defaultinfo = get_string('emptysettingvalue', 'admin');
4745 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
4746 $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>';
4750 $str = '
4751 <div class="form-item clearfix" id="admin-'.$setting->name.'">
4752 <div class="form-label">
4753 <label '.$labelfor.'>'.highlightfast($query, $title).'<span class="form-shortname">'.highlightfast($query, $name).'</span>
4754 '.$override.$warning.'
4755 </label>
4756 </div>
4757 <div class="form-setting">'.$form.$defaultinfo.'</div>
4758 <div class="form-description">'.highlight($query, $description).'</div>
4759 </div>';
4761 $adminroot =& admin_get_root();
4762 if (array_key_exists($fullname, $adminroot->errors)) {
4763 $str = '<fieldset class="error"><legend>'.$adminroot->errors[$fullname]->error.'</legend>'.$str.'</fieldset>';
4766 return $str;
4770 * Try to upgrade the given language pack (or current language)
4771 * If it doesn't work, fail silently and return false
4773 function upgrade_language_pack($lang='') {
4774 global $CFG;
4776 if (empty($lang)) {
4777 $lang = current_language();
4780 if ($lang == 'en_utf8') {
4781 return true; // Nothing to do
4784 notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
4786 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
4787 @mkdir ($CFG->dataroot.'/lang/');
4789 require_once($CFG->libdir.'/componentlib.class.php');
4791 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
4792 $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
4794 if ($status == COMPONENT_INSTALLED) {
4795 debugging('Downloading successful: '.$lang);
4796 @unlink($CFG->dataroot.'/cache/languages');
4797 return true;
4801 return false;
4805 * Based on find_new_settings{@link ()} in upgradesettings.php
4806 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
4808 * @param string $node The node at which to start searching.
4809 * @return boolen true if any settings haven't been initialised, false if they all have
4811 function any_new_admin_settings($node) {
4813 if (is_a($node, 'admin_category')) {
4814 $entries = array_keys($node->children);
4815 foreach ($entries as $entry) {
4816 if (any_new_admin_settings($node->children[$entry])){
4817 return true;
4821 } else if (is_a($node, 'admin_settingpage')) {
4822 foreach ($node->settings as $setting) {
4823 if ($setting->get_setting() === NULL) {
4824 return true;
4829 return false;
4834 * Moved from admin/replace.php so that we can use this in cron
4835 * @param string $search - string to look for (with magic quotes)
4836 * @param string $replace - string to replace (with magic quotes)
4837 * @return bool - success or fail
4839 function db_replace($search, $replace) {
4841 global $db, $CFG;
4843 /// Turn off time limits, sometimes upgrades can be slow.
4844 @set_time_limit(0);
4845 @ob_implicit_flush(true);
4846 while(@ob_end_flush());
4848 if (!$tables = $db->Metatables() ) { // No tables yet at all.
4849 return false;
4851 foreach ($tables as $table) {
4853 if (in_array($table, array($CFG->prefix.'config'))) { // Don't process these
4854 continue;
4857 if ($columns = $db->MetaColumns($table, false)) {
4858 foreach ($columns as $column => $data) {
4859 if (in_array($data->type, array('text','mediumtext','longtext','varchar'))) { // Text stuff only
4860 $db->debug = true;
4861 execute_sql("UPDATE $table SET $column = REPLACE($column, '$search', '$replace')");
4862 $db->debug = false;
4868 return true;
4872 * Prints tables of detected plugins, one table per plugin type,
4873 * and prints whether they are part of the standard Moodle
4874 * distribution or not.
4876 function print_plugin_tables() {
4877 $plugins_standard = array();
4878 $plugins_standard['mod'] = array('assignment',
4879 'chat',
4880 'choice',
4881 'data',
4882 'exercise',
4883 'forum',
4884 'glossary',
4885 'hotpot',
4886 'journal',
4887 'label',
4888 'lams',
4889 'lesson',
4890 'quiz',
4891 'resource',
4892 'scorm',
4893 'survey',
4894 'wiki',
4895 'workshop');
4897 $plugins_standard['blocks'] = array('activity_modules',
4898 'admin',
4899 'admin_bookmarks',
4900 'admin_tree',
4901 'blog_menu',
4902 'blog_tags',
4903 'calendar_month',
4904 'calendar_upcoming',
4905 'course_list',
4906 'course_summary',
4907 'glossary_random',
4908 'html',
4909 'loancalc',
4910 'login',
4911 'mentees',
4912 'messages',
4913 'mnet_hosts',
4914 'news_items',
4915 'online_users',
4916 'participants',
4917 'quiz_results',
4918 'recent_activity',
4919 'rss_client',
4920 'search',
4921 'search_forums',
4922 'section_links',
4923 'site_main_menu',
4924 'social_activities',
4925 'tag_flickr',
4926 'tag_youtube',
4927 'tags');
4929 $plugins_standard['filter'] = array('activitynames',
4930 'algebra',
4931 'censor',
4932 'emailprotect',
4933 'filter',
4934 'mediaplugin',
4935 'multilang',
4936 'tex',
4937 'tidy');
4939 $plugins_installed = array();
4940 $installed_mods = get_records_list('modules', '', '', '', 'name');
4941 $installed_blocks = get_records_list('block', '', '', '', 'name');
4943 foreach($installed_mods as $mod) {
4944 $plugins_installed['mod'][] = $mod->name;
4947 foreach($installed_blocks as $block) {
4948 $plugins_installed['blocks'][] = $block->name;
4951 $plugins_ondisk = array();
4952 $plugins_ondisk['mod'] = get_list_of_plugins('mod', 'db');
4953 $plugins_ondisk['blocks'] = get_list_of_plugins('blocks', 'db');
4954 $plugins_ondisk['filter'] = get_list_of_plugins('filter', 'db');
4956 $strstandard = get_string('standard');
4957 $strnonstandard = get_string('nonstandard');
4958 $strmissingfromdisk = '(' . get_string('missingfromdisk') . ')';
4959 $strabouttobeinstalled = '(' . get_string('abouttobeinstalled') . ')';
4961 $html = '';
4963 $html .= '<table class="generaltable plugincheckwrapper" cellspacing="4" cellpadding="1"><tr valign="top">';
4965 foreach ($plugins_ondisk as $cat => $list_ondisk) {
4966 $strcaption = get_string($cat);
4967 if ($cat == 'mod') {
4968 $strcaption = get_string('activitymodule');
4969 } elseif ($cat == 'filter') {
4970 $strcaption = get_string('managefilters');
4973 $html .= '<td><table class="plugincompattable generaltable boxaligncenter" cellspacing="1" cellpadding="5" '
4974 . 'id="' . $cat . 'compattable" summary="compatibility table"><caption>' . $strcaption . '</caption>' . "\n";
4975 $html .= '<tr class="r0"><th class="header c0">' . get_string('directory') . "</th>\n"
4976 . '<th class="header c1">' . get_string('name') . "</th>\n"
4977 . '<th class="header c2">' . get_string('status') . "</th>\n</tr>\n";
4979 $row = 1;
4981 foreach ($list_ondisk as $k => $plugin) {
4982 $status = 'ok';
4983 $standard = 'standard';
4984 $note = '';
4986 if (!in_array($plugin, $plugins_standard[$cat])) {
4987 $standard = 'nonstandard';
4988 $status = 'warning';
4991 // Get real name and full path of plugin
4992 $plugin_name = "[[$plugin]]";
4994 $plugin_path = "$cat/$plugin";
4996 $plugin_name = get_plugin_name($plugin, $cat);
4998 // Determine if the plugin is about to be installed
4999 if ($cat != 'filter' && !in_array($plugin, $plugins_installed[$cat])) {
5000 $note = $strabouttobeinstalled;
5001 $plugin_name = $plugin;
5004 $html .= "<tr class=\"r$row\">\n"
5005 . "<td class=\"cell c0\">$plugin_path</td>\n"
5006 . "<td class=\"cell c1\">$plugin_name</td>\n"
5007 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $note</td>\n</tr>\n";
5008 $row++;
5010 // If the plugin was both on disk and in the db, unset the value from the installed plugins list
5011 if ($key = array_search($plugin, $plugins_installed[$cat])) {
5012 unset($plugins_installed[$cat][$key]);
5016 // If there are plugins left in the plugins_installed list, it means they are missing from disk
5017 foreach ($plugins_installed[$cat] as $k => $missing_plugin) {
5018 // Make sure the plugin really is missing from disk
5019 if (!in_array($missing_plugin, $plugins_ondisk[$cat])) {
5020 $standard = 'standard';
5021 $status = 'warning';
5023 if (!in_array($missing_plugin, $plugins_standard[$cat])) {
5024 $standard = 'nonstandard';
5027 $plugin_name = $missing_plugin;
5028 $html .= "<tr class=\"r$row\">\n"
5029 . "<td class=\"cell c0\">?</td>\n"
5030 . "<td class=\"cell c1\">$plugin_name</td>\n"
5031 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $strmissingfromdisk</td>\n</tr>\n";
5032 $row++;
5036 $html .= '</table></td>';
5039 $html .= '</tr></table><br />';
5041 echo $html;