Bumped the version up to 1.9.3
[moodle.git] / lib / adminlib.php
blob542105a6fbdbb8db32f4f32b1cff6e4e1fbe5f23
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 '.$module->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 * Try to verify that dataroot is not accessible from web.
754 * It is not 100% correct but might help to reduce number of vulnerable sites.
756 * Protection from httpd.conf and .htaccess is not detected properly.
757 * @param bool $fetchtest try to test public access by fetching file
758 * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING migth be problematic
760 function is_dataroot_insecure($fetchtest=false) {
761 global $CFG;
763 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
765 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
766 $rp = strrev(trim($rp, '/'));
767 $rp = explode('/', $rp);
768 foreach($rp as $r) {
769 if (strpos($siteroot, '/'.$r.'/') === 0) {
770 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
771 } else {
772 break; // probably alias root
776 $siteroot = strrev($siteroot);
777 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
779 if (strpos($dataroot, $siteroot) !== 0) {
780 return false;
783 if (!$fetchtest) {
784 return INSECURE_DATAROOT_WARNING;
787 // now try all methods to fetch a test file using http protocol
789 $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/'));
790 preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches);
791 $httpdocroot = $matches[1];
792 $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot));
793 if (make_upload_directory('diag', false) === false) {
794 return INSECURE_DATAROOT_WARNING;
796 $testfile = $CFG->dataroot.'/diag/public.txt';
797 if (!file_exists($testfile)) {
798 file_put_contents($testfile, 'test file, do not delete');
800 $teststr = trim(file_get_contents($testfile));
801 if (empty($teststr)) {
802 // hmm, strange
803 return INSECURE_DATAROOT_WARNING;
806 $testurl = $datarooturl.'/diag/public.txt';
808 if (extension_loaded('curl') and ($ch = @curl_init($testurl)) !== false) {
809 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
810 curl_setopt($ch, CURLOPT_HEADER, false);
811 $data = curl_exec($ch);
812 if (!curl_errno($ch)) {
813 $data = trim($data);
814 if ($data === $teststr) {
815 curl_close($ch);
816 return INSECURE_DATAROOT_ERROR;
819 curl_close($ch);
822 if ($data = @file_get_contents($testurl)) {
823 $data = trim($data);
824 if ($data === $teststr) {
825 return INSECURE_DATAROOT_ERROR;
829 preg_match('|https?://([^/]+)|i', $testurl, $matches);
830 $sitename = $matches[1];
831 $error = 0;
832 if ($fp = @fsockopen($sitename, 80, $error)) {
833 preg_match('|https?://[^/]+(.*)|i', $testurl, $matches);
834 $localurl = $matches[1];
835 $out = "GET $localurl HTTP/1.1\r\n";
836 $out .= "Host: $sitename\r\n";
837 $out .= "Connection: Close\r\n\r\n";
838 fwrite($fp, $out);
839 $data = '';
840 $incoming = false;
841 while (!feof($fp)) {
842 if ($incoming) {
843 $data .= fgets($fp, 1024);
844 } else if (@fgets($fp, 1024) === "\r\n") {
845 $incoming = true;
848 fclose($fp);
849 $data = trim($data);
850 if ($data === $teststr) {
851 return INSECURE_DATAROOT_ERROR;
855 return INSECURE_DATAROOT_WARNING;
858 /// =============================================================================================================
859 /// administration tree classes and functions
862 // n.b. documentation is still in progress for this code
864 /// INTRODUCTION
866 /// This file performs the following tasks:
867 /// -it defines the necessary objects and interfaces to build the Moodle
868 /// admin hierarchy
869 /// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
870 /// and admin_externalpage_print_footer() functions used on admin pages
872 /// ADMIN_SETTING OBJECTS
874 /// Moodle settings are represented by objects that inherit from the admin_setting
875 /// class. These objects encapsulate how to read a setting, how to write a new value
876 /// to a setting, and how to appropriately display the HTML to modify the setting.
878 /// ADMIN_SETTINGPAGE OBJECTS
880 /// The admin_setting objects are then grouped into admin_settingpages. The latter
881 /// appear in the Moodle admin tree block. All interaction with admin_settingpage
882 /// objects is handled by the admin/settings.php file.
884 /// ADMIN_EXTERNALPAGE OBJECTS
886 /// There are some settings in Moodle that are too complex to (efficiently) handle
887 /// with admin_settingpages. (Consider, for example, user management and displaying
888 /// lists of users.) In this case, we use the admin_externalpage object. This object
889 /// places a link to an external PHP file in the admin tree block.
891 /// If you're using an admin_externalpage object for some settings, you can take
892 /// advantage of the admin_externalpage_* functions. For example, suppose you wanted
893 /// to add a foo.php file into admin. First off, you add the following line to
894 /// admin/settings/first.php (at the end of the file) or to some other file in
895 /// admin/settings:
897 /// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
898 /// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
900 /// Next, in foo.php, your file structure would resemble the following:
902 /// require_once('.../config.php');
903 /// require_once($CFG->libdir.'/adminlib.php');
904 /// admin_externalpage_setup('foo');
905 /// // functionality like processing form submissions goes here
906 /// admin_externalpage_print_header();
907 /// // your HTML goes here
908 /// admin_externalpage_print_footer();
910 /// The admin_externalpage_setup() function call ensures the user is logged in,
911 /// and makes sure that they have the proper role permission to access the page.
913 /// The admin_externalpage_print_header() function prints the header (it figures
914 /// out what category and subcategories the page is classified under) and ensures
915 /// that you're using the admin pagelib (which provides the admin tree block and
916 /// the admin bookmarks block).
918 /// The admin_externalpage_print_footer() function properly closes the tables
919 /// opened up by the admin_externalpage_print_header() function and prints the
920 /// standard Moodle footer.
922 /// ADMIN_CATEGORY OBJECTS
924 /// Above and beyond all this, we have admin_category objects. These objects
925 /// appear as folders in the admin tree block. They contain admin_settingpage's,
926 /// admin_externalpage's, and other admin_category's.
928 /// OTHER NOTES
930 /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
931 /// from part_of_admin_tree (a pseudointerface). This interface insists that
932 /// a class has a check_access method for access permissions, a locate method
933 /// used to find a specific node in the admin tree and find parent path.
935 /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
936 /// interface ensures that the class implements a recursive add function which
937 /// accepts a part_of_admin_tree object and searches for the proper place to
938 /// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
940 /// Please note that the $this->name field of any part_of_admin_tree must be
941 /// UNIQUE throughout the ENTIRE admin tree.
943 /// The $this->name field of an admin_setting object (which is *not* part_of_
944 /// admin_tree) must be unique on the respective admin_settingpage where it is
945 /// used.
948 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
951 * Pseudointerface for anything appearing in the admin tree
953 * The pseudointerface that is implemented by anything that appears in the admin tree
954 * block. It forces inheriting classes to define a method for checking user permissions
955 * and methods for finding something in the admin tree.
957 * @author Vincenzo K. Marcovecchio
958 * @package admin
960 class part_of_admin_tree {
963 * Finds a named part_of_admin_tree.
965 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
966 * and not parentable_part_of_admin_tree, then this function should only check if
967 * $this->name matches $name. If it does, it should return a reference to $this,
968 * otherwise, it should return a reference to NULL.
970 * If a class inherits parentable_part_of_admin_tree, this method should be called
971 * recursively on all child objects (assuming, of course, the parent object's name
972 * doesn't match the search criterion).
974 * @param string $name The internal name of the part_of_admin_tree we're searching for.
975 * @return mixed An object reference or a NULL reference.
977 function &locate($name) {
978 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
979 return;
983 * Removes named part_of_admin_tree.
985 * @param string $name The internal name of the part_of_admin_tree we want to remove.
986 * @return bool success.
988 function prune($name) {
989 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
990 return;
994 * Search using query
995 * @param strin query
996 * @return mixed array-object structure of found settings and pages
998 function search($query) {
999 trigger_error('Admin class does not implement method <strong>search()</strong>', E_USER_WARNING);
1000 return;
1004 * Verifies current user's access to this part_of_admin_tree.
1006 * Used to check if the current user has access to this part of the admin tree or
1007 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
1008 * then this method is usually just a call to has_capability() in the site context.
1010 * If a class inherits parentable_part_of_admin_tree, this method should return the
1011 * logical OR of the return of check_access() on all child objects.
1013 * @return bool True if the user has access, false if she doesn't.
1015 function check_access() {
1016 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
1017 return;
1021 * Mostly usefull for removing of some parts of the tree in admin tree block.
1023 * @return True is hidden from normal list view
1025 function is_hidden() {
1026 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
1027 return;
1032 * Pseudointerface implemented by any part_of_admin_tree that has children.
1034 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
1035 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
1036 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
1037 * include an add method for adding other part_of_admin_tree objects as children.
1039 * @author Vincenzo K. Marcovecchio
1040 * @package admin
1042 class parentable_part_of_admin_tree extends part_of_admin_tree {
1045 * Adds a part_of_admin_tree object to the admin tree.
1047 * Used to add a part_of_admin_tree object to this object or a child of this
1048 * object. $something should only be added if $destinationname matches
1049 * $this->name. If it doesn't, add should be called on child objects that are
1050 * also parentable_part_of_admin_tree's.
1052 * @param string $destinationname The internal name of the new parent for $something.
1053 * @param part_of_admin_tree &$something The object to be added.
1054 * @return bool True on success, false on failure.
1056 function add($destinationname, $something) {
1057 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
1058 return;
1064 * The object used to represent folders (a.k.a. categories) in the admin tree block.
1066 * Each admin_category object contains a number of part_of_admin_tree objects.
1068 * @author Vincenzo K. Marcovecchio
1069 * @package admin
1071 class admin_category extends parentable_part_of_admin_tree {
1074 * @var mixed An array of part_of_admin_tree objects that are this object's children
1076 var $children;
1079 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
1081 var $name;
1084 * @var string The displayed name for this category. Usually obtained through get_string()
1086 var $visiblename;
1089 * @var bool Should this category be hidden in admin tree block?
1091 var $hidden;
1094 * paths
1096 var $path;
1097 var $visiblepath;
1100 * Constructor for an empty admin category
1102 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
1103 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
1104 * @param bool $hidden hide category in admin tree block
1106 function admin_category($name, $visiblename, $hidden=false) {
1107 $this->children = array();
1108 $this->name = $name;
1109 $this->visiblename = $visiblename;
1110 $this->hidden = $hidden;
1114 * Returns a reference to the part_of_admin_tree object with internal name $name.
1116 * @param string $name The internal name of the object we want.
1117 * @param bool $findpath initialize path and visiblepath arrays
1118 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1120 function &locate($name, $findpath=false) {
1121 if ($this->name == $name) {
1122 if ($findpath) {
1123 $this->visiblepath[] = $this->visiblename;
1124 $this->path[] = $this->name;
1126 return $this;
1129 $return = NULL;
1130 foreach($this->children as $childid=>$unused) {
1131 if ($return =& $this->children[$childid]->locate($name, $findpath)) {
1132 break;
1136 if (!is_null($return) and $findpath) {
1137 $return->visiblepath[] = $this->visiblename;
1138 $return->path[] = $this->name;
1141 return $return;
1145 * Search using query
1146 * @param strin query
1147 * @return mixed array-object structure of found settings and pages
1149 function search($query) {
1150 $result = array();
1151 foreach ($this->children as $child) {
1152 $subsearch = $child->search($query);
1153 if (!is_array($subsearch)) {
1154 debugging('Incorrect search result from '.$child->name);
1155 continue;
1157 $result = array_merge($result, $subsearch);
1159 return $result;
1163 * Removes part_of_admin_tree object with internal name $name.
1165 * @param string $name The internal name of the object we want to remove.
1166 * @return bool success
1168 function prune($name) {
1170 if ($this->name == $name) {
1171 return false; //can not remove itself
1174 foreach($this->children as $precedence => $child) {
1175 if ($child->name == $name) {
1176 // found it!
1177 unset($this->children[$precedence]);
1178 return true;
1180 if ($this->children[$precedence]->prune($name)) {
1181 return true;
1184 return false;
1188 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1190 * @param string $destinationame The internal name of the immediate parent that we want for $something.
1191 * @param mixed $something A part_of_admin_tree or setting instanceto be added.
1192 * @return bool True if successfully added, false if $something can not be added.
1194 function add($parentname, $something) {
1195 $parent =& $this->locate($parentname);
1196 if (is_null($parent)) {
1197 debugging('parent does not exist!');
1198 return false;
1201 if (is_a($something, 'part_of_admin_tree')) {
1202 if (!is_a($parent, 'parentable_part_of_admin_tree')) {
1203 debugging('error - parts of tree can be inserted only into parentable parts');
1204 return false;
1206 $parent->children[] = $something;
1207 return true;
1209 } else {
1210 debugging('error - can not add this element');
1211 return false;
1217 * Checks if the user has access to anything in this category.
1219 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1221 function check_access() {
1222 foreach ($this->children as $child) {
1223 if ($child->check_access()) {
1224 return true;
1227 return false;
1231 * Is this category hidden in admin tree block?
1233 * @return bool True if hidden
1235 function is_hidden() {
1236 return $this->hidden;
1240 class admin_root extends admin_category {
1242 * list of errors
1244 var $errors;
1247 * search query
1249 var $search;
1252 * full tree flag - true means all settings required, false onlypages required
1254 var $fulltree;
1257 function admin_root() {
1258 parent::admin_category('root', get_string('administration'), false);
1259 $this->errors = array();
1260 $this->search = '';
1261 $this->fulltree = true;
1266 * Links external PHP pages into the admin tree.
1268 * See detailed usage example at the top of this document (adminlib.php)
1270 * @author Vincenzo K. Marcovecchio
1271 * @package admin
1273 class admin_externalpage extends part_of_admin_tree {
1276 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1278 var $name;
1281 * @var string The displayed name for this external page. Usually obtained through get_string().
1283 var $visiblename;
1286 * @var string The external URL that we should link to when someone requests this external page.
1288 var $url;
1291 * @var string The role capability/permission a user must have to access this external page.
1293 var $req_capability;
1296 * @var object The context in which capability/permission should be checked, default is site context.
1298 var $context;
1301 * @var bool hidden in admin tree block.
1303 var $hidden;
1306 * visible path
1308 var $path;
1309 var $visiblepath;
1312 * Constructor for adding an external page into the admin tree.
1314 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1315 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1316 * @param string $url The external URL that we should link to when someone requests this external page.
1317 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1319 function admin_externalpage($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1320 $this->name = $name;
1321 $this->visiblename = $visiblename;
1322 $this->url = $url;
1323 if (is_array($req_capability)) {
1324 $this->req_capability = $req_capability;
1325 } else {
1326 $this->req_capability = array($req_capability);
1328 $this->hidden = $hidden;
1329 $this->context = $context;
1333 * Returns a reference to the part_of_admin_tree object with internal name $name.
1335 * @param string $name The internal name of the object we want.
1336 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1338 function &locate($name, $findpath=false) {
1339 if ($this->name == $name) {
1340 if ($findpath) {
1341 $this->visiblepath = array($this->visiblename);
1342 $this->path = array($this->name);
1344 return $this;
1345 } else {
1346 $return = NULL;
1347 return $return;
1351 function prune($name) {
1352 return false;
1356 * Search using query
1357 * @param strin query
1358 * @return mixed array-object structure of found settings and pages
1360 function search($query) {
1361 $textlib = textlib_get_instance();
1363 $found = false;
1364 if (strpos(strtolower($this->name), $query) !== false) {
1365 $found = true;
1366 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1367 $found = true;
1369 if ($found) {
1370 $result = new object();
1371 $result->page = $this;
1372 $result->settings = array();
1373 return array($this->name => $result);
1374 } else {
1375 return array();
1380 * Determines if the current user has access to this external page based on $this->req_capability.
1381 * @return bool True if user has access, false otherwise.
1383 function check_access() {
1384 if (!get_site()) {
1385 return true; // no access check before site is fully set up
1387 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1388 foreach($this->req_capability as $cap) {
1389 if (has_capability($cap, $context)) {
1390 return true;
1393 return false;
1397 * Is this external page hidden in admin tree block?
1399 * @return bool True if hidden
1401 function is_hidden() {
1402 return $this->hidden;
1408 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1410 * @author Vincenzo K. Marcovecchio
1411 * @package admin
1413 class admin_settingpage extends part_of_admin_tree {
1416 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1418 var $name;
1421 * @var string The displayed name for this external page. Usually obtained through get_string().
1423 var $visiblename;
1425 * @var mixed An array of admin_setting objects that are part of this setting page.
1427 var $settings;
1430 * @var string The role capability/permission a user must have to access this external page.
1432 var $req_capability;
1435 * @var object The context in which capability/permission should be checked, default is site context.
1437 var $context;
1440 * @var bool hidden in admin tree block.
1442 var $hidden;
1445 * paths
1447 var $path;
1448 var $visiblepath;
1450 // see admin_externalpage
1451 function admin_settingpage($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1452 $this->settings = new object();
1453 $this->name = $name;
1454 $this->visiblename = $visiblename;
1455 if (is_array($req_capability)) {
1456 $this->req_capability = $req_capability;
1457 } else {
1458 $this->req_capability = array($req_capability);
1460 $this->hidden = $hidden;
1461 $this->context = $context;
1464 // see admin_category
1465 function &locate($name, $findpath=false) {
1466 if ($this->name == $name) {
1467 if ($findpath) {
1468 $this->visiblepath = array($this->visiblename);
1469 $this->path = array($this->name);
1471 return $this;
1472 } else {
1473 $return = NULL;
1474 return $return;
1478 function search($query) {
1479 $found = array();
1481 foreach ($this->settings as $setting) {
1482 if ($setting->is_related($query)) {
1483 $found[] = $setting;
1487 if ($found) {
1488 $result = new object();
1489 $result->page = $this;
1490 $result->settings = $found;
1491 return array($this->name => $result);
1494 $textlib = textlib_get_instance();
1496 $found = false;
1497 if (strpos(strtolower($this->name), $query) !== false) {
1498 $found = true;
1499 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1500 $found = true;
1502 if ($found) {
1503 $result = new object();
1504 $result->page = $this;
1505 $result->settings = array();
1506 return array($this->name => $result);
1507 } else {
1508 return array();
1512 function prune($name) {
1513 return false;
1517 * 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
1518 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1519 * @param object $setting is the admin_setting object you want to add
1520 * @return true if successful, false if not
1522 function add($setting) {
1523 if (!is_a($setting, 'admin_setting')) {
1524 debugging('error - not a setting instance');
1525 return false;
1528 $this->settings->{$setting->name} = $setting;
1529 return true;
1532 // see admin_externalpage
1533 function check_access() {
1534 if (!get_site()) {
1535 return true; // no access check before site is fully set up
1537 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1538 foreach($this->req_capability as $cap) {
1539 if (has_capability($cap, $context)) {
1540 return true;
1543 return false;
1547 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1548 * returns a string of the html
1550 function output_html() {
1551 $adminroot =& admin_get_root();
1552 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
1553 foreach($this->settings as $setting) {
1554 $fullname = $setting->get_full_name();
1555 if (array_key_exists($fullname, $adminroot->errors)) {
1556 $data = $adminroot->errors[$fullname]->data;
1557 } else {
1558 $data = $setting->get_setting();
1559 if (is_null($data)) {
1560 $data = $setting->get_defaultsetting();
1563 $return .= $setting->output_html($data);
1565 $return .= '</fieldset>';
1566 return $return;
1570 * Is this settigns page hidden in admin tree block?
1572 * @return bool True if hidden
1574 function is_hidden() {
1575 return $this->hidden;
1582 * Admin settings class. Only exists on setting pages.
1583 * Read & write happens at this level; no authentication.
1585 class admin_setting {
1587 var $name;
1588 var $visiblename;
1589 var $description;
1590 var $defaultsetting;
1591 var $updatedcallback;
1592 var $plugin; // null means main config table
1595 * Constructor
1596 * @param $name string unique ascii name
1597 * @param $visiblename string localised name
1598 * @param strin $description localised long description
1599 * @param mixed $defaultsetting string or array depending on implementation
1601 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1602 $this->name = $name;
1603 $this->visiblename = $visiblename;
1604 $this->description = $description;
1605 $this->defaultsetting = $defaultsetting;
1608 function get_full_name() {
1609 return 's_'.$this->plugin.'_'.$this->name;
1612 function get_id() {
1613 return 'id_s_'.$this->plugin.'_'.$this->name;
1616 function config_read($name) {
1617 global $CFG;
1618 if ($this->plugin === 'backup') {
1619 require_once($CFG->dirroot.'/backup/lib.php');
1620 $backupconfig = backup_get_config();
1621 if (isset($backupconfig->$name)) {
1622 return $backupconfig->$name;
1623 } else {
1624 return NULL;
1627 } else if (!empty($this->plugin)) {
1628 $value = get_config($this->plugin, $name);
1629 return $value === false ? NULL : $value;
1631 } else {
1632 if (isset($CFG->$name)) {
1633 return $CFG->$name;
1634 } else {
1635 return NULL;
1640 function config_write($name, $value) {
1641 global $CFG;
1642 if ($this->plugin === 'backup') {
1643 require_once($CFG->dirroot.'/backup/lib.php');
1644 return (boolean)backup_set_config($name, $value);
1645 } else {
1646 return (boolean)set_config($name, $value, $this->plugin);
1651 * Returns current value of this setting
1652 * @return mixed array or string depending on instance, NULL means not set yet
1654 function get_setting() {
1655 // has to be overridden
1656 return NULL;
1660 * Returns default setting if exists
1661 * @return mixed array or string depending on instance; NULL means no default, user must supply
1663 function get_defaultsetting() {
1664 return $this->defaultsetting;
1668 * Store new setting
1669 * @param mixed string or array, must not be NULL
1670 * @return '' if ok, string error message otherwise
1672 function write_setting($data) {
1673 // should be overridden
1674 return '';
1678 * Return part of form with setting
1679 * @param mixed data array or string depending on setting
1680 * @return string
1682 function output_html($data, $query='') {
1683 // should be overridden
1684 return;
1688 * function called if setting updated - cleanup, cache reset, etc.
1690 function set_updatedcallback($functionname) {
1691 $this->updatedcallback = $functionname;
1695 * Is setting related to query text - used when searching
1696 * @param string $query
1697 * @return bool
1699 function is_related($query) {
1700 if (strpos(strtolower($this->name), $query) !== false) {
1701 return true;
1703 $textlib = textlib_get_instance();
1704 if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1705 return true;
1707 if (strpos($textlib->strtolower($this->description), $query) !== false) {
1708 return true;
1710 $current = $this->get_setting();
1711 if (!is_null($current)) {
1712 if (is_string($current)) {
1713 if (strpos($textlib->strtolower($current), $query) !== false) {
1714 return true;
1718 $default = $this->get_defaultsetting();
1719 if (!is_null($default)) {
1720 if (is_string($default)) {
1721 if (strpos($textlib->strtolower($default), $query) !== false) {
1722 return true;
1726 return false;
1731 * No setting - just heading and text.
1733 class admin_setting_heading extends admin_setting {
1735 * not a setting, just text
1736 * @param string $name of setting
1737 * @param string $heading heading
1738 * @param string $information text in box
1740 function admin_setting_heading($name, $heading, $information) {
1741 parent::admin_setting($name, $heading, $information, '');
1744 function get_setting() {
1745 return true;
1748 function get_defaultsetting() {
1749 return true;
1752 function write_setting($data) {
1753 // do not write any setting
1754 return '';
1757 function output_html($data, $query='') {
1758 $return = '';
1759 if ($this->visiblename != '') {
1760 $return .= print_heading('<a name="'.$this->name.'">'.highlightfast($query, $this->visiblename).'</a>', '', 3, 'main', true);
1762 if ($this->description != '') {
1763 $return .= print_box(highlight($query, $this->description), 'generalbox formsettingheading', '', true);
1765 return $return;
1770 * The most flexibly setting, user is typing text
1772 class admin_setting_configtext extends admin_setting {
1774 var $paramtype;
1775 var $size;
1778 * config text contructor
1779 * @param string $name of setting
1780 * @param string $visiblename localised
1781 * @param string $description long localised info
1782 * @param string $defaultsetting
1783 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
1784 * @param int $size default field size
1786 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
1787 $this->paramtype = $paramtype;
1788 if (!is_null($size)) {
1789 $this->size = $size;
1790 } else {
1791 $this->size = ($paramtype == PARAM_INT) ? 5 : 30;
1793 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1796 function get_setting() {
1797 return $this->config_read($this->name);
1800 function write_setting($data) {
1801 if ($this->paramtype === PARAM_INT and $data === '') {
1802 // do not complain if '' used instead of 0
1803 $data = 0;
1805 // $data is a string
1806 $validated = $this->validate($data);
1807 if ($validated !== true) {
1808 return $validated;
1810 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
1814 * Validate data before storage
1815 * @param string data
1816 * @return mixed true if ok string if error found
1818 function validate($data) {
1819 if (is_string($this->paramtype)) {
1820 if (preg_match($this->paramtype, $data)) {
1821 return true;
1822 } else {
1823 return get_string('validateerror', 'admin');
1826 } else if ($this->paramtype === PARAM_RAW) {
1827 return true;
1829 } else {
1830 $cleaned = stripslashes(clean_param(addslashes($data), $this->paramtype));
1831 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
1832 return true;
1833 } else {
1834 return get_string('validateerror', 'admin');
1839 function output_html($data, $query='') {
1840 $default = $this->get_defaultsetting();
1842 return format_admin_setting($this, $this->visiblename,
1843 '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>',
1844 $this->description, true, '', $default, $query);
1849 * General text area without html editor.
1851 class admin_setting_configtextarea extends admin_setting_configtext {
1852 var $rows;
1853 var $cols;
1855 function admin_setting_configtextarea($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
1856 $this->rows = $rows;
1857 $this->cols = $cols;
1858 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1861 function output_html($data, $query='') {
1862 $default = $this->get_defaultsetting();
1864 $defaultinfo = $default;
1865 if (!is_null($default) and $default !== '') {
1866 $defaultinfo = "\n".$default;
1869 return format_admin_setting($this, $this->visiblename,
1870 '<div class="form-textarea" ><textarea rows="'.$this->rows.'" cols="'.$this->cols.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'">'.s($data).'</textarea></div>',
1871 $this->description, true, '', $defaultinfo, $query);
1876 * Password field, allows unmasking of password
1878 class admin_setting_configpasswordunmask extends admin_setting_configtext {
1880 * Constructor
1881 * @param string $name of setting
1882 * @param string $visiblename localised
1883 * @param string $description long localised info
1884 * @param string $defaultsetting default password
1886 function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting) {
1887 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
1890 function output_html($data, $query='') {
1891 $id = $this->get_id();
1892 $unmask = get_string('unmaskpassword', 'form');
1893 $unmaskjs = '<script type="text/javascript">
1894 //<![CDATA[
1895 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>\');
1896 document.getElementById("'.$this->get_id().'").setAttribute("autocomplete", "off");
1897 //]]>
1898 </script>';
1899 return format_admin_setting($this, $this->visiblename,
1900 '<div class="form-password"><input type="password" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$unmaskjs.'</div>',
1901 $this->description, true, '', NULL, $query);
1906 * Path to directory
1908 class admin_setting_configfile extends admin_setting_configtext {
1910 * Constructor
1911 * @param string $name of setting
1912 * @param string $visiblename localised
1913 * @param string $description long localised info
1914 * @param string $defaultdirectory default directory location
1916 function admin_setting_configfile($name, $visiblename, $description, $defaultdirectory) {
1917 parent::admin_setting_configtext($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
1920 function output_html($data, $query='') {
1921 $default = $this->get_defaultsetting();
1923 if ($data) {
1924 if (file_exists($data)) {
1925 $executable = '<span class="pathok">&#x2714;</span>';
1926 } else {
1927 $executable = '<span class="patherror">&#x2718;</span>';
1929 } else {
1930 $executable = '';
1933 return format_admin_setting($this, $this->visiblename,
1934 '<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>',
1935 $this->description, true, '', $default, $query);
1940 * Path to executable file
1942 class admin_setting_configexecutable extends admin_setting_configfile {
1944 function output_html($data, $query='') {
1945 $default = $this->get_defaultsetting();
1947 if ($data) {
1948 if (file_exists($data) and is_executable($data)) {
1949 $executable = '<span class="pathok">&#x2714;</span>';
1950 } else {
1951 $executable = '<span class="patherror">&#x2718;</span>';
1953 } else {
1954 $executable = '';
1957 return format_admin_setting($this, $this->visiblename,
1958 '<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>',
1959 $this->description, true, '', $default, $query);
1964 * Path to directory
1966 class admin_setting_configdirectory extends admin_setting_configfile {
1967 function output_html($data, $query='') {
1968 $default = $this->get_defaultsetting();
1970 if ($data) {
1971 if (file_exists($data) and is_dir($data)) {
1972 $executable = '<span class="pathok">&#x2714;</span>';
1973 } else {
1974 $executable = '<span class="patherror">&#x2718;</span>';
1976 } else {
1977 $executable = '';
1980 return format_admin_setting($this, $this->visiblename,
1981 '<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>',
1982 $this->description, true, '', $default, $query);
1987 * Checkbox
1989 class admin_setting_configcheckbox extends admin_setting {
1990 var $yes;
1991 var $no;
1994 * Constructor
1995 * @param string $name of setting
1996 * @param string $visiblename localised
1997 * @param string $description long localised info
1998 * @param string $defaultsetting
1999 * @param string $yes value used when checked
2000 * @param string $no value used when not checked
2002 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
2003 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2004 $this->yes = (string)$yes;
2005 $this->no = (string)$no;
2008 function get_setting() {
2009 return $this->config_read($this->name);
2012 function write_setting($data) {
2013 if ((string)$data === $this->yes) { // convert to strings before comparison
2014 $data = $this->yes;
2015 } else {
2016 $data = $this->no;
2018 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2021 function output_html($data, $query='') {
2022 $default = $this->get_defaultsetting();
2024 if (!is_null($default)) {
2025 if ((string)$default === $this->yes) {
2026 $defaultinfo = get_string('checkboxyes', 'admin');
2027 } else {
2028 $defaultinfo = get_string('checkboxno', 'admin');
2030 } else {
2031 $defaultinfo = NULL;
2034 if ((string)$data === $this->yes) { // convert to strings before comparison
2035 $checked = 'checked="checked"';
2036 } else {
2037 $checked = '';
2040 return format_admin_setting($this, $this->visiblename,
2041 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
2042 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
2043 $this->description, true, '', $defaultinfo, $query);
2048 * Multiple checkboxes, each represents different value, stored in csv format
2050 class admin_setting_configmulticheckbox extends admin_setting {
2051 var $choices;
2054 * Constructor
2055 * @param string $name of setting
2056 * @param string $visiblename localised
2057 * @param string $description long localised info
2058 * @param array $defaultsetting array of selected
2059 * @param array $choices array of $value=>$label for each checkbox
2061 function admin_setting_configmulticheckbox($name, $visiblename, $description, $defaultsetting, $choices) {
2062 $this->choices = $choices;
2063 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2067 * This function may be used in ancestors for lazy loading of choices
2068 * @return true if loaded, false if error
2070 function load_choices() {
2072 if (is_array($this->choices)) {
2073 return true;
2075 .... load choices here
2077 return true;
2081 * Is setting related to query text - used when searching
2082 * @param string $query
2083 * @return bool
2085 function is_related($query) {
2086 if (!$this->load_choices() or empty($this->choices)) {
2087 return false;
2089 if (parent::is_related($query)) {
2090 return true;
2093 $textlib = textlib_get_instance();
2094 foreach ($this->choices as $desc) {
2095 if (strpos($textlib->strtolower($desc), $query) !== false) {
2096 return true;
2099 return false;
2102 function get_setting() {
2103 $result = $this->config_read($this->name);
2104 if (is_null($result)) {
2105 return NULL;
2107 if ($result === '') {
2108 return array();
2110 return explode(',', $result);
2113 function write_setting($data) {
2114 if (!is_array($data)) {
2115 return ''; // ignore it
2117 if (!$this->load_choices() or empty($this->choices)) {
2118 return '';
2120 unset($data['xxxxx']);
2121 $result = array();
2122 foreach ($data as $key => $value) {
2123 if ($value and array_key_exists($key, $this->choices)) {
2124 $result[] = $key;
2127 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
2130 function output_html($data, $query='') {
2131 if (!$this->load_choices() or empty($this->choices)) {
2132 return '';
2134 $default = $this->get_defaultsetting();
2135 if (is_null($default)) {
2136 $default = array();
2138 if (is_null($data)) {
2139 foreach ($default as $key=>$value) {
2140 if ($value) {
2141 $current[] = $value;
2146 $options = array();
2147 $defaults = array();
2148 foreach($this->choices as $key=>$description) {
2149 if (in_array($key, $data)) {
2150 $checked = 'checked="checked"';
2151 } else {
2152 $checked = '';
2154 if (!empty($default[$key])) {
2155 $defaults[] = $description;
2158 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
2159 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
2162 if (is_null($default)) {
2163 $defaultinfo = NULL;
2164 } else if (!empty($defaults)) {
2165 $defaultinfo = implode(', ', $defaults);
2166 } else {
2167 $defaultinfo = get_string('none');
2170 $return = '<div class="form-multicheckbox">';
2171 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2172 if ($options) {
2173 $return .= '<ul>';
2174 foreach ($options as $option) {
2175 $return .= '<li>'.$option.'</li>';
2177 $return .= '</ul>';
2179 $return .= '</div>';
2181 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2187 * Multiple checkboxes 2, value stored as string 00101011
2189 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
2190 function get_setting() {
2191 $result = $this->config_read($this->name);
2192 if (is_null($result)) {
2193 return NULL;
2195 if (!$this->load_choices()) {
2196 return NULL;
2198 $result = str_pad($result, count($this->choices), '0');
2199 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2200 $setting = array();
2201 foreach ($this->choices as $key=>$unused) {
2202 $value = array_shift($result);
2203 if ($value) {
2204 $setting[] = $key;
2207 return $setting;
2210 function write_setting($data) {
2211 if (!is_array($data)) {
2212 return ''; // ignore it
2214 if (!$this->load_choices() or empty($this->choices)) {
2215 return '';
2217 $result = '';
2218 foreach ($this->choices as $key=>$unused) {
2219 if (!empty($data[$key])) {
2220 $result .= '1';
2221 } else {
2222 $result .= '0';
2225 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
2230 * Select one value from list
2232 class admin_setting_configselect extends admin_setting {
2233 var $choices;
2236 * Constructor
2237 * @param string $name of setting
2238 * @param string $visiblename localised
2239 * @param string $description long localised info
2240 * @param string $defaultsetting
2241 * @param array $choices array of $value=>$label for each selection
2243 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
2244 $this->choices = $choices;
2245 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2249 * This function may be used in ancestors for lazy loading of choices
2250 * @return true if loaded, false if error
2252 function load_choices() {
2254 if (is_array($this->choices)) {
2255 return true;
2257 .... load choices here
2259 return true;
2262 function is_related($query) {
2263 if (parent::is_related($query)) {
2264 return true;
2266 if (!$this->load_choices()) {
2267 return false;
2269 $textlib = textlib_get_instance();
2270 foreach ($this->choices as $key=>$value) {
2271 if (strpos($textlib->strtolower($key), $query) !== false) {
2272 return true;
2274 if (strpos($textlib->strtolower($value), $query) !== false) {
2275 return true;
2278 return false;
2281 function get_setting() {
2282 return $this->config_read($this->name);
2285 function write_setting($data) {
2286 if (!$this->load_choices() or empty($this->choices)) {
2287 return '';
2289 if (!array_key_exists($data, $this->choices)) {
2290 return ''; // ignore it
2293 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2296 function output_html($data, $query='') {
2297 if (!$this->load_choices() or empty($this->choices)) {
2298 return '';
2300 $default = $this->get_defaultsetting();
2302 if (!is_null($default) and array_key_exists($default, $this->choices)) {
2303 $defaultinfo = $this->choices[$default];
2304 } else {
2305 $defaultinfo = NULL;
2308 $current = $this->get_setting();
2309 $warning = '';
2310 if (is_null($current)) {
2311 //first run
2312 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
2313 // no warning
2314 } else if (!array_key_exists($current, $this->choices)) {
2315 $warning = get_string('warningcurrentsetting', 'admin', s($current));
2316 if (!is_null($default) and $data==$current) {
2317 $data = $default; // use default instead of first value when showing the form
2321 $return = '<div class="form-select defaultsnext"><select id="'.$this->get_id().'" name="'.$this->get_full_name().'">';
2322 foreach ($this->choices as $key => $value) {
2323 // the string cast is needed because key may be integer - 0 is equal to most strings!
2324 $return .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
2326 $return .= '</select></div>';
2328 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
2334 * Select multiple items from list
2336 class admin_setting_configmultiselect extends admin_setting_configselect {
2338 * Constructor
2339 * @param string $name of setting
2340 * @param string $visiblename localised
2341 * @param string $description long localised info
2342 * @param array $defaultsetting array of selected items
2343 * @param array $choices array of $value=>$label for each list item
2345 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
2346 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
2349 function get_setting() {
2350 $result = $this->config_read($this->name);
2351 if (is_null($result)) {
2352 return NULL;
2354 if ($result === '') {
2355 return array();
2357 return explode(',', $result);
2360 function write_setting($data) {
2361 if (!is_array($data)) {
2362 return ''; //ignore it
2364 if (!$this->load_choices() or empty($this->choices)) {
2365 return '';
2368 unset($data['xxxxx']);
2370 $save = array();
2371 foreach ($data as $value) {
2372 if (!array_key_exists($value, $this->choices)) {
2373 continue; // ignore it
2375 $save[] = $value;
2378 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2382 * Is setting related to query text - used when searching
2383 * @param string $query
2384 * @return bool
2386 function is_related($query) {
2387 if (!$this->load_choices() or empty($this->choices)) {
2388 return false;
2390 if (parent::is_related($query)) {
2391 return true;
2394 $textlib = textlib_get_instance();
2395 foreach ($this->choices as $desc) {
2396 if (strpos($textlib->strtolower($desc), $query) !== false) {
2397 return true;
2400 return false;
2403 function output_html($data, $query='') {
2404 if (!$this->load_choices() or empty($this->choices)) {
2405 return '';
2407 $choices = $this->choices;
2408 $default = $this->get_defaultsetting();
2409 if (is_null($default)) {
2410 $default = array();
2412 if (is_null($data)) {
2413 $data = array();
2416 $defaults = array();
2417 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2418 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="10" multiple="multiple">';
2419 foreach ($this->choices as $key => $description) {
2420 if (in_array($key, $data)) {
2421 $selected = 'selected="selected"';
2422 } else {
2423 $selected = '';
2425 if (in_array($key, $default)) {
2426 $defaults[] = $description;
2429 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
2432 if (is_null($default)) {
2433 $defaultinfo = NULL;
2434 } if (!empty($defaults)) {
2435 $defaultinfo = implode(', ', $defaults);
2436 } else {
2437 $defaultinfo = get_string('none');
2440 $return .= '</select></div>';
2441 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
2446 * Time selector
2447 * this is a liiitle bit messy. we're using two selects, but we're returning
2448 * them as an array named after $name (so we only use $name2 internally for the setting)
2450 class admin_setting_configtime extends admin_setting {
2451 var $name2;
2454 * Constructor
2455 * @param string $hoursname setting for hours
2456 * @param string $minutesname setting for hours
2457 * @param string $visiblename localised
2458 * @param string $description long localised info
2459 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
2461 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
2462 $this->name2 = $minutesname;
2463 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
2466 function get_setting() {
2467 $result1 = $this->config_read($this->name);
2468 $result2 = $this->config_read($this->name2);
2469 if (is_null($result1) or is_null($result2)) {
2470 return NULL;
2473 return array('h' => $result1, 'm' => $result2);
2476 function write_setting($data) {
2477 if (!is_array($data)) {
2478 return '';
2481 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
2482 return ($result ? '' : get_string('errorsetting', 'admin'));
2485 function output_html($data, $query='') {
2486 $default = $this->get_defaultsetting();
2488 if (is_array($default)) {
2489 $defaultinfo = $default['h'].':'.$default['m'];
2490 } else {
2491 $defaultinfo = NULL;
2494 $return = '<div class="form-time defaultsnext">'.
2495 '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
2496 for ($i = 0; $i < 24; $i++) {
2497 $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2499 $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
2500 for ($i = 0; $i < 60; $i += 5) {
2501 $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2503 $return .= '</select></div>';
2504 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2510 * Special checkbox for calendar - resets SESSION vars.
2512 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
2513 function admin_setting_special_adminseesall() {
2514 parent::admin_setting_configcheckbox('calendar_adminseesall', get_string('adminseesall', 'admin'),
2515 get_string('helpadminseesall', 'admin'), '0');
2518 function write_setting($data) {
2519 global $SESSION;
2520 unset($SESSION->cal_courses_shown);
2521 return parent::write_setting($data);
2526 * Special select for settings that are altered in setup.php and can not be altered on the fly
2528 class admin_setting_special_selectsetup extends admin_setting_configselect {
2529 function get_setting() {
2530 // read directly from db!
2531 return get_config(NULL, $this->name);
2534 function write_setting($data) {
2535 global $CFG;
2536 // do not change active CFG setting!
2537 $current = $CFG->{$this->name};
2538 $result = parent::write_setting($data);
2539 $CFG->{$this->name} = $current;
2540 return $result;
2545 * Special select for frontpage - stores data in course table
2547 class admin_setting_sitesetselect extends admin_setting_configselect {
2548 function get_setting() {
2549 $site = get_site();
2550 return $site->{$this->name};
2553 function write_setting($data) {
2554 if (!in_array($data, array_keys($this->choices))) {
2555 return get_string('errorsetting', 'admin');
2557 $record = new stdClass();
2558 $record->id = SITEID;
2559 $temp = $this->name;
2560 $record->$temp = $data;
2561 $record->timemodified = time();
2562 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2567 * Special select - lists on the frontpage - hacky
2569 class admin_setting_courselist_frontpage extends admin_setting {
2570 var $choices;
2572 function admin_setting_courselist_frontpage($loggedin) {
2573 global $CFG;
2574 require_once($CFG->dirroot.'/course/lib.php');
2575 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
2576 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
2577 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
2578 $defaults = array(FRONTPAGECOURSELIST);
2579 parent::admin_setting($name, $visiblename, $description, $defaults);
2582 function load_choices() {
2583 if (is_array($this->choices)) {
2584 return true;
2586 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
2587 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
2588 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
2589 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
2590 'none' => get_string('none'));
2591 if ($this->name == 'frontpage' and count_records('course') > FRONTPAGECOURSELIMIT) {
2592 unset($this->choices[FRONTPAGECOURSELIST]);
2594 return true;
2596 function get_setting() {
2597 $result = $this->config_read($this->name);
2598 if (is_null($result)) {
2599 return NULL;
2601 if ($result === '') {
2602 return array();
2604 return explode(',', $result);
2607 function write_setting($data) {
2608 if (!is_array($data)) {
2609 return '';
2611 $this->load_choices();
2612 $save = array();
2613 foreach($data as $datum) {
2614 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
2615 continue;
2617 $save[$datum] = $datum; // no duplicates
2619 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2622 function output_html($data, $query='') {
2623 $this->load_choices();
2624 $currentsetting = array();
2625 foreach ($data as $key) {
2626 if ($key != 'none' and array_key_exists($key, $this->choices)) {
2627 $currentsetting[] = $key; // already selected first
2631 $return = '<div class="form-group">';
2632 for ($i = 0; $i < count($this->choices) - 1; $i++) {
2633 if (!array_key_exists($i, $currentsetting)) {
2634 $currentsetting[$i] = 'none'; //none
2636 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
2637 foreach ($this->choices as $key => $value) {
2638 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
2640 $return .= '</select>';
2641 if ($i !== count($this->choices) - 2) {
2642 $return .= '<br />';
2645 $return .= '</div>';
2647 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2652 * Special checkbox for frontpage - stores data in course table
2654 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
2655 function get_setting() {
2656 $site = get_site();
2657 return $site->{$this->name};
2660 function write_setting($data) {
2661 $record = new object();
2662 $record->id = SITEID;
2663 $record->{$this->name} = ($data == '1' ? 1 : 0);
2664 $record->timemodified = time();
2665 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2670 * Special text for frontpage - stores data in course table.
2671 * Empty string means not set here. Manual setting is required.
2673 class admin_setting_sitesettext extends admin_setting_configtext {
2674 function get_setting() {
2675 $site = get_site();
2676 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
2679 function validate($data) {
2680 $cleaned = stripslashes(clean_param(addslashes($data), PARAM_MULTILANG));
2681 if ($cleaned === '') {
2682 return get_string('required');
2684 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
2685 return true;
2686 } else {
2687 return get_string('validateerror', 'admin');
2691 function write_setting($data) {
2692 $data = trim($data);
2693 $validated = $this->validate($data);
2694 if ($validated !== true) {
2695 return $validated;
2698 $record = new object();
2699 $record->id = SITEID;
2700 $record->{$this->name} = addslashes($data);
2701 $record->timemodified = time();
2702 return (update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
2707 * Special text editor for site description.
2709 class admin_setting_special_frontpagedesc extends admin_setting {
2710 function admin_setting_special_frontpagedesc() {
2711 parent::admin_setting('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
2714 function get_setting() {
2715 $site = get_site();
2716 return $site->{$this->name};
2719 function write_setting($data) {
2720 $record = new object();
2721 $record->id = SITEID;
2722 $record->{$this->name} = addslashes($data);
2723 $record->timemodified = time();
2724 return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2727 function output_html($data, $query='') {
2728 global $CFG;
2730 $CFG->adminusehtmleditor = can_use_html_editor();
2731 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true).'</div>';
2733 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2737 class admin_setting_special_editorfontlist extends admin_setting {
2739 var $items;
2741 function admin_setting_special_editorfontlist() {
2742 global $CFG;
2743 $name = 'editorfontlist';
2744 $visiblename = get_string('editorfontlist', 'admin');
2745 $description = get_string('configeditorfontlist', 'admin');
2746 $defaults = array('k0' => 'Trebuchet',
2747 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
2748 'k1' => 'Arial',
2749 'v1' => 'arial,helvetica,sans-serif',
2750 'k2' => 'Courier New',
2751 'v2' => 'courier new,courier,monospace',
2752 'k3' => 'Georgia',
2753 'v3' => 'georgia,times new roman,times,serif',
2754 'k4' => 'Tahoma',
2755 'v4' => 'tahoma,arial,helvetica,sans-serif',
2756 'k5' => 'Times New Roman',
2757 'v5' => 'times new roman,times,serif',
2758 'k6' => 'Verdana',
2759 'v6' => 'verdana,arial,helvetica,sans-serif',
2760 'k7' => 'Impact',
2761 'v7' => 'impact',
2762 'k8' => 'Wingdings',
2763 'v8' => 'wingdings');
2764 parent::admin_setting($name, $visiblename, $description, $defaults);
2767 function get_setting() {
2768 global $CFG;
2769 $result = $this->config_read($this->name);
2770 if (is_null($result)) {
2771 return NULL;
2773 $i = 0;
2774 $currentsetting = array();
2775 $items = explode(';', $result);
2776 foreach ($items as $item) {
2777 $item = explode(':', $item);
2778 $currentsetting['k'.$i] = $item[0];
2779 $currentsetting['v'.$i] = $item[1];
2780 $i++;
2782 return $currentsetting;
2785 function write_setting($data) {
2787 // there miiight be an easier way to do this :)
2788 // if this is changed, make sure the $defaults array above is modified so that this
2789 // function processes it correctly
2791 $keys = array();
2792 $values = array();
2794 foreach ($data as $key => $value) {
2795 if (substr($key,0,1) == 'k') {
2796 $keys[substr($key,1)] = $value;
2797 } elseif (substr($key,0,1) == 'v') {
2798 $values[substr($key,1)] = $value;
2802 $result = array();
2803 for ($i = 0; $i < count($keys); $i++) {
2804 if (($keys[$i] !== '') && ($values[$i] !== '')) {
2805 $result[] = clean_param($keys[$i],PARAM_NOTAGS).':'.clean_param($values[$i], PARAM_NOTAGS);
2809 return ($this->config_write($this->name, implode(';', $result)) ? '' : get_string('errorsetting', 'admin'));
2812 function output_html($data, $query='') {
2813 $fullname = $this->get_full_name();
2814 $return = '<div class="form-group">';
2815 for ($i = 0; $i < count($data) / 2; $i++) {
2816 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
2817 $return .= '&nbsp;&nbsp;';
2818 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
2820 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
2821 $return .= '&nbsp;&nbsp;';
2822 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2823 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
2824 $return .= '&nbsp;&nbsp;';
2825 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
2826 $return .= '</div>';
2828 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2833 class admin_setting_emoticons extends admin_setting {
2835 var $items;
2837 function admin_setting_emoticons() {
2838 global $CFG;
2839 $name = 'emoticons';
2840 $visiblename = get_string('emoticons', 'admin');
2841 $description = get_string('configemoticons', 'admin');
2842 $defaults = array('k0' => ':-)',
2843 'v0' => 'smiley',
2844 'k1' => ':)',
2845 'v1' => 'smiley',
2846 'k2' => ':-D',
2847 'v2' => 'biggrin',
2848 'k3' => ';-)',
2849 'v3' => 'wink',
2850 'k4' => ':-/',
2851 'v4' => 'mixed',
2852 'k5' => 'V-.',
2853 'v5' => 'thoughtful',
2854 'k6' => ':-P',
2855 'v6' => 'tongueout',
2856 'k7' => 'B-)',
2857 'v7' => 'cool',
2858 'k8' => '^-)',
2859 'v8' => 'approve',
2860 'k9' => '8-)',
2861 'v9' => 'wideeyes',
2862 'k10' => ':o)',
2863 'v10' => 'clown',
2864 'k11' => ':-(',
2865 'v11' => 'sad',
2866 'k12' => ':(',
2867 'v12' => 'sad',
2868 'k13' => '8-.',
2869 'v13' => 'shy',
2870 'k14' => ':-I',
2871 'v14' => 'blush',
2872 'k15' => ':-X',
2873 'v15' => 'kiss',
2874 'k16' => '8-o',
2875 'v16' => 'surprise',
2876 'k17' => 'P-|',
2877 'v17' => 'blackeye',
2878 'k18' => '8-[',
2879 'v18' => 'angry',
2880 'k19' => 'xx-P',
2881 'v19' => 'dead',
2882 'k20' => '|-.',
2883 'v20' => 'sleepy',
2884 'k21' => '}-]',
2885 'v21' => 'evil',
2886 'k22' => '(h)',
2887 'v22' => 'heart',
2888 'k23' => '(heart)',
2889 'v23' => 'heart',
2890 'k24' => '(y)',
2891 'v24' => 'yes',
2892 'k25' => '(n)',
2893 'v25' => 'no',
2894 'k26' => '(martin)',
2895 'v26' => 'martin',
2896 'k27' => '( )',
2897 'v27' => 'egg');
2898 parent::admin_setting($name, $visiblename, $description, $defaults);
2901 function get_setting() {
2902 global $CFG;
2903 $result = $this->config_read($this->name);
2904 if (is_null($result)) {
2905 return NULL;
2907 $i = 0;
2908 $currentsetting = array();
2909 $items = explode('{;}', $result);
2910 foreach ($items as $item) {
2911 $item = explode('{:}', $item);
2912 $currentsetting['k'.$i] = $item[0];
2913 $currentsetting['v'.$i] = $item[1];
2914 $i++;
2916 return $currentsetting;
2919 function write_setting($data) {
2921 // there miiight be an easier way to do this :)
2922 // if this is changed, make sure the $defaults array above is modified so that this
2923 // function processes it correctly
2925 $keys = array();
2926 $values = array();
2928 foreach ($data as $key => $value) {
2929 if (substr($key,0,1) == 'k') {
2930 $keys[substr($key,1)] = $value;
2931 } elseif (substr($key,0,1) == 'v') {
2932 $values[substr($key,1)] = $value;
2936 $result = array();
2937 for ($i = 0; $i < count($keys); $i++) {
2938 if (($keys[$i] !== '') && ($values[$i] !== '')) {
2939 $result[] = clean_param($keys[$i],PARAM_NOTAGS).'{:}'.clean_param($values[$i], PARAM_NOTAGS);
2943 return ($this->config_write($this->name, implode('{;}', $result)) ? '' : get_string('errorsetting', 'admin').$this->visiblename.'<br />');
2946 function output_html($data, $query='') {
2947 $fullname = $this->get_full_name();
2948 $return = '<div class="form-group">';
2949 for ($i = 0; $i < count($data) / 2; $i++) {
2950 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
2951 $return .= '&nbsp;&nbsp;';
2952 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
2954 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
2955 $return .= '&nbsp;&nbsp;';
2956 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2957 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
2958 $return .= '&nbsp;&nbsp;';
2959 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
2960 $return .= '</div>';
2962 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2968 * Setting for spellchecker language selection.
2970 class admin_setting_special_editordictionary extends admin_setting_configselect {
2972 function admin_setting_special_editordictionary() {
2973 $name = 'editordictionary';
2974 $visiblename = get_string('editordictionary','admin');
2975 $description = get_string('configeditordictionary', 'admin');
2976 parent::admin_setting_configselect($name, $visiblename, $description, '', NULL);
2979 function load_choices() {
2980 // function borrowed from the old moodle/admin/editor.php, slightly modified
2981 // Get all installed dictionaries in the system
2982 if (is_array($this->choices)) {
2983 return true;
2986 $this->choices = array();
2988 global $CFG;
2990 clearstatcache();
2992 // If aspellpath isn't set don't even bother ;-)
2993 if (empty($CFG->aspellpath)) {
2994 $this->choices['error'] = 'Empty aspell path!';
2995 return true;
2998 // Do we have access to popen function?
2999 if (!function_exists('popen')) {
3000 $this->choices['error'] = 'Popen function disabled!';
3001 return true;
3004 $cmd = $CFG->aspellpath;
3005 $output = '';
3006 $dictionaries = array();
3008 if(!($handle = @popen(escapeshellarg($cmd).' dump dicts', 'r'))) {
3009 $this->choices['error'] = 'Couldn\'t create handle!';
3012 while(!feof($handle)) {
3013 $output .= fread($handle, 1024);
3015 @pclose($handle);
3017 $dictionaries = explode(chr(10), $output);
3018 foreach ($dictionaries as $dict) {
3019 if (empty($dict)) {
3020 continue;
3022 $this->choices[$dict] = $dict;
3025 if (empty($this->choices)) {
3026 $this->choices['error'] = 'Error! Check your aspell installation!';
3028 return true;
3033 class admin_setting_special_editorhidebuttons extends admin_setting {
3034 var $items;
3036 function admin_setting_special_editorhidebuttons() {
3037 parent::admin_setting('editorhidebuttons', get_string('editorhidebuttons', 'admin'),
3038 get_string('confeditorhidebuttons', 'admin'), array());
3039 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
3040 $this->items = array('fontname' => '',
3041 'fontsize' => '',
3042 'formatblock' => '',
3043 'bold' => 'ed_format_bold.gif',
3044 'italic' => 'ed_format_italic.gif',
3045 'underline' => 'ed_format_underline.gif',
3046 'strikethrough' => 'ed_format_strike.gif',
3047 'subscript' => 'ed_format_sub.gif',
3048 'superscript' => 'ed_format_sup.gif',
3049 'copy' => 'ed_copy.gif',
3050 'cut' => 'ed_cut.gif',
3051 'paste' => 'ed_paste.gif',
3052 'clean' => 'ed_wordclean.gif',
3053 'undo' => 'ed_undo.gif',
3054 'redo' => 'ed_redo.gif',
3055 'justifyleft' => 'ed_align_left.gif',
3056 'justifycenter' => 'ed_align_center.gif',
3057 'justifyright' => 'ed_align_right.gif',
3058 'justifyfull' => 'ed_align_justify.gif',
3059 'lefttoright' => 'ed_left_to_right.gif',
3060 'righttoleft' => 'ed_right_to_left.gif',
3061 'insertorderedlist' => 'ed_list_num.gif',
3062 'insertunorderedlist' => 'ed_list_bullet.gif',
3063 'outdent' => 'ed_indent_less.gif',
3064 'indent' => 'ed_indent_more.gif',
3065 'forecolor' => 'ed_color_fg.gif',
3066 'hilitecolor' => 'ed_color_bg.gif',
3067 'inserthorizontalrule' => 'ed_hr.gif',
3068 'createanchor' => 'ed_anchor.gif',
3069 'createlink' => 'ed_link.gif',
3070 'unlink' => 'ed_unlink.gif',
3071 'insertimage' => 'ed_image.gif',
3072 'inserttable' => 'insert_table.gif',
3073 'insertsmile' => 'em.icon.smile.gif',
3074 'insertchar' => 'icon_ins_char.gif',
3075 'spellcheck' => 'spell-check.gif',
3076 'htmlmode' => 'ed_html.gif',
3077 'popupeditor' => 'fullscreen_maximize.gif',
3078 'search_replace' => 'ed_replace.gif');
3081 function get_setting() {
3082 $result = $this->config_read($this->name);
3083 if (is_null($result)) {
3084 return NULL;
3086 if ($result === '') {
3087 return array();
3089 return explode(' ', $result);
3092 function write_setting($data) {
3093 if (!is_array($data)) {
3094 return ''; // ignore it
3096 unset($data['xxxxx']);
3097 $result = array();
3099 foreach ($data as $key => $value) {
3100 if (!isset($this->items[$key])) {
3101 return get_string('errorsetting', 'admin');
3103 if ($value == '1') {
3104 $result[] = $key;
3107 return ($this->config_write($this->name, implode(' ', $result)) ? '' : get_string('errorsetting', 'admin'));
3110 function output_html($data, $query='') {
3112 global $CFG;
3114 // checkboxes with input name="$this->name[$key]" value="1"
3115 // we do 15 fields per column
3117 $return = '<div class="form-group">';
3118 $return .= '<table><tr><td valign="top" align="right">';
3119 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3121 $count = 0;
3123 foreach($this->items as $key => $value) {
3124 if ($count % 15 == 0 and $count != 0) {
3125 $return .= '</td><td valign="top" align="right">';
3128 $return .= '<label for="'.$this->get_id().$key.'">';
3129 $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;';
3130 $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;';
3131 $return .= '</label>';
3132 $count++;
3133 if ($count % 15 != 0) {
3134 $return .= '<br /><br />';
3138 $return .= '</td></tr>';
3139 $return .= '</table>';
3140 $return .= '</div>';
3142 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3147 * Special setting for limiting of the list of available languages.
3149 class admin_setting_langlist extends admin_setting_configtext {
3150 function admin_setting_langlist() {
3151 parent::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
3154 function write_setting($data) {
3155 $return = parent::write_setting($data);
3156 get_list_of_languages(true);//refresh the list
3157 return $return;
3162 * Course category selection
3164 class admin_settings_coursecat_select extends admin_setting_configselect {
3165 function admin_settings_coursecat_select($name, $visiblename, $description, $defaultsetting) {
3166 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, NULL);
3169 function load_choices() {
3170 global $CFG;
3171 require_once($CFG->dirroot.'/course/lib.php');
3172 if (is_array($this->choices)) {
3173 return true;
3175 $this->choices = make_categories_options();
3176 return true;
3180 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
3181 function admin_setting_special_backupdays() {
3182 parent::admin_setting_configmulticheckbox2('backup_sche_weekdays', get_string('schedule'), get_string('backupschedulehelp'), array(), NULL);
3183 $this->plugin = 'backup';
3186 function load_choices() {
3187 if (is_array($this->choices)) {
3188 return true;
3190 $this->choices = array();
3191 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3192 foreach ($days as $day) {
3193 $this->choices[$day] = get_string($day, 'calendar');
3195 return true;
3200 * Special debug setting
3202 class admin_setting_special_debug extends admin_setting_configselect {
3203 function admin_setting_special_debug() {
3204 parent::admin_setting_configselect('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
3207 function load_choices() {
3208 if (is_array($this->choices)) {
3209 return true;
3211 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
3212 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
3213 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
3214 DEBUG_ALL => get_string('debugall', 'admin'),
3215 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
3216 return true;
3221 class admin_setting_special_calendar_weekend extends admin_setting {
3222 function admin_setting_special_calendar_weekend() {
3223 $name = 'calendar_weekend';
3224 $visiblename = get_string('calendar_weekend', 'admin');
3225 $description = get_string('helpweekenddays', 'admin');
3226 $default = array ('0', '6'); // Saturdays and Sundays
3227 parent::admin_setting($name, $visiblename, $description, $default);
3230 function get_setting() {
3231 $result = $this->config_read($this->name);
3232 if (is_null($result)) {
3233 return NULL;
3235 if ($result === '') {
3236 return array();
3238 $settings = array();
3239 for ($i=0; $i<7; $i++) {
3240 if ($result & (1 << $i)) {
3241 $settings[] = $i;
3244 return $settings;
3247 function write_setting($data) {
3248 if (!is_array($data)) {
3249 return '';
3251 unset($data['xxxxx']);
3252 $result = 0;
3253 foreach($data as $index) {
3254 $result |= 1 << $index;
3256 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
3259 function output_html($data, $query='') {
3260 // The order matters very much because of the implied numeric keys
3261 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3262 $return = '<table><thead><tr>';
3263 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3264 foreach($days as $index => $day) {
3265 $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>';
3267 $return .= '</tr></thead><tbody><tr>';
3268 foreach($days as $index => $day) {
3269 $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>';
3271 $return .= '</tr></tbody></table>';
3273 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3280 * Graded roles in gradebook
3282 class admin_setting_special_gradebookroles extends admin_setting_configmulticheckbox {
3283 function admin_setting_special_gradebookroles() {
3284 parent::admin_setting_configmulticheckbox('gradebookroles', get_string('gradebookroles', 'admin'),
3285 get_string('configgradebookroles', 'admin'), NULL, NULL);
3288 function load_choices() {
3289 global $CFG;
3290 if (empty($CFG->rolesactive)) {
3291 return false;
3293 if (is_array($this->choices)) {
3294 return true;
3296 if ($roles = get_records('role')) {
3297 $this->choices = array();
3298 foreach($roles as $role) {
3299 $this->choices[$role->id] = format_string($role->name);
3301 return true;
3302 } else {
3303 return false;
3307 function get_defaultsetting() {
3308 global $CFG;
3309 if (empty($CFG->rolesactive)) {
3310 return NULL;
3312 $result = array();
3313 if ($studentroles = get_roles_with_capability('moodle/legacy:student', CAP_ALLOW)) {
3314 foreach ($studentroles as $studentrole) {
3315 $result[$studentrole->id] = '1';
3318 return $result;
3322 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
3323 function write_setting($data) {
3324 global $CFG;
3326 $oldvalue = $this->config_read($this->name);
3327 $return = parent::write_setting($data);
3328 $newvalue = $this->config_read($this->name);
3330 if ($oldvalue !== $newvalue) {
3331 // force full regrading
3332 set_field('grade_items', 'needsupdate', 1, 'needsupdate', 0);
3335 return $return;
3340 * Which roles to show on course decription page
3342 class admin_setting_special_coursemanager extends admin_setting_configmulticheckbox {
3343 function admin_setting_special_coursemanager() {
3344 parent::admin_setting_configmulticheckbox('coursemanager', get_string('coursemanager', 'admin'),
3345 get_string('configcoursemanager', 'admin'), NULL, NULL);
3348 function load_choices() {
3349 if (is_array($this->choices)) {
3350 return true;
3352 if ($roles = get_records('role','','','sortorder')) {
3353 $this->choices = array();
3354 foreach($roles as $role) {
3355 $this->choices[$role->id] = format_string($role->name);
3357 return true;
3359 return false;
3362 function get_defaultsetting() {
3363 global $CFG;
3364 if (empty($CFG->rolesactive)) {
3365 return NULL;
3367 $result = array();
3368 if ($teacherroles = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW)) {
3369 foreach ($teacherroles as $teacherrole) {
3370 $result[$teacherrole->id] = '1';
3373 return $result;
3378 * Primary grade export plugin - has state tracking.
3380 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
3381 function admin_setting_special_gradeexport() {
3382 parent::admin_setting_configmulticheckbox('gradeexport', get_string('gradeexport', 'admin'),
3383 get_string('configgradeexport', 'admin'), array(), NULL);
3386 function load_choices() {
3387 if (is_array($this->choices)) {
3388 return true;
3390 $this->choices = array();
3392 if ($plugins = get_list_of_plugins('grade/export')) {
3393 foreach($plugins as $plugin) {
3394 $this->choices[$plugin] = get_string('modulename', 'gradeexport_'.$plugin);
3397 return true;
3402 * Grade category settings
3404 class admin_setting_gradecat_combo extends admin_setting {
3406 var $choices;
3408 function admin_setting_gradecat_combo($name, $visiblename, $description, $defaultsetting, $choices) {
3409 $this->choices = $choices;
3410 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
3413 function get_setting() {
3414 global $CFG;
3416 $value = $this->config_read($this->name);
3417 $flag = $this->config_read($this->name.'_flag');
3419 if (is_null($value) or is_null($flag)) {
3420 return NULL;
3423 $flag = (int)$flag;
3424 $forced = (boolean)(1 & $flag); // first bit
3425 $adv = (boolean)(2 & $flag); // second bit
3427 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
3430 function write_setting($data) {
3431 global $CFG;
3433 $value = $data['value'];
3434 $forced = empty($data['forced']) ? 0 : 1;
3435 $adv = empty($data['adv']) ? 0 : 2;
3436 $flag = ($forced | $adv); //bitwise or
3438 if (!in_array($value, array_keys($this->choices))) {
3439 return 'Error setting ';
3442 $oldvalue = $this->config_read($this->name);
3443 $oldflag = (int)$this->config_read($this->name.'_flag');
3444 $oldforced = (1 & $oldflag); // first bit
3446 $result1 = $this->config_write($this->name, $value);
3447 $result2 = $this->config_write($this->name.'_flag', $flag);
3449 // force regrade if needed
3450 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
3451 require_once($CFG->libdir.'/gradelib.php');
3452 grade_category::updated_forced_settings();
3455 if ($result1 and $result2) {
3456 return '';
3457 } else {
3458 return get_string('errorsetting', 'admin');
3462 function output_html($data, $query='') {
3463 $value = $data['value'];
3464 $forced = !empty($data['forced']);
3465 $adv = !empty($data['adv']);
3467 $default = $this->get_defaultsetting();
3468 if (!is_null($default)) {
3469 $defaultinfo = array();
3470 if (isset($this->choices[$default['value']])) {
3471 $defaultinfo[] = $this->choices[$default['value']];
3473 if (!empty($default['forced'])) {
3474 $defaultinfo[] = get_string('force');
3476 if (!empty($default['adv'])) {
3477 $defaultinfo[] = get_string('advanced');
3479 $defaultinfo = implode(', ', $defaultinfo);
3481 } else {
3482 $defaultinfo = NULL;
3486 $return = '<div class="form-group">';
3487 $return .= '<select class="form-select" id="'.$this->get_id().'" name="'.$this->get_full_name().'[value]">';
3488 foreach ($this->choices as $key => $val) {
3489 // the string cast is needed because key may be integer - 0 is equal to most strings!
3490 $return .= '<option value="'.$key.'"'.((string)$key==$value ? ' selected="selected"' : '').'>'.$val.'</option>';
3492 $return .= '</select>';
3493 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'force" name="'.$this->get_full_name().'[forced]" value="1" '.($forced ? 'checked="checked"' : '').' />'
3494 .'<label for="'.$this->get_id().'force">'.get_string('force').'</label>';
3495 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'adv" name="'.$this->get_full_name().'[adv]" value="1" '.($adv ? 'checked="checked"' : '').' />'
3496 .'<label for="'.$this->get_id().'adv">'.get_string('advanced').'</label>';
3497 $return .= '</div>';
3499 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
3505 * Selection of grade report in user profiles
3507 class admin_setting_grade_profilereport extends admin_setting_configselect {
3508 function admin_setting_grade_profilereport() {
3509 parent::admin_setting_configselect('grade_profilereport', get_string('profilereport', 'grades'), get_string('configprofilereport', 'grades'), 'user', null);
3512 function load_choices() {
3513 if (is_array($this->choices)) {
3514 return true;
3516 $this->choices = array();
3518 global $CFG;
3519 require_once($CFG->libdir.'/gradelib.php');
3521 foreach (get_list_of_plugins('grade/report') as $plugin) {
3522 if (file_exists($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php')) {
3523 require_once($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php');
3524 $functionname = 'grade_report_'.$plugin.'_profilereport';
3525 if (function_exists($functionname)) {
3526 $this->choices[$plugin] = get_string('modulename', 'gradereport_'.$plugin, NULL, $CFG->dirroot.'/grade/report/'.$plugin.'/lang/');
3530 return true;
3535 * Special class for register auth selection
3537 class admin_setting_special_registerauth extends admin_setting_configselect {
3538 function admin_setting_special_registerauth() {
3539 parent::admin_setting_configselect('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null);
3542 function get_defaultsettings() {
3543 $this->load_choices();
3544 if (array_key_exists($this->defaultsetting, $this->choices)) {
3545 return $this->defaultsetting;
3546 } else {
3547 return '';
3551 function load_choices() {
3552 global $CFG;
3554 if (is_array($this->choices)) {
3555 return true;
3557 $this->choices = array();
3558 $this->choices[''] = get_string('disable');
3560 $authsenabled = get_enabled_auth_plugins(true);
3562 foreach ($authsenabled as $auth) {
3563 $authplugin = get_auth_plugin($auth);
3564 if (!$authplugin->can_signup()) {
3565 continue;
3567 // Get the auth title (from core or own auth lang files)
3568 $authtitle = $authplugin->get_title();
3569 $this->choices[$auth] = $authtitle;
3571 return true;
3576 * Module manage page
3578 class admin_page_managemods extends admin_externalpage {
3579 function admin_page_managemods() {
3580 global $CFG;
3581 parent::admin_externalpage('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
3584 function search($query) {
3585 if ($result = parent::search($query)) {
3586 return $result;
3589 $found = false;
3590 if ($modules = get_records('modules')) {
3591 $textlib = textlib_get_instance();
3592 foreach ($modules as $module) {
3593 if (strpos($module->name, $query) !== false) {
3594 $found = true;
3595 break;
3597 $strmodulename = get_string('modulename', $module->name);
3598 if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
3599 $found = true;
3600 break;
3604 if ($found) {
3605 $result = new object();
3606 $result->page = $this;
3607 $result->settings = array();
3608 return array($this->name => $result);
3609 } else {
3610 return array();
3616 * Enrolment manage page
3618 class admin_enrolment_page extends admin_externalpage {
3619 function admin_enrolment_page() {
3620 global $CFG;
3621 parent::admin_externalpage('enrolment', get_string('enrolments'), $CFG->wwwroot . '/'.$CFG->admin.'/enrol.php');
3624 function search($query) {
3625 if ($result = parent::search($query)) {
3626 return $result;
3629 $found = false;
3631 if ($modules = get_list_of_plugins('enrol')) {
3632 $textlib = textlib_get_instance();
3633 foreach ($modules as $plugin) {
3634 if (strpos($plugin, $query) !== false) {
3635 $found = true;
3636 break;
3638 $strmodulename = get_string('enrolname', "enrol_$plugin");
3639 if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
3640 $found = true;
3641 break;
3645 //ugly harcoded hacks
3646 if (strpos('sendcoursewelcomemessage', $query) !== false) {
3647 $found = true;
3648 } else if (strpos($textlib->strtolower(get_string('sendcoursewelcomemessage', 'admin')), $query) !== false) {
3649 $found = true;
3650 } else if (strpos($textlib->strtolower(get_string('configsendcoursewelcomemessage', 'admin')), $query) !== false) {
3651 $found = true;
3652 } else if (strpos($textlib->strtolower(get_string('configenrolmentplugins', 'admin')), $query) !== false) {
3653 $found = true;
3655 if ($found) {
3656 $result = new object();
3657 $result->page = $this;
3658 $result->settings = array();
3659 return array($this->name => $result);
3660 } else {
3661 return array();
3667 * Blocks manage page
3669 class admin_page_manageblocks extends admin_externalpage {
3670 function admin_page_manageblocks() {
3671 global $CFG;
3672 parent::admin_externalpage('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
3675 function search($query) {
3676 global $CFG;
3677 if ($result = parent::search($query)) {
3678 return $result;
3681 $found = false;
3682 if (!empty($CFG->blocks_version) and $blocks = get_records('block')) {
3683 $textlib = textlib_get_instance();
3684 foreach ($blocks as $block) {
3685 if (strpos($block->name, $query) !== false) {
3686 $found = true;
3687 break;
3689 $strblockname = get_string('blockname', 'block_'.$block->name);
3690 if (strpos($textlib->strtolower($strblockname), $query) !== false) {
3691 $found = true;
3692 break;
3696 if ($found) {
3697 $result = new object();
3698 $result->page = $this;
3699 $result->settings = array();
3700 return array($this->name => $result);
3701 } else {
3702 return array();
3708 * Special class for authentication administration.
3710 class admin_setting_manageauths extends admin_setting {
3711 function admin_setting_manageauths() {
3712 parent::admin_setting('authsui', get_string('authsettings', 'admin'), '', '');
3715 function get_setting() {
3716 return true;
3719 function get_defaultsetting() {
3720 return true;
3723 function write_setting($data) {
3724 // do not write any setting
3725 return '';
3728 function is_related($query) {
3729 if (parent::is_related($query)) {
3730 return true;
3733 $textlib = textlib_get_instance();
3734 $authsavailable = get_list_of_plugins('auth');
3735 foreach ($authsavailable as $auth) {
3736 if (strpos($auth, $query) !== false) {
3737 return true;
3739 $authplugin = get_auth_plugin($auth);
3740 $authtitle = $authplugin->get_title();
3741 if (strpos($textlib->strtolower($authtitle), $query) !== false) {
3742 return true;
3745 return false;
3748 function output_html($data, $query='') {
3749 global $CFG;
3752 // display strings
3753 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
3754 'settings', 'edit', 'name', 'enable', 'disable',
3755 'up', 'down', 'none'));
3756 $txt->updown = "$txt->up/$txt->down";
3758 $authsavailable = get_list_of_plugins('auth');
3759 get_enabled_auth_plugins(true); // fix the list of enabled auths
3760 if (empty($CFG->auth)) {
3761 $authsenabled = array();
3762 } else {
3763 $authsenabled = explode(',', $CFG->auth);
3766 // construct the display array, with enabled auth plugins at the top, in order
3767 $displayauths = array();
3768 $registrationauths = array();
3769 $registrationauths[''] = $txt->disable;
3770 foreach ($authsenabled as $auth) {
3771 $authplugin = get_auth_plugin($auth);
3772 /// Get the auth title (from core or own auth lang files)
3773 $authtitle = $authplugin->get_title();
3774 /// Apply titles
3775 $displayauths[$auth] = $authtitle;
3776 if ($authplugin->can_signup()) {
3777 $registrationauths[$auth] = $authtitle;
3781 foreach ($authsavailable as $auth) {
3782 if (array_key_exists($auth, $displayauths)) {
3783 continue; //already in the list
3785 $authplugin = get_auth_plugin($auth);
3786 /// Get the auth title (from core or own auth lang files)
3787 $authtitle = $authplugin->get_title();
3788 /// Apply titles
3789 $displayauths[$auth] = $authtitle;
3790 if ($authplugin->can_signup()) {
3791 $registrationauths[$auth] = $authtitle;
3795 $return = print_heading(get_string('actauthhdr', 'auth'), '', 3, 'main', true);
3796 $return .= print_box_start('generalbox authsui', '', true);
3798 $table = new object();
3799 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings);
3800 $table->align = array('left', 'center', 'center', 'center');
3801 $table->width = '90%';
3802 $table->data = array();
3804 //add always enabled plugins first
3805 $displayname = "<span>".$displayauths['manual']."</span>";
3806 $settings = "<a href=\"auth_config.php?auth=manual\">{$txt->settings}</a>";
3807 //$settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
3808 $table->data[] = array($displayname, '', '', $settings);
3809 $displayname = "<span>".$displayauths['nologin']."</span>";
3810 $settings = "<a href=\"auth_config.php?auth=nologin\">{$txt->settings}</a>";
3811 $table->data[] = array($displayname, '', '', $settings);
3814 // iterate through auth plugins and add to the display table
3815 $updowncount = 1;
3816 $authcount = count($authsenabled);
3817 $url = "auth.php?sesskey=" . sesskey();
3818 foreach ($displayauths as $auth => $name) {
3819 if ($auth == 'manual' or $auth == 'nologin') {
3820 continue;
3822 // hide/show link
3823 if (in_array($auth, $authsenabled)) {
3824 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
3825 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"disable\" /></a>";
3826 // $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\"><input type=\"checkbox\" checked /></a>";
3827 $enabled = true;
3828 $displayname = "<span>$name</span>";
3830 else {
3831 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
3832 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"enable\" /></a>";
3833 // $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\"><input type=\"checkbox\" /></a>";
3834 $enabled = false;
3835 $displayname = "<span class=\"dimmed_text\">$name</span>";
3838 // up/down link (only if auth is enabled)
3839 $updown = '';
3840 if ($enabled) {
3841 if ($updowncount > 1) {
3842 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
3843 $updown .= "<img src=\"{$CFG->pixpath}/t/up.gif\" alt=\"up\" /></a>&nbsp;";
3845 else {
3846 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
3848 if ($updowncount < $authcount) {
3849 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
3850 $updown .= "<img src=\"{$CFG->pixpath}/t/down.gif\" alt=\"down\" /></a>";
3852 else {
3853 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />";
3855 ++ $updowncount;
3858 // settings link
3859 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
3860 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
3861 } else {
3862 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
3865 // add a row to the table
3866 $table->data[] =array($displayname, $hideshow, $updown, $settings);
3868 $return .= print_table($table, true);
3869 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
3870 $return .= print_box_end(true);
3871 return highlight($query, $return);
3875 * Special class for filter administration.
3877 class admin_setting_managefilters extends admin_setting {
3878 function admin_setting_managefilters() {
3879 parent::admin_setting('filtersui', get_string('filtersettings', 'admin'), '', '');
3882 function get_setting() {
3883 return true;
3886 function get_defaultsetting() {
3887 return true;
3890 function write_setting($data) {
3891 // do not write any setting
3892 return '';
3895 function is_related($query) {
3896 if (parent::is_related($query)) {
3897 return true;
3900 $textlib = textlib_get_instance();
3901 $filterlocations = array('mod','filter');
3902 foreach ($filterlocations as $filterlocation) {
3903 $plugins = get_list_of_plugins($filterlocation);
3904 foreach ($plugins as $plugin) {
3905 if (strpos($plugin, $query) !== false) {
3906 return true;
3908 $name = get_string('filtername', $plugin);
3909 if (strpos($textlib->strtolower($name), $query) !== false) {
3910 return true;
3914 return false;
3917 function output_html($data, $query='') {
3918 global $CFG;
3920 $strname = get_string('name');
3921 $strhide = get_string('disable');
3922 $strshow = get_string('enable');
3923 $strhideshow = "$strhide/$strshow";
3924 $strsettings = get_string('settings');
3925 $strup = get_string('up');
3926 $strdown = get_string('down');
3927 $strupdown = "$strup/$strdown";
3929 // get a list of possible filters (and translate name if possible)
3930 // note filters can be in the dedicated filters area OR in their
3931 // associated modules
3932 $installedfilters = array();
3933 $filtersettings_new = array();
3934 $filtersettings_old = array();
3935 $filterlocations = array('mod','filter');
3936 foreach ($filterlocations as $filterlocation) {
3937 $plugins = get_list_of_plugins($filterlocation);
3938 foreach ($plugins as $plugin) {
3939 $pluginpath = "$CFG->dirroot/$filterlocation/$plugin/filter.php";
3940 $settingspath_new = "$CFG->dirroot/$filterlocation/$plugin/filtersettings.php";
3941 $settingspath_old = "$CFG->dirroot/$filterlocation/$plugin/filterconfig.html";
3942 if (is_readable($pluginpath)) {
3943 $name = trim(get_string("filtername", $plugin));
3944 if (empty($name) or ($name == '[[filtername]]')) {
3945 $textlib = textlib_get_instance();
3946 $name = $textlib->strtotitle($plugin);
3948 $installedfilters["$filterlocation/$plugin"] = $name;
3949 if (is_readable($settingspath_new)) {
3950 $filtersettings_new[] = "$filterlocation/$plugin";
3951 } else if (is_readable($settingspath_old)) {
3952 $filtersettings_old[] = "$filterlocation/$plugin";
3958 // get all the currently selected filters
3959 if (!empty($CFG->textfilters)) {
3960 $oldactivefilters = explode(',', $CFG->textfilters);
3961 $oldactivefilters = array_unique($oldactivefilters);
3962 } else {
3963 $oldactivefilters = array();
3966 // take this opportunity to clean up filters
3967 $activefilters = array();
3968 foreach ($oldactivefilters as $oldactivefilter) {
3969 if (!empty($oldactivefilter) and array_key_exists($oldactivefilter, $installedfilters)) {
3970 $activefilters[] = $oldactivefilter;
3974 // construct the display array with installed filters
3975 // at the top in the right order
3976 $displayfilters = array();
3977 foreach ($activefilters as $activefilter) {
3978 $name = $installedfilters[$activefilter];
3979 $displayfilters[$activefilter] = $name;
3981 foreach ($installedfilters as $key => $filter) {
3982 if (!array_key_exists($key, $displayfilters)) {
3983 $displayfilters[$key] = $filter;
3987 $return = print_heading(get_string('actfilterhdr', 'filters'), '', 3, 'main', true);
3988 $return .= print_box_start('generalbox filtersui', '', true);
3990 $table = new object();
3991 $table->head = array($strname, $strhideshow, $strupdown, $strsettings);
3992 $table->align = array('left', 'center', 'center', 'center');
3993 $table->width = '90%';
3994 $table->data = array();
3996 $filtersurl = "$CFG->wwwroot/$CFG->admin/filters.php?sesskey=".sesskey();
3997 $imgurl = "$CFG->pixpath/t";
3999 // iterate through filters adding to display table
4000 $updowncount = 1;
4001 $activefilterscount = count($activefilters);
4002 foreach ($displayfilters as $path => $name) {
4003 $upath = urlencode($path);
4004 // get hide/show link
4005 if (in_array($path, $activefilters)) {
4006 $hideshow = "<a href=\"$filtersurl&amp;action=hide&amp;filterpath=$upath\">";
4007 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"$strhide\" /></a>";
4008 $hidden = false;
4009 $displayname = "<span>$name</span>";
4011 else {
4012 $hideshow = "<a href=\"$filtersurl&amp;action=show&amp;filterpath=$upath\">";
4013 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"$strshow\" /></a>";
4014 $hidden = true;
4015 $displayname = "<span class=\"dimmed_text\">$name</span>";
4018 // get up/down link (only if not hidden)
4019 $updown = '';
4020 if (!$hidden) {
4021 if ($updowncount>1) {
4022 $updown .= "<a href=\"$filtersurl&amp;action=up&amp;filterpath=$upath\">";
4023 $updown .= "<img src=\"$imgurl/up.gif\" alt=\"$strup\" /></a>&nbsp;";
4025 else {
4026 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
4028 if ($updowncount<$activefilterscount) {
4029 $updown .= "<a href=\"$filtersurl&amp;action=down&amp;filterpath=$upath\">";
4030 $updown .= "<img src=\"$imgurl/down.gif\" alt=\"$strdown\" /></a>";
4032 else {
4033 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />";
4035 ++$updowncount;
4038 // settings link (if defined)
4039 $settings = '';
4040 if (in_array($path, $filtersettings_new)) {
4041 $settings = "<a href=\"settings.php?section=filtersetting".str_replace('/', '',$path)."\">$strsettings</a>";
4042 } else if (in_array($path, $filtersettings_old)) {
4043 $settings = "<a href=\"filter.php?filter=".urlencode($path)."\">$strsettings</a>";
4046 // write data into the table object
4047 $table->data[] = array($displayname, $hideshow, $updown, $settings);
4049 $return .= print_table($table, true);
4050 $return .= get_string('tablenosave', 'filters');
4051 $return .= print_box_end(true);
4052 return highlight($query, $return);
4057 * Initialise admin page - this function does require login and permission
4058 * checks specified in page definition.
4059 * This function must be called on each admin page before other code.
4060 * @param string $section name of page
4062 function admin_externalpage_setup($section) {
4064 global $CFG, $PAGE, $USER;
4065 require_once($CFG->libdir.'/blocklib.php');
4066 require_once($CFG->dirroot.'/'.$CFG->admin.'/pagelib.php');
4068 if ($site = get_site()) {
4069 require_login();
4070 } else {
4071 redirect($CFG->wwwroot.'/'.$CFG->admin.'/index.php');
4072 die;
4075 $adminroot =& admin_get_root(false, false); // settings not required for external pages
4076 $extpage =& $adminroot->locate($section);
4078 if (empty($extpage) or !is_a($extpage, 'admin_externalpage')) {
4079 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
4080 die;
4083 // this eliminates our need to authenticate on the actual pages
4084 if (!($extpage->check_access())) {
4085 print_error('accessdenied', 'admin');
4086 die;
4089 page_map_class(PAGE_ADMIN, 'page_admin');
4090 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
4091 $PAGE->init_extra($section); // hack alert!
4093 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
4095 if (!isset($USER->adminediting)) {
4096 $USER->adminediting = false;
4099 if ($PAGE->user_allowed_editing()) {
4100 if ($adminediting == 1) {
4101 $USER->adminediting = true;
4102 } elseif ($adminediting == 0) {
4103 $USER->adminediting = false;
4109 * Print header for admin page
4110 * @param string $focus focus element
4112 function admin_externalpage_print_header($focus='') {
4114 if (!is_string($focus)) {
4115 $focus = ''; // BC compatibility, there used to be adminroot parameter
4118 global $CFG, $PAGE, $SITE, $THEME;
4120 define('ADMIN_EXT_HEADER_PRINTED', 'true');
4122 if (!empty($SITE->fullname)) {
4123 $pageblocks = blocks_setup($PAGE);
4125 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
4126 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
4127 BLOCK_L_MAX_WIDTH);
4128 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
4129 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
4130 BLOCK_R_MAX_WIDTH);
4132 $PAGE->print_header('', $focus);
4133 echo '<table id="layout-table" summary=""><tr>';
4135 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
4136 foreach ($lt as $column) {
4137 $lt1[] = $column;
4138 if ($column == 'middle') break;
4140 foreach ($lt1 as $column) {
4141 switch ($column) {
4142 case 'left':
4143 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
4144 print_container_start();
4145 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
4146 print_container_end();
4147 echo '</td>';
4148 break;
4150 case 'middle':
4151 echo '<td id="middle-column">';
4152 print_container_start(true);
4153 $THEME->open_header_containers++; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
4154 break;
4156 case 'right':
4157 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
4158 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
4159 print_container_start();
4160 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
4161 print_container_end();
4162 echo '</td>';
4164 break;
4167 } else {
4168 print_header();
4173 * Print footer on admin page - please use normal print_footer() instead
4175 function admin_externalpage_print_footer() {
4177 global $CFG, $PAGE, $SITE, $THEME;
4179 define('ADMIN_EXT_FOOTER_PRINTED', 'true');
4181 if (!empty($SITE->fullname)) {
4182 $pageblocks = blocks_setup($PAGE);
4183 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
4184 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
4185 BLOCK_L_MAX_WIDTH);
4186 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
4187 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
4188 BLOCK_R_MAX_WIDTH);
4190 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
4191 foreach ($lt as $column) {
4192 if ($column != 'middle') {
4193 array_shift($lt);
4194 } else if ($column == 'middle') {
4195 break;
4198 foreach ($lt as $column) {
4199 switch ($column) {
4200 case 'left':
4201 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
4202 print_container_start();
4203 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
4204 print_container_end();
4205 echo '</td>';
4206 break;
4208 case 'middle':
4209 print_container_end();
4210 $THEME->open_header_containers--; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
4211 echo '</td>';
4212 break;
4214 case 'right':
4215 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
4216 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
4217 print_container_start();
4218 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
4219 print_container_end();
4220 echo '</td>';
4222 break;
4225 echo '</tr></table>';
4227 print_footer();
4231 * Returns the reference to admin tree root
4232 * @return reference
4234 function &admin_get_root($reload=false, $requirefulltree=true) {
4235 global $CFG;
4237 static $ADMIN = NULL;
4239 if (!is_null($ADMIN)) {
4240 $olderrors = $ADMIN->errors;
4241 $oldsearch = $ADMIN->search;
4242 $oldfulltree = $ADMIN->fulltree;
4243 } else {
4244 $olderrors = array();
4245 $oldsearch = '';
4246 $oldfulltree = false;
4249 if ($reload or ($requirefulltree and !$oldfulltree)) {
4250 $ADMIN = NULL;
4253 if (is_null($ADMIN)) {
4254 // start the admin tree!
4255 $ADMIN = new admin_root();
4256 // array of error messages and search query
4257 $ADMIN->errors = $olderrors;
4258 $ADMIN->search = $oldsearch;
4259 if ($requirefulltree) {
4260 $ADMIN->fulltree = true;
4261 } else {
4262 $ADMIN->fulltree = $oldfulltree;
4265 // we process this file first to create categories first and in correct order
4266 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
4268 // now we process all other files in admin/settings to build the admin tree
4269 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
4270 if ($file != $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
4271 include($file);
4274 if (file_exists($CFG->dirroot.'/local/settings.php')) {
4275 include_once($CFG->dirroot.'/local/settings.php');
4279 return $ADMIN;
4282 /// settings utility functions
4285 * This function applies default settings.
4286 * @param object $node, NULL means complete tree
4287 * @param bool $uncoditional if true overrides all values with defaults
4288 * @return void
4290 function admin_apply_default_settings($node=NULL, $unconditional=true) {
4291 global $CFG;
4293 if (is_null($node)) {
4294 $node =& admin_get_root();
4297 if (is_a($node, 'admin_category')) {
4298 $entries = array_keys($node->children);
4299 foreach ($entries as $entry) {
4300 admin_apply_default_settings($node->children[$entry], $unconditional);
4303 } else if (is_a($node, 'admin_settingpage')) {
4304 foreach ($node->settings as $setting) {
4305 if (!$unconditional and !is_null($setting->get_setting())) {
4306 //do not override existing defaults
4307 continue;
4309 $defaultsetting = $setting->get_defaultsetting();
4310 if (is_null($defaultsetting)) {
4311 // no value yet - default maybe applied after admin user creation or in upgradesettings
4312 continue;
4314 $setting->write_setting($defaultsetting);
4320 * Store changed settings, this function updates the errors variable in $ADMIN
4321 * @param object $formdata from form (without magic quotes)
4322 * @return int number of changed settings
4324 function admin_write_settings($formdata) {
4325 global $CFG, $SITE, $COURSE;
4327 $olddbsessions = !empty($CFG->dbsessions);
4328 $formdata = (array)stripslashes_recursive($formdata);
4330 $data = array();
4331 foreach ($formdata as $fullname=>$value) {
4332 if (strpos($fullname, 's_') !== 0) {
4333 continue; // not a config value
4335 $data[$fullname] = $value;
4338 $adminroot =& admin_get_root();
4339 $settings = admin_find_write_settings($adminroot, $data);
4341 $count = 0;
4342 foreach ($settings as $fullname=>$setting) {
4343 $original = serialize($setting->get_setting()); // comparison must work for arrays too
4344 $error = $setting->write_setting($data[$fullname]);
4345 if ($error !== '') {
4346 $adminroot->errors[$fullname] = new object();
4347 $adminroot->errors[$fullname]->data = $data[$fullname];
4348 $adminroot->errors[$fullname]->id = $setting->get_id();
4349 $adminroot->errors[$fullname]->error = $error;
4351 if ($original !== serialize($setting->get_setting())) {
4352 $count++;
4353 $callbackfunction = $setting->updatedcallback;
4354 if (function_exists($callbackfunction)) {
4355 $callbackfunction($fullname);
4360 if ($olddbsessions != !empty($CFG->dbsessions)) {
4361 require_logout();
4364 // now update $SITE - it might have been changed
4365 $SITE = get_record('course', 'id', $SITE->id);
4366 $COURSE = clone($SITE);
4368 // now reload all settings - some of them might depend on the changed
4369 admin_get_root(true);
4370 return $count;
4374 * Internal recursive function - finds all settings from submitted form
4376 function admin_find_write_settings($node, $data) {
4377 $return = array();
4379 if (empty($data)) {
4380 return $return;
4383 if (is_a($node, 'admin_category')) {
4384 $entries = array_keys($node->children);
4385 foreach ($entries as $entry) {
4386 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
4389 } else if (is_a($node, 'admin_settingpage')) {
4390 foreach ($node->settings as $setting) {
4391 $fullname = $setting->get_full_name();
4392 if (array_key_exists($fullname, $data)) {
4393 $return[$fullname] = $setting;
4399 return $return;
4403 * Internal function - prints the search results
4405 function admin_search_settings_html($query) {
4406 global $CFG;
4408 $textlib = textlib_get_instance();
4409 if ($textlib->strlen($query) < 2) {
4410 return '';
4412 $query = $textlib->strtolower($query);
4414 $adminroot =& admin_get_root();
4415 $findings = $adminroot->search($query);
4416 $return = '';
4417 $savebutton = false;
4419 foreach ($findings as $found) {
4420 $page = $found->page;
4421 $settings = $found->settings;
4422 if ($page->is_hidden()) {
4423 // hidden pages are not displayed in search results
4424 continue;
4426 if (is_a($page, 'admin_externalpage')) {
4427 $return .= print_heading(get_string('searchresults','admin').' - <a href="'.$page->url.'">'.highlight($query, $page->visiblename).'</a>', '', 2, 'main', true);
4428 } else if (is_a($page, 'admin_settingpage')) {
4429 $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);
4430 } else {
4431 continue;
4433 if (!empty($settings)) {
4434 $savebutton = true;
4435 $return .= '<fieldset class="adminsettings">'."\n";
4436 foreach ($settings as $setting) {
4437 $return .= '<div class="clearer"><!-- --></div>'."\n";
4438 $fullname = $setting->get_full_name();
4439 if (array_key_exists($fullname, $adminroot->errors)) {
4440 $data = $adminroot->errors[$fullname]->data;
4441 } else {
4442 $data = $setting->get_setting();
4443 if (is_null($data)) {
4444 $data = $setting->get_defaultsetting();
4447 $return .= $setting->output_html($data, $query);
4449 $return .= '</fieldset>';
4453 if ($savebutton) {
4454 $return .= '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges','admin').'" /></div>';
4457 return $return;
4461 * Internal function - returns arrays of html pages with uninitialised settings
4463 function admin_output_new_settings_by_page($node) {
4464 $return = array();
4466 if (is_a($node, 'admin_category')) {
4467 $entries = array_keys($node->children);
4468 foreach ($entries as $entry) {
4469 $return += admin_output_new_settings_by_page($node->children[$entry]);
4472 } else if (is_a($node, 'admin_settingpage')) {
4473 $newsettings = array();
4474 foreach ($node->settings as $setting) {
4475 if (is_null($setting->get_setting())) {
4476 $newsettings[] = $setting;
4479 if (count($newsettings) > 0) {
4480 $adminroot =& admin_get_root();
4481 $page = print_heading(get_string('upgradesettings','admin').' - '.$node->visiblename, '', 2, 'main', true);
4482 $page .= '<fieldset class="adminsettings">'."\n";
4483 foreach ($newsettings as $setting) {
4484 $fullname = $setting->get_full_name();
4485 if (array_key_exists($fullname, $adminroot->errors)) {
4486 $data = $adminroot->errors[$fullname]->data;
4487 } else {
4488 $data = $setting->get_setting();
4489 if (is_null($data)) {
4490 $data = $setting->get_defaultsetting();
4493 $page .= '<div class="clearer"><!-- --></div>'."\n";
4494 $page .= $setting->output_html($data);
4496 $page .= '</fieldset>';
4497 $return[$node->name] = $page;
4501 return $return;
4505 * Unconditionally applies default admin settings in main config table
4506 * @param array $defaults array of string values
4508 function apply_default_exception_settings($defaults) {
4509 foreach($defaults as $key => $value) {
4510 set_config($key, $value, NULL);
4515 * Format admin settings
4516 * @param string $object setting
4517 * @param string $title label element
4518 * @param string $form form fragment, html code - not highlighed automaticaly
4519 * @param string $description
4520 * @param bool $label link label to id
4521 * @param string $warning warning text
4522 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string
4523 * @param string $query search query to be highlighted
4525 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
4526 global $CFG;
4528 $name = $setting->name;
4529 $fullname = $setting->get_full_name();
4531 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
4532 if ($label) {
4533 $labelfor = 'for = "'.$setting->get_id().'"';
4534 } else {
4535 $labelfor = '';
4538 if (empty($setting->plugin) and array_key_exists($name, $CFG->config_php_settings)) {
4539 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
4540 } else {
4541 $override = '';
4544 if ($warning !== '') {
4545 $warning = '<div class="form-warning">'.$warning.'</div>';
4548 if (is_null($defaultinfo)) {
4549 $defaultinfo = '';
4550 } else {
4551 if ($defaultinfo === '') {
4552 $defaultinfo = get_string('emptysettingvalue', 'admin');
4554 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
4555 $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>';
4559 $str = '
4560 <div class="form-item clearfix" id="admin-'.$setting->name.'">
4561 <div class="form-label">
4562 <label '.$labelfor.'>'.highlightfast($query, $title).'<span class="form-shortname">'.highlightfast($query, $name).'</span>
4563 '.$override.$warning.'
4564 </label>
4565 </div>
4566 <div class="form-setting">'.$form.$defaultinfo.'</div>
4567 <div class="form-description">'.highlight($query, $description).'</div>
4568 </div>';
4570 $adminroot =& admin_get_root();
4571 if (array_key_exists($fullname, $adminroot->errors)) {
4572 $str = '<fieldset class="error"><legend>'.$adminroot->errors[$fullname]->error.'</legend>'.$str.'</fieldset>';
4575 return $str;
4579 * Try to upgrade the given language pack (or current language)
4580 * If it doesn't work, fail silently and return false
4582 function upgrade_language_pack($lang='') {
4583 global $CFG;
4585 if (empty($lang)) {
4586 $lang = current_language();
4589 if ($lang == 'en_utf8') {
4590 return true; // Nothing to do
4593 notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
4595 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
4596 @mkdir ($CFG->dataroot.'/lang/');
4598 require_once($CFG->libdir.'/componentlib.class.php');
4600 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
4601 $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
4603 if ($status == COMPONENT_INSTALLED) {
4604 debugging('Downloading successful: '.$lang);
4605 @unlink($CFG->dataroot.'/cache/languages');
4606 return true;
4610 return false;
4614 * Based on find_new_settings{@link ()} in upgradesettings.php
4615 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
4617 * @param string $node The node at which to start searching.
4618 * @return boolen true if any settings haven't been initialised, false if they all have
4620 function any_new_admin_settings($node) {
4622 if (is_a($node, 'admin_category')) {
4623 $entries = array_keys($node->children);
4624 foreach ($entries as $entry) {
4625 if (any_new_admin_settings($node->children[$entry])){
4626 return true;
4630 } else if (is_a($node, 'admin_settingpage')) {
4631 foreach ($node->settings as $setting) {
4632 if ($setting->get_setting() === NULL) {
4633 return true;
4638 return false;
4643 * Moved from admin/replace.php so that we can use this in cron
4644 * @param string $search - string to look for (with magic quotes)
4645 * @param string $replace - string to replace (with magic quotes)
4646 * @return bool - success or fail
4648 function db_replace($search, $replace) {
4650 global $db, $CFG;
4652 /// Turn off time limits, sometimes upgrades can be slow.
4653 @set_time_limit(0);
4654 @ob_implicit_flush(true);
4655 while(@ob_end_flush());
4657 if (!$tables = $db->Metatables() ) { // No tables yet at all.
4658 return false;
4660 foreach ($tables as $table) {
4662 if (in_array($table, array($CFG->prefix.'config'))) { // Don't process these
4663 continue;
4666 if ($columns = $db->MetaColumns($table, false)) {
4667 foreach ($columns as $column => $data) {
4668 if (in_array($data->type, array('text','mediumtext','longtext','varchar'))) { // Text stuff only
4669 $db->debug = true;
4670 execute_sql("UPDATE $table SET $column = REPLACE($column, '$search', '$replace');");
4671 $db->debug = false;
4677 return true;
4681 * Prints tables of detected plugins, one table per plugin type,
4682 * and prints whether they are part of the standard Moodle
4683 * distribution or not.
4685 function print_plugin_tables() {
4686 $plugins_standard = array();
4687 $plugins_standard['mod'] = array('assignment',
4688 'chat',
4689 'choice',
4690 'data',
4691 'exercise',
4692 'forum',
4693 'glossary',
4694 'hotpot',
4695 'journal',
4696 'label',
4697 'lams',
4698 'lesson',
4699 'quiz',
4700 'resource',
4701 'scorm',
4702 'survey',
4703 'wiki',
4704 'workshop');
4706 $plugins_standard['blocks'] = array('activity_modules',
4707 'admin',
4708 'admin_bookmarks',
4709 'admin_tree',
4710 'blog_menu',
4711 'blog_tags',
4712 'calendar_month',
4713 'calendar_upcoming',
4714 'course_list',
4715 'course_summary',
4716 'glossary_random',
4717 'html',
4718 'loancalc',
4719 'login',
4720 'mentees',
4721 'messages',
4722 'mnet_hosts',
4723 'news_items',
4724 'online_users',
4725 'participants',
4726 'quiz_results',
4727 'recent_activity',
4728 'rss_client',
4729 'search',
4730 'search_forums',
4731 'section_links',
4732 'site_main_menu',
4733 'social_activities',
4734 'tag_flickr',
4735 'tag_youtube',
4736 'tags');
4738 $plugins_standard['filter'] = array('activitynames',
4739 'algebra',
4740 'censor',
4741 'emailprotect',
4742 'filter',
4743 'mediaplugin',
4744 'multilang',
4745 'tex',
4746 'tidy');
4748 $plugins_installed = array();
4749 $installed_mods = get_records_list('modules', '', '', '', 'name');
4750 $installed_blocks = get_records_list('block', '', '', '', 'name');
4752 foreach($installed_mods as $mod) {
4753 $plugins_installed['mod'][] = $mod->name;
4756 foreach($installed_blocks as $block) {
4757 $plugins_installed['blocks'][] = $block->name;
4760 $plugins_ondisk = array();
4761 $plugins_ondisk['mod'] = get_list_of_plugins('mod', 'db');
4762 $plugins_ondisk['blocks'] = get_list_of_plugins('blocks', 'db');
4763 $plugins_ondisk['filter'] = get_list_of_plugins('filter', 'db');
4765 $strstandard = get_string('standard');
4766 $strnonstandard = get_string('nonstandard');
4767 $strmissingfromdisk = '(' . get_string('missingfromdisk') . ')';
4768 $strabouttobeinstalled = '(' . get_string('abouttobeinstalled') . ')';
4770 $html = '';
4772 $html .= '<table class="generaltable plugincheckwrapper" cellspacing="4" cellpadding="1"><tr valign="top">';
4774 foreach ($plugins_ondisk as $cat => $list_ondisk) {
4775 $strcaption = get_string($cat);
4776 if ($cat == 'mod') {
4777 $strcaption = get_string('activitymodule');
4778 } elseif ($cat == 'filter') {
4779 $strcaption = get_string('managefilters');
4782 $html .= '<td><table class="plugincompattable generaltable boxaligncenter" cellspacing="1" cellpadding="5" '
4783 . 'id="' . $cat . 'compattable" summary="compatibility table"><caption>' . $strcaption . '</caption>' . "\n";
4784 $html .= '<tr class="r0"><th class="header c0">' . get_string('directory') . "</th>\n"
4785 . '<th class="header c1">' . get_string('name') . "</th>\n"
4786 . '<th class="header c2">' . get_string('status') . "</th>\n</tr>\n";
4788 $row = 1;
4790 foreach ($list_ondisk as $k => $plugin) {
4791 $status = 'ok';
4792 $standard = 'standard';
4793 $note = '';
4795 if (!in_array($plugin, $plugins_standard[$cat])) {
4796 $standard = 'nonstandard';
4797 $status = 'warning';
4800 // Get real name and full path of plugin
4801 $plugin_name = "[[$plugin]]";
4803 $plugin_path = "$cat/$plugin";
4805 $plugin_name = get_plugin_name($plugin, $cat);
4807 // Determine if the plugin is about to be installed
4808 if ($cat != 'filter' && !in_array($plugin, $plugins_installed[$cat])) {
4809 $note = $strabouttobeinstalled;
4810 $plugin_name = $plugin;
4813 $html .= "<tr class=\"r$row\">\n"
4814 . "<td class=\"cell c0\">$plugin_path</td>\n"
4815 . "<td class=\"cell c1\">$plugin_name</td>\n"
4816 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $note</td>\n</tr>\n";
4817 $row++;
4819 // If the plugin was both on disk and in the db, unset the value from the installed plugins list
4820 if ($key = array_search($plugin, $plugins_installed[$cat])) {
4821 unset($plugins_installed[$cat][$key]);
4825 // If there are plugins left in the plugins_installed list, it means they are missing from disk
4826 foreach ($plugins_installed[$cat] as $k => $missing_plugin) {
4827 // Make sure the plugin really is missing from disk
4828 if (!in_array($missing_plugin, $plugins_ondisk[$cat])) {
4829 $standard = 'standard';
4830 $status = 'warning';
4832 if (!in_array($missing_plugin, $plugins_standard[$cat])) {
4833 $standard = 'nonstandard';
4836 $plugin_name = $missing_plugin;
4837 $html .= "<tr class=\"r$row\">\n"
4838 . "<td class=\"cell c0\">?</td>\n"
4839 . "<td class=\"cell c1\">$plugin_name</td>\n"
4840 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $strmissingfromdisk</td>\n</tr>\n";
4841 $row++;
4845 $html .= '</table></td>';
4848 $html .= '</tr></table><br />';
4850 echo $html;