MDL-15505
[moodle-linuxchix.git] / lib / adminlib.php
blob5bab80de4170d1d315fd26c97483da70053102a1
1 <?php
3 /**
4 * adminlib.php - Contains functions that only administrators will ever need to use
6 * @author Martin Dougiamas and many others
7 * @version $Id$
8 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
9 * @package moodlecore
12 function upgrade_main_savepoint($result, $version) {
13 global $CFG;
15 if ($result) {
16 if ($CFG->version >= $version) {
17 // something really wrong is going on in main upgrade script
18 error("Upgrade savepoint: Can not upgrade main version from $CFG->version to $version.");
20 set_config('version', $version);
21 } else {
22 notify ("Upgrade savepoint: Error during main upgrade to version $version");
26 function upgrade_mod_savepoint($result, $version, $type) {
27 //TODO
30 function upgrade_plugin_savepoint($result, $version, $type, $dir) {
31 //TODO
34 function upgrade_backup_savepoint($result, $version) {
35 //TODO
38 function upgrade_blocks_savepoint($result, $version, $type) {
39 //TODO
42 /**
43 * Upgrade plugins
45 * @uses $db
46 * @uses $CFG
47 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
48 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
49 * @param string $return The url to prompt the user to continue to
51 function upgrade_plugins($type, $dir, $return) {
52 global $CFG, $db;
54 /// Let's know if the header has been printed, so the funcion is being called embedded in an outer page
55 $embedded = defined('HEADER_PRINTED');
57 $plugs = get_list_of_plugins($dir);
58 $updated_plugins = false;
59 $strpluginsetup = get_string('pluginsetup');
61 foreach ($plugs as $plug) {
63 $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
65 unset($plugin);
67 if (is_readable($fullplug .'/version.php')) {
68 include_once($fullplug .'/version.php'); // defines $plugin with version etc
69 } else {
70 continue; // Nothing to do.
73 $oldupgrade = false;
74 $newupgrade = false;
75 if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) {
76 include_once($fullplug . '/db/'. $CFG->dbtype . '.php'); // defines old upgrading function
77 $oldupgrade = true;
79 if (is_readable($fullplug . '/db/upgrade.php')) {
80 include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
81 $newupgrade = true;
84 if (!isset($plugin)) {
85 continue;
88 if (!empty($plugin->requires)) {
89 if ($plugin->requires > $CFG->version) {
90 $info = new object();
91 $info->pluginname = $plug;
92 $info->pluginversion = $plugin->version;
93 $info->currentmoodle = $CFG->version;
94 $info->requiremoodle = $plugin->requires;
95 if (!$updated_plugins && !$embedded) {
96 print_header($strpluginsetup, $strpluginsetup,
97 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
98 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
100 upgrade_log_start();
101 notify(get_string('pluginrequirementsnotmet', 'error', $info));
102 $updated_plugins = true;
103 continue;
107 $plugin->name = $plug; // The name MUST match the directory
109 $pluginversion = $type.'_'.$plug.'_version';
111 if (!isset($CFG->$pluginversion)) {
112 set_config($pluginversion, 0);
115 if ($CFG->$pluginversion == $plugin->version) {
116 // do nothing
117 } else if ($CFG->$pluginversion < $plugin->version) {
118 if (!$updated_plugins && !$embedded) {
119 print_header($strpluginsetup, $strpluginsetup,
120 build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
121 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
123 $updated_plugins = true;
124 upgrade_log_start();
125 print_heading($dir.'/'. $plugin->name .' plugin needs upgrading');
126 $db->debug = true;
127 @set_time_limit(0); // To allow slow databases to complete the long SQL
129 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
130 /// Both old .sql files and new install.xml are supported
131 /// but we priorize install.xml (XMLDB) if present
132 $status = false;
133 if (file_exists($fullplug . '/db/install.xml')) {
134 $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
135 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
136 $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
137 } else {
138 $status = true;
141 $db->debug = false;
142 /// Continue with the instalation, roles and other stuff
143 if ($status) {
144 /// OK so far, now update the plugins record
145 set_config($pluginversion, $plugin->version);
147 /// Install capabilities
148 if (!update_capabilities($type.'/'.$plug)) {
149 error('Could not set up the capabilities for '.$plugin->name.'!');
151 /// Install events
152 events_update_definition($type.'/'.$plug);
154 /// Run local install function if there is one
155 if (is_readable($fullplug .'/lib.php')) {
156 include_once($fullplug .'/lib.php');
157 $installfunction = $plugin->name.'_install';
158 if (function_exists($installfunction)) {
159 if (! $installfunction() ) {
160 notify('Encountered a problem running install function for '.$module->name.'!');
165 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
166 } else {
167 notify('Installing '. $plugin->name .' FAILED!');
169 } else { // Upgrade existing install
170 /// Run de old and new upgrade functions for the module
171 $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade';
172 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
174 /// First, the old function if exists
175 $oldupgrade_status = true;
176 if ($oldupgrade && function_exists($oldupgrade_function)) {
177 $db->debug = true;
178 $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
179 } else if ($oldupgrade) {
180 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
181 $fullplug . '/db/' . $CFG->dbtype . '.php');
184 /// Then, the new function if exists and the old one was ok
185 $newupgrade_status = true;
186 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
187 $db->debug = true;
188 $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
189 } else if ($newupgrade) {
190 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
191 $fullplug . '/db/upgrade.php');
194 $db->debug=false;
195 /// Now analyze upgrade results
196 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
197 // OK so far, now update the plugins record
198 set_config($pluginversion, $plugin->version);
199 if (!update_capabilities($type.'/'.$plug)) {
200 error('Could not update '.$plugin->name.' capabilities!');
202 events_update_definition($type.'/'.$plug);
203 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
204 } else {
205 notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
208 echo '<hr />';
209 } else {
210 upgrade_log_start();
211 error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
215 upgrade_log_finish();
217 if ($updated_plugins && !$embedded) {
218 print_continue($return);
219 print_footer('none');
220 die;
225 * Find and check all modules and load them up or upgrade them if necessary
227 * @uses $db
228 * @uses $CFG
229 * @param string $return The url to prompt the user to continue to
230 * @todo Finish documenting this function
232 function upgrade_activity_modules($return) {
234 global $CFG, $db;
236 if (!$mods = get_list_of_plugins('mod') ) {
237 error('No modules installed!');
240 $updated_modules = false;
241 $strmodulesetup = get_string('modulesetup');
243 foreach ($mods as $mod) {
245 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
246 continue;
249 $fullmod = $CFG->dirroot .'/mod/'. $mod;
251 unset($module);
253 if ( is_readable($fullmod .'/version.php')) {
254 include_once($fullmod .'/version.php'); // defines $module with version etc
255 } else {
256 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
257 continue;
260 $oldupgrade = false;
261 $newupgrade = false;
262 if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
263 include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function
264 $oldupgrade = true;
266 if ( is_readable($fullmod . '/db/upgrade.php')) {
267 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
268 $newupgrade = true;
271 if (!isset($module)) {
272 continue;
275 if (!empty($module->requires)) {
276 if ($module->requires > $CFG->version) {
277 $info = new object();
278 $info->modulename = $mod;
279 $info->moduleversion = $module->version;
280 $info->currentmoodle = $CFG->version;
281 $info->requiremoodle = $module->requires;
282 if (!$updated_modules) {
283 print_header($strmodulesetup, $strmodulesetup,
284 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
285 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
287 upgrade_log_start();
288 notify(get_string('modulerequirementsnotmet', 'error', $info));
289 $updated_modules = true;
290 continue;
294 $module->name = $mod; // The name MUST match the directory
296 include_once($fullmod.'/lib.php'); // defines upgrading and/or installing functions
298 if ($currmodule = get_record('modules', 'name', $module->name)) {
299 if ($currmodule->version == $module->version) {
300 // do nothing
301 } else if ($currmodule->version < $module->version) {
302 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
303 if (!$oldupgrade && !$newupgrade) {
304 notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' .
305 $fullmod . '/db/upgrade.php were not readable');
306 continue;
308 if (!$updated_modules) {
309 print_header($strmodulesetup, $strmodulesetup,
310 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
311 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
313 upgrade_log_start();
314 print_heading($module->name .' module needs upgrading');
316 /// Run de old and new upgrade functions for the module
317 $oldupgrade_function = $module->name . '_upgrade';
318 $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
320 /// First, the old function if exists
321 $oldupgrade_status = true;
322 if ($oldupgrade && function_exists($oldupgrade_function)) {
323 $db->debug = true;
324 $oldupgrade_status = $oldupgrade_function($currmodule->version, $module);
325 if (!$oldupgrade_status) {
326 notify ('Upgrade function ' . $oldupgrade_function .
327 ' did not complete successfully.');
329 } else if ($oldupgrade) {
330 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
331 $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php');
334 /// Then, the new function if exists and the old one was ok
335 $newupgrade_status = true;
336 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
337 $db->debug = true;
338 $newupgrade_status = $newupgrade_function($currmodule->version, $module);
339 } else if ($newupgrade && $oldupgrade_status) {
340 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
341 $mod . ': ' . $fullmod . '/db/upgrade.php');
344 $db->debug=false;
345 /// Now analyze upgrade results
346 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
347 // OK so far, now update the modules record
348 $module->id = $currmodule->id;
349 if (! update_record('modules', $module)) {
350 error('Could not update '. $module->name .' record in modules table!');
352 remove_dir($CFG->dataroot . '/cache', true); // flush cache
353 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
354 echo '<hr />';
355 } else {
356 notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
359 /// Update the capabilities table?
360 if (!update_capabilities('mod/'.$module->name)) {
361 error('Could not update '.$module->name.' capabilities!');
363 events_update_definition('mod/'.$module->name);
365 $updated_modules = true;
367 } else {
368 upgrade_log_start();
369 error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
372 } else { // module not installed yet, so install it
373 if (!$updated_modules) {
374 print_header($strmodulesetup, $strmodulesetup,
375 build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
376 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
378 upgrade_log_start();
379 print_heading($module->name);
380 $updated_modules = true;
381 $db->debug = true;
382 @set_time_limit(0); // To allow slow databases to complete the long SQL
384 /// Both old .sql files and new install.xml are supported
385 /// but we priorize install.xml (XMLDB) if present
386 if (file_exists($fullmod . '/db/install.xml')) {
387 $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
388 } else {
389 $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method
392 $db->debug = false;
394 /// Continue with the installation, roles and other stuff
395 if ($status) {
396 if ($module->id = insert_record('modules', $module)) {
398 /// Capabilities
399 if (!update_capabilities('mod/'.$module->name)) {
400 error('Could not set up the capabilities for '.$module->name.'!');
403 /// Events
404 events_update_definition('mod/'.$module->name);
406 /// Run local install function if there is one
407 $installfunction = $module->name.'_install';
408 if (function_exists($installfunction)) {
409 if (! $installfunction() ) {
410 notify('Encountered a problem running install function for '.$module->name.'!');
414 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
415 echo '<hr />';
416 } else {
417 error($module->name .' module could not be added to the module list!');
419 } else {
420 error($module->name .' tables could NOT be set up successfully!');
424 /// Check submodules of this module if necessary
426 $submoduleupgrade = $module->name.'_upgrade_submodules';
427 if (function_exists($submoduleupgrade)) {
428 $submoduleupgrade();
432 /// Run any defaults or final code that is necessary for this module
434 if ( is_readable($fullmod .'/defaults.php')) {
435 // Insert default values for any important configuration variables
436 unset($defaults);
437 include($fullmod .'/defaults.php'); // include here means execute, not library include
438 if (!empty($defaults)) {
439 foreach ($defaults as $name => $value) {
440 if (!isset($CFG->$name)) {
441 set_config($name, $value);
448 upgrade_log_finish(); // finish logging if started
450 if ($updated_modules) {
451 print_continue($return);
452 print_footer('none');
453 die;
458 * Try to obtain or release the cron lock.
460 * @param string $name name of lock
461 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionaly
462 * @param bool $ignorecurrent ignore current lock state, usually entend previous lock
463 * @return bool true if lock obtained
465 function set_cron_lock($name, $until, $ignorecurrent=false) {
466 if (empty($name)) {
467 debugging("Tried to get a cron lock for a null fieldname");
468 return false;
471 // remove lock by force == remove from config table
472 if (is_null($until)) {
473 set_config($name, null);
474 return true;
477 if (!$ignorecurrent) {
478 // read value from db - other processes might have changed it
479 $value = get_field('config', 'value', 'name', $name);
481 if ($value and $value > time()) {
482 //lock active
483 return false;
487 set_config($name, $until);
488 return true;
491 function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
492 static $thisbarid;
493 static $starttime;
494 static $lasttime;
496 if ($total < 2) { // No need to show anything
497 return;
500 // Are we done?
501 if ($done >= $total) {
502 $done = $total;
503 if (!empty($thisbarid)) {
504 $donetext .= ' ('.$done.'/'.$total.') '.get_string('success');
505 print_progress_redraw($thisbarid, $done, $total, 500, $donetext);
506 $thisbarid = $starttime = $lasttime = NULL;
508 return;
511 if (empty($starttime)) {
512 $starttime = $lasttime = time();
513 $lasttime = $starttime - $updatetime;
514 $thisbarid = uniqid();
515 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
516 echo '<div id="bar'.$thisbarid.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
517 echo '<div id="slider'.$thisbarid.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
518 echo '</div>';
519 echo '<div id="text'.$thisbarid.'" align="center" style="width:500px;"></div>';
520 echo '</td></tr></table>';
521 echo '</div>';
524 $now = time();
526 if ($done && (($now - $lasttime) >= $updatetime)) {
527 $elapsedtime = $now - $starttime;
528 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
529 $percentage = round((float)$done / (float)$total, 2);
530 $width = (int)(500 * $percentage);
532 if ($projectedtime > 10) {
533 $projectedtext = ' Ending: '.format_time($projectedtime);
534 } else {
535 $projectedtext = '';
538 $donetext .= ' ('.$done.'/'.$total.') '.$projectedtext;
539 print_progress_redraw($thisbarid, $done, $total, $width, $donetext);
541 $lasttime = $now;
545 // Don't call this function directly, it's called from print_progress.
546 function print_progress_redraw($thisbarid, $done, $total, $width, $donetext='') {
547 if (empty($thisbarid)) {
548 return;
550 echo '<script>';
551 echo 'document.getElementById("text'.$thisbarid.'").innerHTML = "'.addslashes($donetext).'";'."\n";
552 echo 'document.getElementById("slider'.$thisbarid.'").style.width = \''.$width.'px\';'."\n";
553 echo '</script>';
556 function upgrade_get_javascript() {
557 global $CFG;
559 if (!empty($_SESSION['installautopilot'])) {
560 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
561 } else {
562 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
564 $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>';
566 return $linktoscrolltoerrors;
569 function create_admin_user() {
570 global $CFG, $USER;
572 if (empty($CFG->rolesactive)) { // No admin user yet.
574 $user = new object();
575 $user->auth = 'manual';
576 $user->firstname = get_string('admin');
577 $user->lastname = get_string('user');
578 $user->username = 'admin';
579 $user->password = hash_internal_user_password('admin');
580 $user->email = 'root@localhost';
581 $user->confirmed = 1;
582 $user->mnethostid = $CFG->mnet_localhost_id;
583 $user->lang = $CFG->lang;
584 $user->maildisplay = 1;
585 $user->timemodified = time();
587 if (!$user->id = insert_record('user', $user)) {
588 error('SERIOUS ERROR: Could not create admin user record !!!');
591 if (!$user = get_record('user', 'id', $user->id)) { // Double check.
592 error('User ID was incorrect (can\'t find it)');
595 // Assign the default admin roles to the new user.
596 if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW)) {
597 error('No admin role could be found');
599 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
600 foreach ($adminroles as $adminrole) {
601 role_assign($adminrole->id, $user->id, 0, $sitecontext->id);
604 set_config('rolesactive', 1);
606 // Log the user in.
607 $USER = get_complete_user_data('username', 'admin');
608 $USER->newadminuser = 1;
609 load_all_capabilities();
611 redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id"); // Edit thyself
612 } else {
613 error('Can not create admin!');
617 ////////////////////////////////////////////////
618 /// upgrade logging functions
619 ////////////////////////////////////////////////
621 $upgradeloghandle = false;
622 $upgradelogbuffer = '';
623 // I did not find out how to use static variable in callback function,
624 // the problem was that I could not flush the static buffer :-(
625 global $upgradeloghandle, $upgradelogbuffer;
628 * Check if upgrade is already running.
630 * If anything goes wrong due to missing call to upgrade_log_finish()
631 * just restart the browser.
633 * @param string warning message indicating upgrade is already running
634 * @param int page reload timeout
636 function upgrade_check_running($message, $timeout) {
637 if (!empty($_SESSION['upgraderunning'])) {
638 print_header();
639 redirect(me(), $message, $timeout);
644 * Start logging of output into file (if not disabled) and
645 * prevent aborting and concurrent execution of upgrade script.
647 * Please note that you can not write into session variables after calling this function!
649 * This function may be called repeatedly.
651 function upgrade_log_start() {
652 global $CFG, $upgradeloghandle;
654 if (!empty($_SESSION['upgraderunning'])) {
655 return; // logging already started
658 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
659 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
660 if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
661 session_write_close(); // from now on user can reload page - will be displayed warning
663 make_upload_directory('upgradelogs');
664 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
665 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
669 * Terminate logging of output, flush all data, allow script aborting
670 * and reopen session for writing. Function error() does terminate the logging too.
672 * Please make sure that each upgrade_log_start() is properly terminated by
673 * this function or error().
675 * This function may be called repeatedly.
677 function upgrade_log_finish() {
678 global $CFG, $upgradeloghandle, $upgradelogbuffer;
680 if (empty($_SESSION['upgraderunning'])) {
681 return; // logging already terminated
684 @ob_end_flush();
685 if ($upgradelogbuffer !== '') {
686 @fwrite($upgradeloghandle, $upgradelogbuffer);
687 $upgradelogbuffer = '';
689 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
690 @fclose($upgradeloghandle);
691 $upgradeloghandle = false;
693 if (empty($CFG->dbsessions)) {
694 @session_start(); // ignore header errors, we only need to reopen session
696 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
697 if (connection_aborted()) {
698 die;
700 @ignore_user_abort(false);
704 * Callback function for logging into files. Not more than one file is created per minute,
705 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
707 * This function must not output any characters or throw warnigns and errors!
709 function upgrade_log_callback($string) {
710 global $CFG, $upgradeloghandle, $upgradelogbuffer;
712 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
713 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
714 $upgradelogbuffer .= $string;
715 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
716 @fwrite($upgradeloghandle, $upgradelogbuffer);
717 $upgradelogbuffer = '';
719 } else {
720 $upgradeloghandle = 'error';
723 return $string;
727 * Try to verify that dataroot is not accessible from web.
728 * It is not 100% correct but might help to reduce number of vulnerable sites.
730 * Protection from httpd.conf and .htaccess is not detected properly.
732 function is_dataroot_insecure() {
733 global $CFG;
735 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
737 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
738 $rp = strrev(trim($rp, '/'));
739 $rp = explode('/', $rp);
740 foreach($rp as $r) {
741 if (strpos($siteroot, '/'.$r.'/') === 0) {
742 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
743 } else {
744 break; // probably alias root
748 $siteroot = strrev($siteroot);
749 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
751 if (strpos($dataroot, $siteroot) === 0) {
752 return true;
754 return false;
757 /// =============================================================================================================
758 /// administration tree classes and functions
761 // n.b. documentation is still in progress for this code
763 /// INTRODUCTION
765 /// This file performs the following tasks:
766 /// -it defines the necessary objects and interfaces to build the Moodle
767 /// admin hierarchy
768 /// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
769 /// and admin_externalpage_print_footer() functions used on admin pages
771 /// ADMIN_SETTING OBJECTS
773 /// Moodle settings are represented by objects that inherit from the admin_setting
774 /// class. These objects encapsulate how to read a setting, how to write a new value
775 /// to a setting, and how to appropriately display the HTML to modify the setting.
777 /// ADMIN_SETTINGPAGE OBJECTS
779 /// The admin_setting objects are then grouped into admin_settingpages. The latter
780 /// appear in the Moodle admin tree block. All interaction with admin_settingpage
781 /// objects is handled by the admin/settings.php file.
783 /// ADMIN_EXTERNALPAGE OBJECTS
785 /// There are some settings in Moodle that are too complex to (efficiently) handle
786 /// with admin_settingpages. (Consider, for example, user management and displaying
787 /// lists of users.) In this case, we use the admin_externalpage object. This object
788 /// places a link to an external PHP file in the admin tree block.
790 /// If you're using an admin_externalpage object for some settings, you can take
791 /// advantage of the admin_externalpage_* functions. For example, suppose you wanted
792 /// to add a foo.php file into admin. First off, you add the following line to
793 /// admin/settings/first.php (at the end of the file) or to some other file in
794 /// admin/settings:
796 /// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
797 /// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
799 /// Next, in foo.php, your file structure would resemble the following:
801 /// require_once('.../config.php');
802 /// require_once($CFG->libdir.'/adminlib.php');
803 /// admin_externalpage_setup('foo');
804 /// // functionality like processing form submissions goes here
805 /// admin_externalpage_print_header();
806 /// // your HTML goes here
807 /// admin_externalpage_print_footer();
809 /// The admin_externalpage_setup() function call ensures the user is logged in,
810 /// and makes sure that they have the proper role permission to access the page.
812 /// The admin_externalpage_print_header() function prints the header (it figures
813 /// out what category and subcategories the page is classified under) and ensures
814 /// that you're using the admin pagelib (which provides the admin tree block and
815 /// the admin bookmarks block).
817 /// The admin_externalpage_print_footer() function properly closes the tables
818 /// opened up by the admin_externalpage_print_header() function and prints the
819 /// standard Moodle footer.
821 /// ADMIN_CATEGORY OBJECTS
823 /// Above and beyond all this, we have admin_category objects. These objects
824 /// appear as folders in the admin tree block. They contain admin_settingpage's,
825 /// admin_externalpage's, and other admin_category's.
827 /// OTHER NOTES
829 /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
830 /// from part_of_admin_tree (a pseudointerface). This interface insists that
831 /// a class has a check_access method for access permissions, a locate method
832 /// used to find a specific node in the admin tree and find parent path.
834 /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
835 /// interface ensures that the class implements a recursive add function which
836 /// accepts a part_of_admin_tree object and searches for the proper place to
837 /// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
839 /// Please note that the $this->name field of any part_of_admin_tree must be
840 /// UNIQUE throughout the ENTIRE admin tree.
842 /// The $this->name field of an admin_setting object (which is *not* part_of_
843 /// admin_tree) must be unique on the respective admin_settingpage where it is
844 /// used.
847 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
850 * Pseudointerface for anything appearing in the admin tree
852 * The pseudointerface that is implemented by anything that appears in the admin tree
853 * block. It forces inheriting classes to define a method for checking user permissions
854 * and methods for finding something in the admin tree.
856 * @author Vincenzo K. Marcovecchio
857 * @package admin
859 class part_of_admin_tree {
862 * Finds a named part_of_admin_tree.
864 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
865 * and not parentable_part_of_admin_tree, then this function should only check if
866 * $this->name matches $name. If it does, it should return a reference to $this,
867 * otherwise, it should return a reference to NULL.
869 * If a class inherits parentable_part_of_admin_tree, this method should be called
870 * recursively on all child objects (assuming, of course, the parent object's name
871 * doesn't match the search criterion).
873 * @param string $name The internal name of the part_of_admin_tree we're searching for.
874 * @return mixed An object reference or a NULL reference.
876 function &locate($name) {
877 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
878 return;
882 * Removes named part_of_admin_tree.
884 * @param string $name The internal name of the part_of_admin_tree we want to remove.
885 * @return bool success.
887 function prune($name) {
888 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
889 return;
893 * Search using query
894 * @param strin query
895 * @return mixed array-object structure of found settings and pages
897 function search($query) {
898 trigger_error('Admin class does not implement method <strong>search()</strong>', E_USER_WARNING);
899 return;
903 * Verifies current user's access to this part_of_admin_tree.
905 * Used to check if the current user has access to this part of the admin tree or
906 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
907 * then this method is usually just a call to has_capability() in the site context.
909 * If a class inherits parentable_part_of_admin_tree, this method should return the
910 * logical OR of the return of check_access() on all child objects.
912 * @return bool True if the user has access, false if she doesn't.
914 function check_access() {
915 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
916 return;
920 * Mostly usefull for removing of some parts of the tree in admin tree block.
922 * @return True is hidden from normal list view
924 function is_hidden() {
925 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
926 return;
931 * Pseudointerface implemented by any part_of_admin_tree that has children.
933 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
934 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
935 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
936 * include an add method for adding other part_of_admin_tree objects as children.
938 * @author Vincenzo K. Marcovecchio
939 * @package admin
941 class parentable_part_of_admin_tree extends part_of_admin_tree {
944 * Adds a part_of_admin_tree object to the admin tree.
946 * Used to add a part_of_admin_tree object to this object or a child of this
947 * object. $something should only be added if $destinationname matches
948 * $this->name. If it doesn't, add should be called on child objects that are
949 * also parentable_part_of_admin_tree's.
951 * @param string $destinationname The internal name of the new parent for $something.
952 * @param part_of_admin_tree &$something The object to be added.
953 * @return bool True on success, false on failure.
955 function add($destinationname, $something) {
956 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
957 return;
963 * The object used to represent folders (a.k.a. categories) in the admin tree block.
965 * Each admin_category object contains a number of part_of_admin_tree objects.
967 * @author Vincenzo K. Marcovecchio
968 * @package admin
970 class admin_category extends parentable_part_of_admin_tree {
973 * @var mixed An array of part_of_admin_tree objects that are this object's children
975 var $children;
978 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
980 var $name;
983 * @var string The displayed name for this category. Usually obtained through get_string()
985 var $visiblename;
988 * @var bool Should this category be hidden in admin tree block?
990 var $hidden;
993 * paths
995 var $path;
996 var $visiblepath;
999 * Constructor for an empty admin category
1001 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
1002 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
1003 * @param bool $hidden hide category in admin tree block
1005 function admin_category($name, $visiblename, $hidden=false) {
1006 $this->children = array();
1007 $this->name = $name;
1008 $this->visiblename = $visiblename;
1009 $this->hidden = $hidden;
1013 * Returns a reference to the part_of_admin_tree object with internal name $name.
1015 * @param string $name The internal name of the object we want.
1016 * @param bool $findpath initialize path and visiblepath arrays
1017 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1019 function &locate($name, $findpath=false) {
1020 if ($this->name == $name) {
1021 if ($findpath) {
1022 $this->visiblepath[] = $this->visiblename;
1023 $this->path[] = $this->name;
1025 return $this;
1028 $return = NULL;
1029 foreach($this->children as $childid=>$unused) {
1030 if ($return =& $this->children[$childid]->locate($name, $findpath)) {
1031 break;
1035 if (!is_null($return) and $findpath) {
1036 $return->visiblepath[] = $this->visiblename;
1037 $return->path[] = $this->name;
1040 return $return;
1044 * Search using query
1045 * @param strin query
1046 * @return mixed array-object structure of found settings and pages
1048 function search($query) {
1049 $result = array();
1050 foreach ($this->children as $child) {
1051 $subsearch = $child->search($query);
1052 if (!is_array($subsearch)) {
1053 debugging('Incorrect search result from '.$child->name);
1054 continue;
1056 $result = array_merge($result, $subsearch);
1058 return $result;
1062 * Removes part_of_admin_tree object with internal name $name.
1064 * @param string $name The internal name of the object we want to remove.
1065 * @return bool success
1067 function prune($name) {
1069 if ($this->name == $name) {
1070 return false; //can not remove itself
1073 foreach($this->children as $precedence => $child) {
1074 if ($child->name == $name) {
1075 // found it!
1076 unset($this->children[$precedence]);
1077 return true;
1079 if ($this->children[$precedence]->prune($name)) {
1080 return true;
1083 return false;
1087 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1089 * @param string $destinationame The internal name of the immediate parent that we want for $something.
1090 * @param mixed $something A part_of_admin_tree or setting instanceto be added.
1091 * @return bool True if successfully added, false if $something can not be added.
1093 function add($parentname, $something) {
1094 $parent =& $this->locate($parentname);
1095 if (is_null($parent)) {
1096 debugging('parent does not exist!');
1097 return false;
1100 if (is_a($something, 'part_of_admin_tree')) {
1101 if (!is_a($parent, 'parentable_part_of_admin_tree')) {
1102 debugging('error - parts of tree can be inserted only into parentable parts');
1103 return false;
1105 $parent->children[] = $something;
1106 return true;
1108 } else {
1109 debugging('error - can not add this element');
1110 return false;
1116 * Checks if the user has access to anything in this category.
1118 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1120 function check_access() {
1121 foreach ($this->children as $child) {
1122 if ($child->check_access()) {
1123 return true;
1126 return false;
1130 * Is this category hidden in admin tree block?
1132 * @return bool True if hidden
1134 function is_hidden() {
1135 return $this->hidden;
1139 class admin_root extends admin_category {
1141 * list of errors
1143 var $errors;
1146 * search query
1148 var $search;
1151 * full tree flag - true means all settings required, false onlypages required
1153 var $fulltree;
1156 function admin_root() {
1157 parent::admin_category('root', get_string('administration'), false);
1158 $this->errors = array();
1159 $this->search = '';
1160 $this->fulltree = true;
1165 * Links external PHP pages into the admin tree.
1167 * See detailed usage example at the top of this document (adminlib.php)
1169 * @author Vincenzo K. Marcovecchio
1170 * @package admin
1172 class admin_externalpage extends part_of_admin_tree {
1175 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1177 var $name;
1180 * @var string The displayed name for this external page. Usually obtained through get_string().
1182 var $visiblename;
1185 * @var string The external URL that we should link to when someone requests this external page.
1187 var $url;
1190 * @var string The role capability/permission a user must have to access this external page.
1192 var $req_capability;
1195 * @var object The context in which capability/permission should be checked, default is site context.
1197 var $context;
1200 * @var bool hidden in admin tree block.
1202 var $hidden;
1205 * visible path
1207 var $path;
1208 var $visiblepath;
1211 * Constructor for adding an external page into the admin tree.
1213 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1214 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1215 * @param string $url The external URL that we should link to when someone requests this external page.
1216 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1218 function admin_externalpage($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1219 $this->name = $name;
1220 $this->visiblename = $visiblename;
1221 $this->url = $url;
1222 if (is_array($req_capability)) {
1223 $this->req_capability = $req_capability;
1224 } else {
1225 $this->req_capability = array($req_capability);
1227 $this->hidden = $hidden;
1228 $this->context = $context;
1232 * Returns a reference to the part_of_admin_tree object with internal name $name.
1234 * @param string $name The internal name of the object we want.
1235 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1237 function &locate($name, $findpath=false) {
1238 if ($this->name == $name) {
1239 if ($findpath) {
1240 $this->visiblepath = array($this->visiblename);
1241 $this->path = array($this->name);
1243 return $this;
1244 } else {
1245 $return = NULL;
1246 return $return;
1250 function prune($name) {
1251 return false;
1255 * Search using query
1256 * @param strin query
1257 * @return mixed array-object structure of found settings and pages
1259 function search($query) {
1260 $textlib = textlib_get_instance();
1262 $found = false;
1263 if (strpos(strtolower($this->name), $query) !== false) {
1264 $found = true;
1265 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1266 $found = true;
1268 if ($found) {
1269 $result = new object();
1270 $result->page = $this;
1271 $result->settings = array();
1272 return array($this->name => $result);
1273 } else {
1274 return array();
1279 * Determines if the current user has access to this external page based on $this->req_capability.
1280 * @return bool True if user has access, false otherwise.
1282 function check_access() {
1283 if (!get_site()) {
1284 return true; // no access check before site is fully set up
1286 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1287 foreach($this->req_capability as $cap) {
1288 if (has_capability($cap, $context)) {
1289 return true;
1292 return false;
1296 * Is this external page hidden in admin tree block?
1298 * @return bool True if hidden
1300 function is_hidden() {
1301 return $this->hidden;
1307 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1309 * @author Vincenzo K. Marcovecchio
1310 * @package admin
1312 class admin_settingpage extends part_of_admin_tree {
1315 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1317 var $name;
1320 * @var string The displayed name for this external page. Usually obtained through get_string().
1322 var $visiblename;
1324 * @var mixed An array of admin_setting objects that are part of this setting page.
1326 var $settings;
1329 * @var string The role capability/permission a user must have to access this external page.
1331 var $req_capability;
1334 * @var object The context in which capability/permission should be checked, default is site context.
1336 var $context;
1339 * @var bool hidden in admin tree block.
1341 var $hidden;
1344 * paths
1346 var $path;
1347 var $visiblepath;
1349 // see admin_externalpage
1350 function admin_settingpage($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1351 $this->settings = new object();
1352 $this->name = $name;
1353 $this->visiblename = $visiblename;
1354 if (is_array($req_capability)) {
1355 $this->req_capability = $req_capability;
1356 } else {
1357 $this->req_capability = array($req_capability);
1359 $this->hidden = $hidden;
1360 $this->context = $context;
1363 // see admin_category
1364 function &locate($name, $findpath=false) {
1365 if ($this->name == $name) {
1366 if ($findpath) {
1367 $this->visiblepath = array($this->visiblename);
1368 $this->path = array($this->name);
1370 return $this;
1371 } else {
1372 $return = NULL;
1373 return $return;
1377 function search($query) {
1378 $found = array();
1380 foreach ($this->settings as $setting) {
1381 if ($setting->is_related($query)) {
1382 $found[] = $setting;
1386 if ($found) {
1387 $result = new object();
1388 $result->page = $this;
1389 $result->settings = $found;
1390 return array($this->name => $result);
1393 $textlib = textlib_get_instance();
1395 $found = false;
1396 if (strpos(strtolower($this->name), $query) !== false) {
1397 $found = true;
1398 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1399 $found = true;
1401 if ($found) {
1402 $result = new object();
1403 $result->page = $this;
1404 $result->settings = array();
1405 return array($this->name => $result);
1406 } else {
1407 return array();
1411 function prune($name) {
1412 return false;
1416 * 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
1417 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1418 * @param object $setting is the admin_setting object you want to add
1419 * @return true if successful, false if not
1421 function add($setting) {
1422 if (!is_a($setting, 'admin_setting')) {
1423 debugging('error - not a setting instance');
1424 return false;
1427 $this->settings->{$setting->name} = $setting;
1428 return true;
1431 // see admin_externalpage
1432 function check_access() {
1433 if (!get_site()) {
1434 return true; // no access check before site is fully set up
1436 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1437 foreach($this->req_capability as $cap) {
1438 if (has_capability($cap, $context)) {
1439 return true;
1442 return false;
1446 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1447 * returns a string of the html
1449 function output_html() {
1450 $adminroot =& admin_get_root();
1451 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
1452 foreach($this->settings as $setting) {
1453 $fullname = $setting->get_full_name();
1454 if (array_key_exists($fullname, $adminroot->errors)) {
1455 $data = $adminroot->errors[$fullname]->data;
1456 } else {
1457 $data = $setting->get_setting();
1458 if (is_null($data)) {
1459 $data = $setting->get_defaultsetting();
1462 $return .= $setting->output_html($data);
1464 $return .= '</fieldset>';
1465 return $return;
1469 * Is this settigns page hidden in admin tree block?
1471 * @return bool True if hidden
1473 function is_hidden() {
1474 return $this->hidden;
1481 * Admin settings class. Only exists on setting pages.
1482 * Read & write happens at this level; no authentication.
1484 class admin_setting {
1486 var $name;
1487 var $visiblename;
1488 var $description;
1489 var $defaultsetting;
1490 var $updatedcallback;
1491 var $plugin; // null means main config table
1494 * Constructor
1495 * @param $name string unique ascii name
1496 * @param $visiblename string localised name
1497 * @param strin $description localised long description
1498 * @param mixed $defaultsetting string or array depending on implementation
1500 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1501 $this->name = $name;
1502 $this->visiblename = $visiblename;
1503 $this->description = $description;
1504 $this->defaultsetting = $defaultsetting;
1507 function get_full_name() {
1508 return 's_'.$this->plugin.'_'.$this->name;
1511 function get_id() {
1512 return 'id_s_'.$this->plugin.'_'.$this->name;
1515 function config_read($name) {
1516 global $CFG;
1517 if ($this->plugin === 'backup') {
1518 require_once($CFG->dirroot.'/backup/lib.php');
1519 $backupconfig = backup_get_config();
1520 if (isset($backupconfig->$name)) {
1521 return $backupconfig->$name;
1522 } else {
1523 return NULL;
1526 } else if (!empty($this->plugin)) {
1527 $value = get_config($this->plugin, $name);
1528 return $value === false ? NULL : $value;
1530 } else {
1531 if (isset($CFG->$name)) {
1532 return $CFG->$name;
1533 } else {
1534 return NULL;
1539 function config_write($name, $value) {
1540 global $CFG;
1541 if ($this->plugin === 'backup') {
1542 require_once($CFG->dirroot.'/backup/lib.php');
1543 return (boolean)backup_set_config($name, $value);
1544 } else {
1545 return (boolean)set_config($name, $value, $this->plugin);
1550 * Returns current value of this setting
1551 * @return mixed array or string depending on instance, NULL means not set yet
1553 function get_setting() {
1554 // has to be overridden
1555 return NULL;
1559 * Returns default setting if exists
1560 * @return mixed array or string depending on instance; NULL means no default, user must supply
1562 function get_defaultsetting() {
1563 return $this->defaultsetting;
1567 * Store new setting
1568 * @param mixed string or array, must not be NULL
1569 * @return '' if ok, string error message otherwise
1571 function write_setting($data) {
1572 // should be overridden
1573 return '';
1577 * Return part of form with setting
1578 * @param mixed data array or string depending on setting
1579 * @return string
1581 function output_html($data, $query='') {
1582 // should be overridden
1583 return;
1587 * function called if setting updated - cleanup, cache reset, etc.
1589 function set_updatedcallback($functionname) {
1590 $this->updatedcallback = $functionname;
1594 * Is setting related to query text - used when searching
1595 * @param string $query
1596 * @return bool
1598 function is_related($query) {
1599 if (strpos(strtolower($this->name), $query) !== false) {
1600 return true;
1602 $textlib = textlib_get_instance();
1603 if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1604 return true;
1606 if (strpos($textlib->strtolower($this->description), $query) !== false) {
1607 return true;
1609 $current = $this->get_setting();
1610 if (!is_null($current)) {
1611 if (is_string($current)) {
1612 if (strpos($textlib->strtolower($current), $query) !== false) {
1613 return true;
1617 $default = $this->get_defaultsetting();
1618 if (!is_null($default)) {
1619 if (is_string($default)) {
1620 if (strpos($textlib->strtolower($default), $query) !== false) {
1621 return true;
1625 return false;
1630 * No setting - just heading and text.
1632 class admin_setting_heading extends admin_setting {
1634 * not a setting, just text
1635 * @param string $name of setting
1636 * @param string $heading heading
1637 * @param string $information text in box
1639 function admin_setting_heading($name, $heading, $information) {
1640 parent::admin_setting($name, $heading, $information, '');
1643 function get_setting() {
1644 return true;
1647 function get_defaultsetting() {
1648 return true;
1651 function write_setting($data) {
1652 // do not write any setting
1653 return '';
1656 function output_html($data, $query='') {
1657 $return = '';
1658 if ($this->visiblename != '') {
1659 $return .= print_heading('<a name="'.$this->name.'">'.highlightfast($query, $this->visiblename).'</a>', '', 3, 'main', true);
1661 if ($this->description != '') {
1662 $return .= print_box(highlight($query, $this->description), 'generalbox formsettingheading', '', true);
1664 return $return;
1669 * The most flexibly setting, user is typing text
1671 class admin_setting_configtext extends admin_setting {
1673 var $paramtype;
1674 var $size;
1677 * config text contructor
1678 * @param string $name of setting
1679 * @param string $visiblename localised
1680 * @param string $description long localised info
1681 * @param string $defaultsetting
1682 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
1683 * @param int $size default field size
1685 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
1686 $this->paramtype = $paramtype;
1687 if (!is_null($size)) {
1688 $this->size = $size;
1689 } else {
1690 $this->size = ($paramtype == PARAM_INT) ? 5 : 30;
1692 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1695 function get_setting() {
1696 return $this->config_read($this->name);
1699 function write_setting($data) {
1700 if ($this->paramtype === PARAM_INT and $data === '') {
1701 // do not complain if '' used instead of 0
1702 $data = 0;
1704 // $data is a string
1705 $validated = $this->validate($data);
1706 if ($validated !== true) {
1707 return $validated;
1709 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
1713 * Validate data before storage
1714 * @param string data
1715 * @return mixed true if ok string if error found
1717 function validate($data) {
1718 if (is_string($this->paramtype)) {
1719 if (preg_match($this->paramtype, $data)) {
1720 return true;
1721 } else {
1722 return get_string('validateerror', 'admin');
1725 } else if ($this->paramtype === PARAM_RAW) {
1726 return true;
1728 } else {
1729 $cleaned = stripslashes(clean_param(addslashes($data), $this->paramtype));
1730 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
1731 return true;
1732 } else {
1733 return get_string('validateerror', 'admin');
1738 function output_html($data, $query='') {
1739 $default = $this->get_defaultsetting();
1741 return format_admin_setting($this, $this->visiblename,
1742 '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>',
1743 $this->description, true, '', $default, $query);
1748 * General text area without html editor.
1750 class admin_setting_configtextarea extends admin_setting_configtext {
1751 var $rows;
1752 var $cols;
1754 function admin_setting_configtextarea($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
1755 $this->rows = $rows;
1756 $this->cols = $cols;
1757 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1760 function output_html($data, $query='') {
1761 $default = $this->get_defaultsetting();
1763 $defaultinfo = $default;
1764 if (!is_null($default) and $default !== '') {
1765 $defaultinfo = "\n".$default;
1768 return format_admin_setting($this, $this->visiblename,
1769 '<div class="form-textarea" ><textarea rows="'.$this->rows.'" cols="'.$this->cols.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'">'.s($data).'</textarea></div>',
1770 $this->description, true, '', $defaultinfo, $query);
1775 * Password field, allows unmasking of password
1777 class admin_setting_configpasswordunmask extends admin_setting_configtext {
1779 * Constructor
1780 * @param string $name of setting
1781 * @param string $visiblename localised
1782 * @param string $description long localised info
1783 * @param string $defaultsetting default password
1785 function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting) {
1786 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
1789 function output_html($data, $query='') {
1790 $id = $this->get_id();
1791 $unmask = get_string('unmaskpassword', 'form');
1792 $unmaskjs = '<script type="text/javascript">
1793 //<![CDATA[
1794 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>\');
1795 //]]>
1796 </script>';
1797 return format_admin_setting($this, $this->visiblename,
1798 '<div class="form-password"><input type="password" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$unmaskjs.'</div>',
1799 $this->description, true, '', NULL, $query);
1804 * Path to directory
1806 class admin_setting_configfile extends admin_setting_configtext {
1808 * Constructor
1809 * @param string $name of setting
1810 * @param string $visiblename localised
1811 * @param string $description long localised info
1812 * @param string $defaultdirectory default directory location
1814 function admin_setting_configfile($name, $visiblename, $description, $defaultdirectory) {
1815 parent::admin_setting_configtext($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
1818 function output_html($data, $query='') {
1819 $default = $this->get_defaultsetting();
1821 if ($data) {
1822 if (file_exists($data)) {
1823 $executable = '<span class="pathok">&#x2714;</span>';
1824 } else {
1825 $executable = '<span class="patherror">&#x2718;</span>';
1827 } else {
1828 $executable = '';
1831 return format_admin_setting($this, $this->visiblename,
1832 '<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>',
1833 $this->description, true, '', $default, $query);
1838 * Path to executable file
1840 class admin_setting_configexecutable extends admin_setting_configfile {
1842 function output_html($data, $query='') {
1843 $default = $this->get_defaultsetting();
1845 if ($data) {
1846 if (file_exists($data) and is_executable($data)) {
1847 $executable = '<span class="pathok">&#x2714;</span>';
1848 } else {
1849 $executable = '<span class="patherror">&#x2718;</span>';
1851 } else {
1852 $executable = '';
1855 return format_admin_setting($this, $this->visiblename,
1856 '<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>',
1857 $this->description, true, '', $default, $query);
1862 * Path to directory
1864 class admin_setting_configdirectory extends admin_setting_configfile {
1865 function output_html($data, $query='') {
1866 $default = $this->get_defaultsetting();
1868 if ($data) {
1869 if (file_exists($data) and is_dir($data)) {
1870 $executable = '<span class="pathok">&#x2714;</span>';
1871 } else {
1872 $executable = '<span class="patherror">&#x2718;</span>';
1874 } else {
1875 $executable = '';
1878 return format_admin_setting($this, $this->visiblename,
1879 '<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>',
1880 $this->description, true, '', $default, $query);
1885 * Checkbox
1887 class admin_setting_configcheckbox extends admin_setting {
1888 var $yes;
1889 var $no;
1892 * Constructor
1893 * @param string $name of setting
1894 * @param string $visiblename localised
1895 * @param string $description long localised info
1896 * @param string $defaultsetting
1897 * @param string $yes value used when checked
1898 * @param string $no value used when not checked
1900 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
1901 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1902 $this->yes = (string)$yes;
1903 $this->no = (string)$no;
1906 function get_setting() {
1907 return $this->config_read($this->name);
1910 function write_setting($data) {
1911 if ((string)$data === $this->yes) { // convert to strings before comparison
1912 $data = $this->yes;
1913 } else {
1914 $data = $this->no;
1916 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
1919 function output_html($data, $query='') {
1920 $default = $this->get_defaultsetting();
1922 if (!is_null($default)) {
1923 if ((string)$default === $this->yes) {
1924 $defaultinfo = get_string('checkboxyes', 'admin');
1925 } else {
1926 $defaultinfo = get_string('checkboxno', 'admin');
1928 } else {
1929 $defaultinfo = NULL;
1932 if ((string)$data === $this->yes) { // convert to strings before comparison
1933 $checked = 'checked="checked"';
1934 } else {
1935 $checked = '';
1938 return format_admin_setting($this, $this->visiblename,
1939 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
1940 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
1941 $this->description, true, '', $defaultinfo, $query);
1946 * Multiple checkboxes, each represents different value, stored in csv format
1948 class admin_setting_configmulticheckbox extends admin_setting {
1949 var $choices;
1952 * Constructor
1953 * @param string $name of setting
1954 * @param string $visiblename localised
1955 * @param string $description long localised info
1956 * @param array $defaultsetting array of selected
1957 * @param array $choices array of $value=>$label for each checkbox
1959 function admin_setting_configmulticheckbox($name, $visiblename, $description, $defaultsetting, $choices) {
1960 $this->choices = $choices;
1961 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1965 * This function may be used in ancestors for lazy loading of choices
1966 * @return true if loaded, false if error
1968 function load_choices() {
1970 if (is_array($this->choices)) {
1971 return true;
1973 .... load choices here
1975 return true;
1979 * Is setting related to query text - used when searching
1980 * @param string $query
1981 * @return bool
1983 function is_related($query) {
1984 if (!$this->load_choices() or empty($this->choices)) {
1985 return false;
1987 if (parent::is_related($query)) {
1988 return true;
1991 $textlib = textlib_get_instance();
1992 foreach ($this->choices as $desc) {
1993 if (strpos($textlib->strtolower($desc), $query) !== false) {
1994 return true;
1997 return false;
2000 function get_setting() {
2001 $result = $this->config_read($this->name);
2002 if (is_null($result)) {
2003 return NULL;
2005 if ($result === '') {
2006 return array();
2008 return explode(',', $result);
2011 function write_setting($data) {
2012 if (!is_array($data)) {
2013 return ''; // ignore it
2015 if (!$this->load_choices() or empty($this->choices)) {
2016 return '';
2018 unset($data['xxxxx']);
2019 $result = array();
2020 foreach ($data as $key => $value) {
2021 if ($value and array_key_exists($key, $this->choices)) {
2022 $result[] = $key;
2025 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
2028 function output_html($data, $query='') {
2029 if (!$this->load_choices() or empty($this->choices)) {
2030 return '';
2032 $default = $this->get_defaultsetting();
2033 if (is_null($default)) {
2034 $default = array();
2036 if (is_null($data)) {
2037 foreach ($default as $key=>$value) {
2038 if ($value) {
2039 $current[] = $value;
2044 $options = array();
2045 $defaults = array();
2046 foreach($this->choices as $key=>$description) {
2047 if (in_array($key, $data)) {
2048 $checked = 'checked="checked"';
2049 } else {
2050 $checked = '';
2052 if (!empty($default[$key])) {
2053 $defaults[] = $description;
2056 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
2057 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
2060 if (is_null($default)) {
2061 $defaultinfo = NULL;
2062 } else if (!empty($defaults)) {
2063 $defaultinfo = implode(', ', $defaults);
2064 } else {
2065 $defaultinfo = get_string('none');
2068 $return = '<div class="form-multicheckbox">';
2069 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2070 if ($options) {
2071 $return .= '<ul>';
2072 foreach ($options as $option) {
2073 $return .= '<li>'.$option.'</li>';
2075 $return .= '</ul>';
2077 $return .= '</div>';
2079 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2085 * Multiple checkboxes 2, value stored as string 00101011
2087 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
2088 function get_setting() {
2089 $result = $this->config_read($this->name);
2090 if (is_null($result)) {
2091 return NULL;
2093 if (!$this->load_choices()) {
2094 return NULL;
2096 $result = str_pad($result, count($this->choices), '0');
2097 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2098 $setting = array();
2099 foreach ($this->choices as $key=>$unused) {
2100 $value = array_shift($result);
2101 if ($value) {
2102 $setting[] = $key;
2105 return $setting;
2108 function write_setting($data) {
2109 if (!is_array($data)) {
2110 return ''; // ignore it
2112 if (!$this->load_choices() or empty($this->choices)) {
2113 return '';
2115 $result = '';
2116 foreach ($this->choices as $key=>$unused) {
2117 if (!empty($data[$key])) {
2118 $result .= '1';
2119 } else {
2120 $result .= '0';
2123 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
2128 * Select one value from list
2130 class admin_setting_configselect extends admin_setting {
2131 var $choices;
2134 * Constructor
2135 * @param string $name of setting
2136 * @param string $visiblename localised
2137 * @param string $description long localised info
2138 * @param string $defaultsetting
2139 * @param array $choices array of $value=>$label for each selection
2141 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
2142 $this->choices = $choices;
2143 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
2147 * This function may be used in ancestors for lazy loading of choices
2148 * @return true if loaded, false if error
2150 function load_choices() {
2152 if (is_array($this->choices)) {
2153 return true;
2155 .... load choices here
2157 return true;
2160 function is_related($query) {
2161 if (parent::is_related($query)) {
2162 return true;
2164 if (!$this->load_choices()) {
2165 return false;
2167 $textlib = textlib_get_instance();
2168 foreach ($this->choices as $key=>$value) {
2169 if (strpos($textlib->strtolower($key), $query) !== false) {
2170 return true;
2172 if (strpos($textlib->strtolower($value), $query) !== false) {
2173 return true;
2176 return false;
2179 function get_setting() {
2180 return $this->config_read($this->name);
2183 function write_setting($data) {
2184 if (!$this->load_choices() or empty($this->choices)) {
2185 return '';
2187 if (!array_key_exists($data, $this->choices)) {
2188 return ''; // ignore it
2191 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2194 function output_html($data, $query='') {
2195 if (!$this->load_choices() or empty($this->choices)) {
2196 return '';
2198 $default = $this->get_defaultsetting();
2200 if (!is_null($default) and array_key_exists($default, $this->choices)) {
2201 $defaultinfo = $this->choices[$default];
2202 } else {
2203 $defaultinfo = NULL;
2206 $current = $this->get_setting();
2207 $warning = '';
2208 if (is_null($current)) {
2209 //first run
2210 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
2211 // no warning
2212 } else if (!array_key_exists($current, $this->choices)) {
2213 $warning = get_string('warningcurrentsetting', 'admin', s($current));
2214 if (!is_null($default) and $data==$current) {
2215 $data = $default; // use default instead of first value when showing the form
2219 $return = '<div class="form-select defaultsnext"><select id="'.$this->get_id().'" name="'.$this->get_full_name().'">';
2220 foreach ($this->choices as $key => $value) {
2221 // the string cast is needed because key may be integer - 0 is equal to most strings!
2222 $return .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
2224 $return .= '</select></div>';
2226 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
2232 * Select multiple items from list
2234 class admin_setting_configmultiselect extends admin_setting_configselect {
2236 * Constructor
2237 * @param string $name of setting
2238 * @param string $visiblename localised
2239 * @param string $description long localised info
2240 * @param array $defaultsetting array of selected items
2241 * @param array $choices array of $value=>$label for each list item
2243 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
2244 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
2247 function get_setting() {
2248 $result = $this->config_read($this->name);
2249 if (is_null($result)) {
2250 return NULL;
2252 if ($result === '') {
2253 return array();
2255 return explode(',', $result);
2258 function write_setting($data) {
2259 if (!is_array($data)) {
2260 return ''; //ignore it
2262 if (!$this->load_choices() or empty($this->choices)) {
2263 return '';
2266 unset($data['xxxxx']);
2268 $save = array();
2269 foreach ($data as $value) {
2270 if (!array_key_exists($value, $this->choices)) {
2271 continue; // ignore it
2273 $save[] = $value;
2276 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2280 * Is setting related to query text - used when searching
2281 * @param string $query
2282 * @return bool
2284 function is_related($query) {
2285 if (!$this->load_choices() or empty($this->choices)) {
2286 return false;
2288 if (parent::is_related($query)) {
2289 return true;
2292 $textlib = textlib_get_instance();
2293 foreach ($this->choices as $desc) {
2294 if (strpos($textlib->strtolower($desc), $query) !== false) {
2295 return true;
2298 return false;
2301 function output_html($data, $query='') {
2302 if (!$this->load_choices() or empty($this->choices)) {
2303 return '';
2305 $choices = $this->choices;
2306 $default = $this->get_defaultsetting();
2307 if (is_null($default)) {
2308 $default = array();
2310 if (is_null($data)) {
2311 $data = array();
2314 $defaults = array();
2315 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2316 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="10" multiple="multiple">';
2317 foreach ($this->choices as $key => $description) {
2318 if (in_array($key, $data)) {
2319 $selected = 'selected="selected"';
2320 } else {
2321 $selected = '';
2323 if (in_array($key, $default)) {
2324 $defaults[] = $description;
2327 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
2330 if (is_null($default)) {
2331 $defaultinfo = NULL;
2332 } if (!empty($defaults)) {
2333 $defaultinfo = implode(', ', $defaults);
2334 } else {
2335 $defaultinfo = get_string('none');
2338 $return .= '</select></div>';
2339 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
2344 * Time selector
2345 * this is a liiitle bit messy. we're using two selects, but we're returning
2346 * them as an array named after $name (so we only use $name2 internally for the setting)
2348 class admin_setting_configtime extends admin_setting {
2349 var $name2;
2352 * Constructor
2353 * @param string $hoursname setting for hours
2354 * @param string $minutesname setting for hours
2355 * @param string $visiblename localised
2356 * @param string $description long localised info
2357 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
2359 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
2360 $this->name2 = $minutesname;
2361 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
2364 function get_setting() {
2365 $result1 = $this->config_read($this->name);
2366 $result2 = $this->config_read($this->name2);
2367 if (is_null($result1) or is_null($result2)) {
2368 return NULL;
2371 return array('h' => $result1, 'm' => $result2);
2374 function write_setting($data) {
2375 if (!is_array($data)) {
2376 return '';
2379 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
2380 return ($result ? '' : get_string('errorsetting', 'admin'));
2383 function output_html($data, $query='') {
2384 $default = $this->get_defaultsetting();
2386 if (is_array($default)) {
2387 $defaultinfo = $default['h'].':'.$default['m'];
2388 } else {
2389 $defaultinfo = NULL;
2392 $return = '<div class="form-time defaultsnext">'.
2393 '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
2394 for ($i = 0; $i < 24; $i++) {
2395 $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2397 $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
2398 for ($i = 0; $i < 60; $i += 5) {
2399 $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2401 $return .= '</select></div>';
2402 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2408 * Special checkbox for calendar - resets SESSION vars.
2410 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
2411 function admin_setting_special_adminseesall() {
2412 parent::admin_setting_configcheckbox('calendar_adminseesall', get_string('adminseesall', 'admin'),
2413 get_string('helpadminseesall', 'admin'), '0');
2416 function write_setting($data) {
2417 global $SESSION;
2418 unset($SESSION->cal_courses_shown);
2419 return parent::write_setting($data);
2424 * Special select for settings that are altered in setup.php and can not be altered on the fly
2426 class admin_setting_special_selectsetup extends admin_setting_configselect {
2427 function get_setting() {
2428 // read directly from db!
2429 return get_config(NULL, $this->name);
2432 function write_setting($data) {
2433 global $CFG;
2434 // do not change active CFG setting!
2435 $current = $CFG->{$this->name};
2436 $result = parent::write_setting($data);
2437 $CFG->{$this->name} = $current;
2438 return $result;
2443 * Special select for frontpage - stores data in course table
2445 class admin_setting_sitesetselect extends admin_setting_configselect {
2446 function get_setting() {
2447 $site = get_site();
2448 return $site->{$this->name};
2451 function write_setting($data) {
2452 if (!in_array($data, array_keys($this->choices))) {
2453 return get_string('errorsetting', 'admin');
2455 $record = new stdClass();
2456 $record->id = SITEID;
2457 $temp = $this->name;
2458 $record->$temp = $data;
2459 $record->timemodified = time();
2460 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2465 * Special select - lists on the frontpage - hacky
2467 class admin_setting_courselist_frontpage extends admin_setting {
2468 var $choices;
2470 function admin_setting_courselist_frontpage($loggedin) {
2471 global $CFG;
2472 require_once($CFG->dirroot.'/course/lib.php');
2473 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
2474 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
2475 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
2476 $defaults = array(FRONTPAGECOURSELIST);
2477 parent::admin_setting($name, $visiblename, $description, $defaults);
2480 function load_choices() {
2481 if (is_array($this->choices)) {
2482 return true;
2484 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
2485 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
2486 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
2487 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
2488 'none' => get_string('none'));
2489 if ($this->name == 'frontpage' and count_records('course') > FRONTPAGECOURSELIMIT) {
2490 unset($this->choices[FRONTPAGECOURSELIST]);
2492 return true;
2494 function get_setting() {
2495 $result = $this->config_read($this->name);
2496 if (is_null($result)) {
2497 return NULL;
2499 if ($result === '') {
2500 return array();
2502 return explode(',', $result);
2505 function write_setting($data) {
2506 if (!is_array($data)) {
2507 return '';
2509 $this->load_choices();
2510 $save = array();
2511 foreach($data as $datum) {
2512 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
2513 continue;
2515 $save[$datum] = $datum; // no duplicates
2517 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2520 function output_html($data, $query='') {
2521 $this->load_choices();
2522 $currentsetting = array();
2523 foreach ($data as $key) {
2524 if ($key != 'none' and array_key_exists($key, $this->choices)) {
2525 $currentsetting[] = $key; // already selected first
2529 $return = '<div class="form-group">';
2530 for ($i = 0; $i < count($this->choices) - 1; $i++) {
2531 if (!array_key_exists($i, $currentsetting)) {
2532 $currentsetting[$i] = 'none'; //none
2534 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
2535 foreach ($this->choices as $key => $value) {
2536 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
2538 $return .= '</select>';
2539 if ($i !== count($this->choices) - 2) {
2540 $return .= '<br />';
2543 $return .= '</div>';
2545 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2550 * Special checkbox for frontpage - stores data in course table
2552 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
2553 function get_setting() {
2554 $site = get_site();
2555 return $site->{$this->name};
2558 function write_setting($data) {
2559 $record = new object();
2560 $record->id = SITEID;
2561 $record->{$this->name} = ($data == '1' ? 1 : 0);
2562 $record->timemodified = time();
2563 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2568 * Special text for frontpage - stores data in course table.
2569 * Empty string means not set here. Manual setting is required.
2571 class admin_setting_sitesettext extends admin_setting_configtext {
2572 function get_setting() {
2573 $site = get_site();
2574 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
2577 function validate($data) {
2578 $cleaned = stripslashes(clean_param(addslashes($data), PARAM_MULTILANG));
2579 if ($cleaned === '') {
2580 return get_string('required');
2582 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
2583 return true;
2584 } else {
2585 return get_string('validateerror', 'admin');
2589 function write_setting($data) {
2590 $data = trim($data);
2591 $validated = $this->validate($data);
2592 if ($validated !== true) {
2593 return $validated;
2596 $record = new object();
2597 $record->id = SITEID;
2598 $record->{$this->name} = addslashes($data);
2599 $record->timemodified = time();
2600 return (update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
2605 * Special text editor for site description.
2607 class admin_setting_special_frontpagedesc extends admin_setting {
2608 function admin_setting_special_frontpagedesc() {
2609 parent::admin_setting('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
2612 function get_setting() {
2613 $site = get_site();
2614 return $site->{$this->name};
2617 function write_setting($data) {
2618 $record = new object();
2619 $record->id = SITEID;
2620 $record->{$this->name} = addslashes($data);
2621 $record->timemodified = time();
2622 return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2625 function output_html($data, $query='') {
2626 global $CFG;
2628 $CFG->adminusehtmleditor = can_use_html_editor();
2629 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true).'</div>';
2631 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2635 class admin_setting_special_editorfontlist extends admin_setting {
2637 var $items;
2639 function admin_setting_special_editorfontlist() {
2640 global $CFG;
2641 $name = 'editorfontlist';
2642 $visiblename = get_string('editorfontlist', 'admin');
2643 $description = get_string('configeditorfontlist', 'admin');
2644 $defaults = array('k0' => 'Trebuchet',
2645 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
2646 'k1' => 'Arial',
2647 'v1' => 'arial,helvetica,sans-serif',
2648 'k2' => 'Courier New',
2649 'v2' => 'courier new,courier,monospace',
2650 'k3' => 'Georgia',
2651 'v3' => 'georgia,times new roman,times,serif',
2652 'k4' => 'Tahoma',
2653 'v4' => 'tahoma,arial,helvetica,sans-serif',
2654 'k5' => 'Times New Roman',
2655 'v5' => 'times new roman,times,serif',
2656 'k6' => 'Verdana',
2657 'v6' => 'verdana,arial,helvetica,sans-serif',
2658 'k7' => 'Impact',
2659 'v7' => 'impact',
2660 'k8' => 'Wingdings',
2661 'v8' => 'wingdings');
2662 parent::admin_setting($name, $visiblename, $description, $defaults);
2665 function get_setting() {
2666 global $CFG;
2667 $result = $this->config_read($this->name);
2668 if (is_null($result)) {
2669 return NULL;
2671 $i = 0;
2672 $currentsetting = array();
2673 $items = explode(';', $result);
2674 foreach ($items as $item) {
2675 $item = explode(':', $item);
2676 $currentsetting['k'.$i] = $item[0];
2677 $currentsetting['v'.$i] = $item[1];
2678 $i++;
2680 return $currentsetting;
2683 function write_setting($data) {
2685 // there miiight be an easier way to do this :)
2686 // if this is changed, make sure the $defaults array above is modified so that this
2687 // function processes it correctly
2689 $keys = array();
2690 $values = array();
2692 foreach ($data as $key => $value) {
2693 if (substr($key,0,1) == 'k') {
2694 $keys[substr($key,1)] = $value;
2695 } elseif (substr($key,0,1) == 'v') {
2696 $values[substr($key,1)] = $value;
2700 $result = array();
2701 for ($i = 0; $i < count($keys); $i++) {
2702 if (($keys[$i] !== '') && ($values[$i] !== '')) {
2703 $result[] = clean_param($keys[$i],PARAM_NOTAGS).':'.clean_param($values[$i], PARAM_NOTAGS);
2707 return ($this->config_write($this->name, implode(';', $result)) ? '' : get_string('errorsetting', 'admin'));
2710 function output_html($data, $query='') {
2711 $fullname = $this->get_full_name();
2712 $return = '<div class="form-group">';
2713 for ($i = 0; $i < count($data) / 2; $i++) {
2714 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
2715 $return .= '&nbsp;&nbsp;';
2716 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
2718 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
2719 $return .= '&nbsp;&nbsp;';
2720 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2721 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
2722 $return .= '&nbsp;&nbsp;';
2723 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
2724 $return .= '</div>';
2726 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2731 class admin_setting_emoticons extends admin_setting {
2733 var $items;
2735 function admin_setting_emoticons() {
2736 global $CFG;
2737 $name = 'emoticons';
2738 $visiblename = get_string('emoticons', 'admin');
2739 $description = get_string('configemoticons', 'admin');
2740 $defaults = array('k0' => ':-)',
2741 'v0' => 'smiley',
2742 'k1' => ':)',
2743 'v1' => 'smiley',
2744 'k2' => ':-D',
2745 'v2' => 'biggrin',
2746 'k3' => ';-)',
2747 'v3' => 'wink',
2748 'k4' => ':-/',
2749 'v4' => 'mixed',
2750 'k5' => 'V-.',
2751 'v5' => 'thoughtful',
2752 'k6' => ':-P',
2753 'v6' => 'tongueout',
2754 'k7' => 'B-)',
2755 'v7' => 'cool',
2756 'k8' => '^-)',
2757 'v8' => 'approve',
2758 'k9' => '8-)',
2759 'v9' => 'wideeyes',
2760 'k10' => ':o)',
2761 'v10' => 'clown',
2762 'k11' => ':-(',
2763 'v11' => 'sad',
2764 'k12' => ':(',
2765 'v12' => 'sad',
2766 'k13' => '8-.',
2767 'v13' => 'shy',
2768 'k14' => ':-I',
2769 'v14' => 'blush',
2770 'k15' => ':-X',
2771 'v15' => 'kiss',
2772 'k16' => '8-o',
2773 'v16' => 'surprise',
2774 'k17' => 'P-|',
2775 'v17' => 'blackeye',
2776 'k18' => '8-[',
2777 'v18' => 'angry',
2778 'k19' => 'xx-P',
2779 'v19' => 'dead',
2780 'k20' => '|-.',
2781 'v20' => 'sleepy',
2782 'k21' => '}-]',
2783 'v21' => 'evil',
2784 'k22' => '(h)',
2785 'v22' => 'heart',
2786 'k23' => '(heart)',
2787 'v23' => 'heart',
2788 'k24' => '(y)',
2789 'v24' => 'yes',
2790 'k25' => '(n)',
2791 'v25' => 'no',
2792 'k26' => '(martin)',
2793 'v26' => 'martin',
2794 'k27' => '( )',
2795 'v27' => 'egg');
2796 parent::admin_setting($name, $visiblename, $description, $defaults);
2799 function get_setting() {
2800 global $CFG;
2801 $result = $this->config_read($this->name);
2802 if (is_null($result)) {
2803 return NULL;
2805 $i = 0;
2806 $currentsetting = array();
2807 $items = explode('{;}', $result);
2808 foreach ($items as $item) {
2809 $item = explode('{:}', $item);
2810 $currentsetting['k'.$i] = $item[0];
2811 $currentsetting['v'.$i] = $item[1];
2812 $i++;
2814 return $currentsetting;
2817 function write_setting($data) {
2819 // there miiight be an easier way to do this :)
2820 // if this is changed, make sure the $defaults array above is modified so that this
2821 // function processes it correctly
2823 $keys = array();
2824 $values = array();
2826 foreach ($data as $key => $value) {
2827 if (substr($key,0,1) == 'k') {
2828 $keys[substr($key,1)] = $value;
2829 } elseif (substr($key,0,1) == 'v') {
2830 $values[substr($key,1)] = $value;
2834 $result = array();
2835 for ($i = 0; $i < count($keys); $i++) {
2836 if (($keys[$i] !== '') && ($values[$i] !== '')) {
2837 $result[] = clean_param($keys[$i],PARAM_NOTAGS).'{:}'.clean_param($values[$i], PARAM_NOTAGS);
2841 return ($this->config_write($this->name, implode('{;}', $result)) ? '' : get_string('errorsetting', 'admin').$this->visiblename.'<br />');
2844 function output_html($data, $query='') {
2845 $fullname = $this->get_full_name();
2846 $return = '<div class="form-group">';
2847 for ($i = 0; $i < count($data) / 2; $i++) {
2848 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
2849 $return .= '&nbsp;&nbsp;';
2850 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
2852 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
2853 $return .= '&nbsp;&nbsp;';
2854 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
2855 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
2856 $return .= '&nbsp;&nbsp;';
2857 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
2858 $return .= '</div>';
2860 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
2866 * Setting for spellchecker language selection.
2868 class admin_setting_special_editordictionary extends admin_setting_configselect {
2870 function admin_setting_special_editordictionary() {
2871 $name = 'editordictionary';
2872 $visiblename = get_string('editordictionary','admin');
2873 $description = get_string('configeditordictionary', 'admin');
2874 parent::admin_setting_configselect($name, $visiblename, $description, '', NULL);
2877 function load_choices() {
2878 // function borrowed from the old moodle/admin/editor.php, slightly modified
2879 // Get all installed dictionaries in the system
2880 if (is_array($this->choices)) {
2881 return true;
2884 $this->choices = array();
2886 global $CFG;
2888 clearstatcache();
2890 // If aspellpath isn't set don't even bother ;-)
2891 if (empty($CFG->aspellpath)) {
2892 $this->choices['error'] = 'Empty aspell path!';
2893 return true;
2896 // Do we have access to popen function?
2897 if (!function_exists('popen')) {
2898 $this->choices['error'] = 'Popen function disabled!';
2899 return true;
2902 $cmd = $CFG->aspellpath;
2903 $output = '';
2904 $dictionaries = array();
2906 if(!($handle = @popen(escapeshellarg($cmd).' dump dicts', 'r'))) {
2907 $this->choices['error'] = 'Couldn\'t create handle!';
2910 while(!feof($handle)) {
2911 $output .= fread($handle, 1024);
2913 @pclose($handle);
2915 $dictionaries = explode(chr(10), $output);
2916 foreach ($dictionaries as $dict) {
2917 if (empty($dict)) {
2918 continue;
2920 $this->choices[$dict] = $dict;
2923 if (empty($this->choices)) {
2924 $this->choices['error'] = 'Error! Check your aspell installation!';
2926 return true;
2931 class admin_setting_special_editorhidebuttons extends admin_setting {
2932 var $items;
2934 function admin_setting_special_editorhidebuttons() {
2935 parent::admin_setting('editorhidebuttons', get_string('editorhidebuttons', 'admin'),
2936 get_string('confeditorhidebuttons', 'admin'), array());
2937 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
2938 $this->items = array('fontname' => '',
2939 'fontsize' => '',
2940 'formatblock' => '',
2941 'bold' => 'ed_format_bold.gif',
2942 'italic' => 'ed_format_italic.gif',
2943 'underline' => 'ed_format_underline.gif',
2944 'strikethrough' => 'ed_format_strike.gif',
2945 'subscript' => 'ed_format_sub.gif',
2946 'superscript' => 'ed_format_sup.gif',
2947 'copy' => 'ed_copy.gif',
2948 'cut' => 'ed_cut.gif',
2949 'paste' => 'ed_paste.gif',
2950 'clean' => 'ed_wordclean.gif',
2951 'undo' => 'ed_undo.gif',
2952 'redo' => 'ed_redo.gif',
2953 'justifyleft' => 'ed_align_left.gif',
2954 'justifycenter' => 'ed_align_center.gif',
2955 'justifyright' => 'ed_align_right.gif',
2956 'justifyfull' => 'ed_align_justify.gif',
2957 'lefttoright' => 'ed_left_to_right.gif',
2958 'righttoleft' => 'ed_right_to_left.gif',
2959 'insertorderedlist' => 'ed_list_num.gif',
2960 'insertunorderedlist' => 'ed_list_bullet.gif',
2961 'outdent' => 'ed_indent_less.gif',
2962 'indent' => 'ed_indent_more.gif',
2963 'forecolor' => 'ed_color_fg.gif',
2964 'hilitecolor' => 'ed_color_bg.gif',
2965 'inserthorizontalrule' => 'ed_hr.gif',
2966 'createanchor' => 'ed_anchor.gif',
2967 'createlink' => 'ed_link.gif',
2968 'unlink' => 'ed_unlink.gif',
2969 'insertimage' => 'ed_image.gif',
2970 'inserttable' => 'insert_table.gif',
2971 'insertsmile' => 'em.icon.smile.gif',
2972 'insertchar' => 'icon_ins_char.gif',
2973 'spellcheck' => 'spell-check.gif',
2974 'htmlmode' => 'ed_html.gif',
2975 'popupeditor' => 'fullscreen_maximize.gif',
2976 'search_replace' => 'ed_replace.gif');
2979 function get_setting() {
2980 $result = $this->config_read($this->name);
2981 if (is_null($result)) {
2982 return NULL;
2984 if ($result === '') {
2985 return array();
2987 return explode(' ', $result);
2990 function write_setting($data) {
2991 if (!is_array($data)) {
2992 return ''; // ignore it
2994 unset($data['xxxxx']);
2995 $result = array();
2997 foreach ($data as $key => $value) {
2998 if (!isset($this->items[$key])) {
2999 return get_string('errorsetting', 'admin');
3001 if ($value == '1') {
3002 $result[] = $key;
3005 return ($this->config_write($this->name, implode(' ', $result)) ? '' : get_string('errorsetting', 'admin'));
3008 function output_html($data, $query='') {
3010 global $CFG;
3012 // checkboxes with input name="$this->name[$key]" value="1"
3013 // we do 15 fields per column
3015 $return = '<div class="form-group">';
3016 $return .= '<table><tr><td valign="top" align="right">';
3017 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3019 $count = 0;
3021 foreach($this->items as $key => $value) {
3022 if ($count % 15 == 0 and $count != 0) {
3023 $return .= '</td><td valign="top" align="right">';
3026 $return .= '<label for="'.$this->get_id().$key.'">';
3027 $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;';
3028 $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;';
3029 $return .= '</label>';
3030 $count++;
3031 if ($count % 15 != 0) {
3032 $return .= '<br /><br />';
3036 $return .= '</td></tr>';
3037 $return .= '</table>';
3038 $return .= '</div>';
3040 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3045 * Special setting for limiting of the list of available languages.
3047 class admin_setting_langlist extends admin_setting_configtext {
3048 function admin_setting_langlist() {
3049 parent::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
3052 function write_setting($data) {
3053 $return = parent::write_setting($data);
3054 get_list_of_languages(true);//refresh the list
3055 return $return;
3060 * Course category selection
3062 class admin_settings_coursecat_select extends admin_setting_configselect {
3063 function admin_settings_coursecat_select($name, $visiblename, $description, $defaultsetting) {
3064 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, NULL);
3067 function load_choices() {
3068 global $CFG;
3069 require_once($CFG->dirroot.'/course/lib.php');
3070 if (is_array($this->choices)) {
3071 return true;
3073 $this->choices = make_categories_options();
3074 return true;
3078 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
3079 function admin_setting_special_backupdays() {
3080 parent::admin_setting_configmulticheckbox2('backup_sche_weekdays', get_string('schedule'), get_string('backupschedulehelp'), array(), NULL);
3081 $this->plugin = 'backup';
3084 function load_choices() {
3085 if (is_array($this->choices)) {
3086 return true;
3088 $this->choices = array();
3089 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3090 foreach ($days as $day) {
3091 $this->choices[$day] = get_string($day, 'calendar');
3093 return true;
3098 * Special debug setting
3100 class admin_setting_special_debug extends admin_setting_configselect {
3101 function admin_setting_special_debug() {
3102 parent::admin_setting_configselect('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
3105 function load_choices() {
3106 if (is_array($this->choices)) {
3107 return true;
3109 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
3110 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
3111 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
3112 DEBUG_ALL => get_string('debugall', 'admin'),
3113 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
3114 return true;
3119 class admin_setting_special_calendar_weekend extends admin_setting {
3120 function admin_setting_special_calendar_weekend() {
3121 $name = 'calendar_weekend';
3122 $visiblename = get_string('calendar_weekend', 'admin');
3123 $description = get_string('helpweekenddays', 'admin');
3124 $default = array ('0', '6'); // Saturdays and Sundays
3125 parent::admin_setting($name, $visiblename, $description, $default);
3128 function get_setting() {
3129 $result = $this->config_read($this->name);
3130 if (is_null($result)) {
3131 return NULL;
3133 if ($result === '') {
3134 return array();
3136 $settings = array();
3137 for ($i=0; $i<7; $i++) {
3138 if ($result & (1 << $i)) {
3139 $setting[] = $i;
3142 return $setting;
3145 function write_setting($data) {
3146 if (!is_array($data)) {
3147 return '';
3149 unset($data['xxxxx']);
3150 $result = 0;
3151 foreach($data as $index) {
3152 $result |= 1 << $index;
3154 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
3157 function output_html($data, $query='') {
3158 // The order matters very much because of the implied numeric keys
3159 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3160 $return = '<table><thead><tr>';
3161 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3162 foreach($days as $index => $day) {
3163 $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>';
3165 $return .= '</tr></thead><tbody><tr>';
3166 foreach($days as $index => $day) {
3167 $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>';
3169 $return .= '</tr></tbody></table>';
3171 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3178 * Graded roles in gradebook
3180 class admin_setting_special_gradebookroles extends admin_setting_configmulticheckbox {
3181 function admin_setting_special_gradebookroles() {
3182 parent::admin_setting_configmulticheckbox('gradebookroles', get_string('gradebookroles', 'admin'),
3183 get_string('configgradebookroles', 'admin'), NULL, NULL);
3186 function load_choices() {
3187 global $CFG;
3188 if (empty($CFG->rolesactive)) {
3189 return false;
3191 if (is_array($this->choices)) {
3192 return true;
3194 if ($roles = get_records('role')) {
3195 $this->choices = array();
3196 foreach($roles as $role) {
3197 $this->choices[$role->id] = format_string($role->name);
3199 return true;
3200 } else {
3201 return false;
3205 function get_defaultsetting() {
3206 global $CFG;
3207 if (empty($CFG->rolesactive)) {
3208 return NULL;
3210 $result = array();
3211 if ($studentroles = get_roles_with_capability('moodle/legacy:student', CAP_ALLOW)) {
3212 foreach ($studentroles as $studentrole) {
3213 $result[$studentrole->id] = '1';
3216 return $result;
3220 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
3221 function write_setting($data) {
3222 global $CFG;
3224 $oldvalue = $this->config_read($this->name);
3225 $return = parent::write_setting($data);
3226 $newvalue = $this->config_read($this->name);
3228 if ($oldvalue !== $newvalue) {
3229 // force full regrading
3230 set_field('grade_items', 'needsupdate', 1, 'needsupdate', 0);
3233 return $return;
3238 * Which roles to show on course decription page
3240 class admin_setting_special_coursemanager extends admin_setting_configmulticheckbox {
3241 function admin_setting_special_coursemanager() {
3242 parent::admin_setting_configmulticheckbox('coursemanager', get_string('coursemanager', 'admin'),
3243 get_string('configcoursemanager', 'admin'), NULL, NULL);
3246 function load_choices() {
3247 if (is_array($this->choices)) {
3248 return true;
3250 if ($roles = get_records('role','','','sortorder')) {
3251 $this->choices = array();
3252 foreach($roles as $role) {
3253 $this->choices[$role->id] = format_string($role->name);
3255 return true;
3257 return false;
3260 function get_defaultsetting() {
3261 global $CFG;
3262 if (empty($CFG->rolesactive)) {
3263 return NULL;
3265 $result = array();
3266 if ($teacherroles = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW)) {
3267 foreach ($teacherroles as $teacherrole) {
3268 $result[$teacherrole->id] = '1';
3271 return $result;
3276 * Primary grade export plugin - has state tracking.
3278 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
3279 function admin_setting_special_gradeexport() {
3280 parent::admin_setting_configmulticheckbox('gradeexport', get_string('gradeexport', 'admin'),
3281 get_string('configgradeexport', 'admin'), array(), NULL);
3284 function load_choices() {
3285 if (is_array($this->choices)) {
3286 return true;
3288 $this->choices = array();
3290 if ($plugins = get_list_of_plugins('grade/export')) {
3291 foreach($plugins as $plugin) {
3292 $this->choices[$plugin] = get_string('modulename', 'gradeexport_'.$plugin);
3295 return true;
3300 * Grade category settings
3302 class admin_setting_gradecat_combo extends admin_setting {
3304 var $choices;
3306 function admin_setting_gradecat_combo($name, $visiblename, $description, $defaultsetting, $choices) {
3307 $this->choices = $choices;
3308 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
3311 function get_setting() {
3312 global $CFG;
3314 $value = $this->config_read($this->name);
3315 $flag = $this->config_read($this->name.'_flag');
3317 if (is_null($value) or is_null($flag)) {
3318 return NULL;
3321 $flag = (int)$flag;
3322 $forced = (boolean)(1 & $flag); // first bit
3323 $adv = (boolean)(2 & $flag); // second bit
3325 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
3328 function write_setting($data) {
3329 global $CFG;
3331 $value = $data['value'];
3332 $forced = empty($data['forced']) ? 0 : 1;
3333 $adv = empty($data['adv']) ? 0 : 2;
3334 $flag = ($forced | $adv); //bitwise or
3336 if (!in_array($value, array_keys($this->choices))) {
3337 return 'Error setting ';
3340 $oldvalue = $this->config_read($this->name);
3341 $oldflag = (int)$this->config_read($this->name.'_flag');
3342 $oldforced = (1 & $oldflag); // first bit
3344 $result1 = $this->config_write($this->name, $value);
3345 $result2 = $this->config_write($this->name.'_flag', $flag);
3347 // force regrade if needed
3348 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
3349 require_once($CFG->libdir.'/gradelib.php');
3350 grade_category::updated_forced_settings();
3353 if ($result1 and $result2) {
3354 return '';
3355 } else {
3356 return get_string('errorsetting', 'admin');
3360 function output_html($data, $query='') {
3361 $value = $data['value'];
3362 $forced = !empty($data['forced']);
3363 $adv = !empty($data['adv']);
3365 $default = $this->get_defaultsetting();
3366 if (!is_null($default)) {
3367 $defaultinfo = array();
3368 if (isset($this->choices[$default['value']])) {
3369 $defaultinfo[] = $this->choices[$default['value']];
3371 if (!empty($default['forced'])) {
3372 $defaultinfo[] = get_string('force');
3374 if (!empty($default['adv'])) {
3375 $defaultinfo[] = get_string('advanced');
3377 $defaultinfo = implode(', ', $defaultinfo);
3379 } else {
3380 $defaultinfo = NULL;
3384 $return = '<div class="form-group">';
3385 $return .= '<select class="form-select" id="'.$this->get_id().'" name="'.$this->get_full_name().'[value]">';
3386 foreach ($this->choices as $key => $val) {
3387 // the string cast is needed because key may be integer - 0 is equal to most strings!
3388 $return .= '<option value="'.$key.'"'.((string)$key==$value ? ' selected="selected"' : '').'>'.$val.'</option>';
3390 $return .= '</select>';
3391 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'force" name="'.$this->get_full_name().'[forced]" value="1" '.($forced ? 'checked="checked"' : '').' />'
3392 .'<label for="'.$this->get_id().'force">'.get_string('force').'</label>';
3393 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'adv" name="'.$this->get_full_name().'[adv]" value="1" '.($adv ? 'checked="checked"' : '').' />'
3394 .'<label for="'.$this->get_id().'adv">'.get_string('advanced').'</label>';
3395 $return .= '</div>';
3397 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
3403 * Selection of grade report in user profiles
3405 class admin_setting_grade_profilereport extends admin_setting_configselect {
3406 function admin_setting_grade_profilereport() {
3407 parent::admin_setting_configselect('grade_profilereport', get_string('profilereport', 'grades'), get_string('configprofilereport', 'grades'), 'user', null);
3410 function load_choices() {
3411 if (is_array($this->choices)) {
3412 return true;
3414 $this->choices = array();
3416 global $CFG;
3417 require_once($CFG->libdir.'/gradelib.php');
3419 foreach (get_list_of_plugins('grade/report') as $plugin) {
3420 if (file_exists($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php')) {
3421 require_once($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php');
3422 $functionname = 'grade_report_'.$plugin.'_profilereport';
3423 if (function_exists($functionname)) {
3424 $this->choices[$plugin] = get_string('modulename', 'gradereport_'.$plugin, NULL, $CFG->dirroot.'/grade/report/'.$plugin.'/lang/');
3428 return true;
3433 * Special class for register auth selection
3435 class admin_setting_special_registerauth extends admin_setting_configselect {
3436 function admin_setting_special_registerauth() {
3437 parent::admin_setting_configselect('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), 'email', null);
3440 function get_defaultsettings() {
3441 $this->load_choices();
3442 if (array_key_exists($this->defaultsetting, $this->choices)) {
3443 return $this->defaultsetting;
3444 } else {
3445 return '';
3449 function load_choices() {
3450 global $CFG;
3452 if (is_array($this->choices)) {
3453 return true;
3455 $this->choices = array();
3456 $this->choices[''] = get_string('disable');
3458 $authsenabled = get_enabled_auth_plugins(true);
3460 foreach ($authsenabled as $auth) {
3461 $authplugin = get_auth_plugin($auth);
3462 if (!$authplugin->can_signup()) {
3463 continue;
3465 // Get the auth title (from core or own auth lang files)
3466 $authtitle = $authplugin->get_title();
3467 $this->choices[$auth] = $authtitle;
3469 return true;
3474 * Module manage page
3476 class admin_page_managemods extends admin_externalpage {
3477 function admin_page_managemods() {
3478 global $CFG;
3479 parent::admin_externalpage('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
3482 function search($query) {
3483 if ($result = parent::search($query)) {
3484 return $result;
3487 $found = false;
3488 if ($modules = get_records('modules')) {
3489 $textlib = textlib_get_instance();
3490 foreach ($modules as $module) {
3491 if (strpos($module->name, $query) !== false) {
3492 $found = true;
3493 break;
3495 $strmodulename = get_string('modulename', $module->name);
3496 if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
3497 $found = true;
3498 break;
3502 if ($found) {
3503 $result = new object();
3504 $result->page = $this;
3505 $result->settings = array();
3506 return array($this->name => $result);
3507 } else {
3508 return array();
3514 * Blocks manage page
3516 class admin_page_manageblocks extends admin_externalpage {
3517 function admin_page_manageblocks() {
3518 global $CFG;
3519 parent::admin_externalpage('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
3522 function search($query) {
3523 global $CFG;
3524 if ($result = parent::search($query)) {
3525 return $result;
3528 $found = false;
3529 if (!empty($CFG->blocks_version) and $blocks = get_records('block')) {
3530 $textlib = textlib_get_instance();
3531 foreach ($blocks as $block) {
3532 if (strpos($block->name, $query) !== false) {
3533 $found = true;
3534 break;
3536 $strblockname = get_string('blockname', 'block_'.$block->name);
3537 if (strpos($textlib->strtolower($strblockname), $query) !== false) {
3538 $found = true;
3539 break;
3543 if ($found) {
3544 $result = new object();
3545 $result->page = $this;
3546 $result->settings = array();
3547 return array($this->name => $result);
3548 } else {
3549 return array();
3555 * Special class for authentication administration.
3557 class admin_setting_manageauths extends admin_setting {
3558 function admin_setting_manageauths() {
3559 parent::admin_setting('authsui', get_string('authsettings', 'admin'), '', '');
3562 function get_setting() {
3563 return true;
3566 function get_defaultsetting() {
3567 return true;
3570 function write_setting($data) {
3571 // do not write any setting
3572 return '';
3575 function is_related($query) {
3576 if (parent::is_related($query)) {
3577 return true;
3580 $textlib = textlib_get_instance();
3581 $authsavailable = get_list_of_plugins('auth');
3582 foreach ($authsavailable as $auth) {
3583 if (strpos($auth, $query) !== false) {
3584 return true;
3586 $authplugin = get_auth_plugin($auth);
3587 $authtitle = $authplugin->get_title();
3588 if (strpos($textlib->strtolower($authtitle), $query) !== false) {
3589 return true;
3592 return false;
3595 function output_html($data, $query='') {
3596 global $CFG;
3599 // display strings
3600 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
3601 'settings', 'edit', 'name', 'enable', 'disable',
3602 'up', 'down', 'none'));
3603 $txt->updown = "$txt->up/$txt->down";
3605 $authsavailable = get_list_of_plugins('auth');
3606 get_enabled_auth_plugins(true); // fix the list of enabled auths
3607 if (empty($CFG->auth)) {
3608 $authsenabled = array();
3609 } else {
3610 $authsenabled = explode(',', $CFG->auth);
3613 // construct the display array, with enabled auth plugins at the top, in order
3614 $displayauths = array();
3615 $registrationauths = array();
3616 $registrationauths[''] = $txt->disable;
3617 foreach ($authsenabled as $auth) {
3618 $authplugin = get_auth_plugin($auth);
3619 /// Get the auth title (from core or own auth lang files)
3620 $authtitle = $authplugin->get_title();
3621 /// Apply titles
3622 $displayauths[$auth] = $authtitle;
3623 if ($authplugin->can_signup()) {
3624 $registrationauths[$auth] = $authtitle;
3628 foreach ($authsavailable as $auth) {
3629 if (array_key_exists($auth, $displayauths)) {
3630 continue; //already in the list
3632 $authplugin = get_auth_plugin($auth);
3633 /// Get the auth title (from core or own auth lang files)
3634 $authtitle = $authplugin->get_title();
3635 /// Apply titles
3636 $displayauths[$auth] = $authtitle;
3637 if ($authplugin->can_signup()) {
3638 $registrationauths[$auth] = $authtitle;
3642 $return = print_heading(get_string('actauthhdr', 'auth'), '', 3, 'main', true);
3643 $return .= print_box_start('generalbox authsui', '', true);
3645 $table = new object();
3646 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings);
3647 $table->align = array('left', 'center', 'center', 'center');
3648 $table->width = '90%';
3649 $table->data = array();
3651 //add always enabled plugins first
3652 $displayname = "<span>".$displayauths['manual']."</span>";
3653 $settings = "<a href=\"auth_config.php?auth=manual\">{$txt->settings}</a>";
3654 //$settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
3655 $table->data[] = array($displayname, '', '', $settings);
3656 $displayname = "<span>".$displayauths['nologin']."</span>";
3657 $settings = "<a href=\"auth_config.php?auth=nologin\">{$txt->settings}</a>";
3658 $table->data[] = array($displayname, '', '', $settings);
3661 // iterate through auth plugins and add to the display table
3662 $updowncount = 1;
3663 $authcount = count($authsenabled);
3664 $url = "auth.php?sesskey=" . sesskey();
3665 foreach ($displayauths as $auth => $name) {
3666 if ($auth == 'manual' or $auth == 'nologin') {
3667 continue;
3669 // hide/show link
3670 if (in_array($auth, $authsenabled)) {
3671 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
3672 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"disable\" /></a>";
3673 // $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\"><input type=\"checkbox\" checked /></a>";
3674 $enabled = true;
3675 $displayname = "<span>$name</span>";
3677 else {
3678 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
3679 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"enable\" /></a>";
3680 // $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\"><input type=\"checkbox\" /></a>";
3681 $enabled = false;
3682 $displayname = "<span class=\"dimmed_text\">$name</span>";
3685 // up/down link (only if auth is enabled)
3686 $updown = '';
3687 if ($enabled) {
3688 if ($updowncount > 1) {
3689 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
3690 $updown .= "<img src=\"{$CFG->pixpath}/t/up.gif\" alt=\"up\" /></a>&nbsp;";
3692 else {
3693 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
3695 if ($updowncount < $authcount) {
3696 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
3697 $updown .= "<img src=\"{$CFG->pixpath}/t/down.gif\" alt=\"down\" /></a>";
3699 else {
3700 $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />";
3702 ++ $updowncount;
3705 // settings link
3706 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
3707 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
3708 } else {
3709 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
3712 // add a row to the table
3713 $table->data[] =array($displayname, $hideshow, $updown, $settings);
3715 $return .= print_table($table, true);
3716 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
3717 $return .= print_box_end(true);
3718 return highlight($query, $return);
3722 * Special class for filter administration.
3724 class admin_setting_managefilters extends admin_setting {
3725 function admin_setting_managefilters() {
3726 parent::admin_setting('filtersui', get_string('filtersettings', 'admin'), '', '');
3729 function get_setting() {
3730 return true;
3733 function get_defaultsetting() {
3734 return true;
3737 function write_setting($data) {
3738 // do not write any setting
3739 return '';
3742 function is_related($query) {
3743 if (parent::is_related($query)) {
3744 return true;
3747 $textlib = textlib_get_instance();
3748 $filterlocations = array('mod','filter');
3749 foreach ($filterlocations as $filterlocation) {
3750 $plugins = get_list_of_plugins($filterlocation);
3751 foreach ($plugins as $plugin) {
3752 if (strpos($plugin, $query) !== false) {
3753 return true;
3755 $name = get_string('filtername', $plugin);
3756 if (strpos($textlib->strtolower($name), $query) !== false) {
3757 return true;
3761 return false;
3764 function output_html($data, $query='') {
3765 global $CFG;
3767 $strname = get_string('name');
3768 $strhide = get_string('disable');
3769 $strshow = get_string('enable');
3770 $strhideshow = "$strhide/$strshow";
3771 $strsettings = get_string('settings');
3772 $strup = get_string('up');
3773 $strdown = get_string('down');
3774 $strupdown = "$strup/$strdown";
3776 // get a list of possible filters (and translate name if possible)
3777 // note filters can be in the dedicated filters area OR in their
3778 // associated modules
3779 $installedfilters = array();
3780 $filtersettings_new = array();
3781 $filtersettings_old = array();
3782 $filterlocations = array('mod','filter');
3783 foreach ($filterlocations as $filterlocation) {
3784 $plugins = get_list_of_plugins($filterlocation);
3785 foreach ($plugins as $plugin) {
3786 $pluginpath = "$CFG->dirroot/$filterlocation/$plugin/filter.php";
3787 $settingspath_new = "$CFG->dirroot/$filterlocation/$plugin/filtersettings.php";
3788 $settingspath_old = "$CFG->dirroot/$filterlocation/$plugin/filterconfig.html";
3789 if (is_readable($pluginpath)) {
3790 $name = trim(get_string("filtername", $plugin));
3791 if (empty($name) or ($name == '[[filtername]]')) {
3792 $textlib = textlib_get_instance();
3793 $name = $textlib->strtotitle($plugin);
3795 $installedfilters["$filterlocation/$plugin"] = $name;
3796 if (is_readable($settingspath_new)) {
3797 $filtersettings_new[] = "$filterlocation/$plugin";
3798 } else if (is_readable($settingspath_old)) {
3799 $filtersettings_old[] = "$filterlocation/$plugin";
3805 // get all the currently selected filters
3806 if (!empty($CFG->textfilters)) {
3807 $oldactivefilters = explode(',', $CFG->textfilters);
3808 $oldactivefilters = array_unique($oldactivefilters);
3809 } else {
3810 $oldactivefilters = array();
3813 // take this opportunity to clean up filters
3814 $activefilters = array();
3815 foreach ($oldactivefilters as $oldactivefilter) {
3816 if (!empty($oldactivefilter) and array_key_exists($oldactivefilter, $installedfilters)) {
3817 $activefilters[] = $oldactivefilter;
3821 // construct the display array with installed filters
3822 // at the top in the right order
3823 $displayfilters = array();
3824 foreach ($activefilters as $activefilter) {
3825 $name = $installedfilters[$activefilter];
3826 $displayfilters[$activefilter] = $name;
3828 foreach ($installedfilters as $key => $filter) {
3829 if (!array_key_exists($key, $displayfilters)) {
3830 $displayfilters[$key] = $filter;
3834 $return = print_heading(get_string('actfilterhdr', 'filters'), '', 3, 'main', true);
3835 $return .= print_box_start('generalbox filtersui', '', true);
3837 $table = new object();
3838 $table->head = array($strname, $strhideshow, $strupdown, $strsettings);
3839 $table->align = array('left', 'center', 'center', 'center');
3840 $table->width = '90%';
3841 $table->data = array();
3843 $filtersurl = "$CFG->wwwroot/$CFG->admin/filters.php?sesskey=".sesskey();
3844 $imgurl = "$CFG->pixpath/t";
3846 // iterate through filters adding to display table
3847 $updowncount = 1;
3848 $activefilterscount = count($activefilters);
3849 foreach ($displayfilters as $path => $name) {
3850 $upath = urlencode($path);
3851 // get hide/show link
3852 if (in_array($path, $activefilters)) {
3853 $hideshow = "<a href=\"$filtersurl&amp;action=hide&amp;filterpath=$upath\">";
3854 $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"$strhide\" /></a>";
3855 $hidden = false;
3856 $displayname = "<span>$name</span>";
3858 else {
3859 $hideshow = "<a href=\"$filtersurl&amp;action=show&amp;filterpath=$upath\">";
3860 $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"$strshow\" /></a>";
3861 $hidden = true;
3862 $displayname = "<span class=\"dimmed_text\">$name</span>";
3865 // get up/down link (only if not hidden)
3866 $updown = '';
3867 if (!$hidden) {
3868 if ($updowncount>1) {
3869 $updown .= "<a href=\"$filtersurl&amp;action=up&amp;filterpath=$upath\">";
3870 $updown .= "<img src=\"$imgurl/up.gif\" alt=\"$strup\" /></a>&nbsp;";
3872 else {
3873 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
3875 if ($updowncount<$activefilterscount) {
3876 $updown .= "<a href=\"$filtersurl&amp;action=down&amp;filterpath=$upath\">";
3877 $updown .= "<img src=\"$imgurl/down.gif\" alt=\"$strdown\" /></a>";
3879 else {
3880 $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />";
3882 ++$updowncount;
3885 // settings link (if defined)
3886 $settings = '';
3887 if (in_array($path, $filtersettings_new)) {
3888 $settings = "<a href=\"settings.php?section=filtersetting".str_replace('/', '',$path)."\">$strsettings</a>";
3889 } else if (in_array($path, $filtersettings_old)) {
3890 $settings = "<a href=\"filter.php?filter=".urlencode($path)."\">$strsettings</a>";
3893 // write data into the table object
3894 $table->data[] = array($displayname, $hideshow, $updown, $settings);
3896 $return .= print_table($table, true);
3897 $return .= get_string('tablenosave', 'filters');
3898 $return .= print_box_end(true);
3899 return highlight($query, $return);
3904 * Initialise admin page - this function does require login and permission
3905 * checks specified in page definition.
3906 * This function must be called on each admin page before other code.
3907 * @param string $section name of page
3909 function admin_externalpage_setup($section) {
3911 global $CFG, $PAGE, $USER;
3912 require_once($CFG->libdir.'/blocklib.php');
3913 require_once($CFG->dirroot.'/'.$CFG->admin.'/pagelib.php');
3915 if ($site = get_site()) {
3916 require_login();
3917 } else {
3918 redirect($CFG->wwwroot.'/'.$CFG->admin.'/index.php');
3919 die;
3922 $adminroot =& admin_get_root(false, false); // settings not required for external pages
3923 $extpage =& $adminroot->locate($section);
3925 if (empty($extpage) or !is_a($extpage, 'admin_externalpage')) {
3926 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
3927 die;
3930 // this eliminates our need to authenticate on the actual pages
3931 if (!($extpage->check_access())) {
3932 print_error('accessdenied', 'admin');
3933 die;
3936 page_map_class(PAGE_ADMIN, 'page_admin');
3937 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
3938 $PAGE->init_extra($section); // hack alert!
3940 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
3942 if (!isset($USER->adminediting)) {
3943 $USER->adminediting = false;
3946 if ($PAGE->user_allowed_editing()) {
3947 if ($adminediting == 1) {
3948 $USER->adminediting = true;
3949 } elseif ($adminediting == 0) {
3950 $USER->adminediting = false;
3956 * Print header for admin page
3957 * @param string $focus focus element
3959 function admin_externalpage_print_header($focus='') {
3961 if (!is_string($focus)) {
3962 $focus = ''; // BC compatibility, there used to be adminroot parameter
3965 global $CFG, $PAGE, $SITE, $THEME;
3967 define('ADMIN_EXT_HEADER_PRINTED', 'true');
3969 if (!empty($SITE->fullname)) {
3970 $pageblocks = blocks_setup($PAGE);
3972 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
3973 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
3974 BLOCK_L_MAX_WIDTH);
3975 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
3976 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
3977 BLOCK_R_MAX_WIDTH);
3979 $PAGE->print_header('', $focus);
3980 echo '<table id="layout-table" summary=""><tr>';
3982 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
3983 foreach ($lt as $column) {
3984 $lt1[] = $column;
3985 if ($column == 'middle') break;
3987 foreach ($lt1 as $column) {
3988 switch ($column) {
3989 case 'left':
3990 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
3991 print_container_start();
3992 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
3993 print_container_end();
3994 echo '</td>';
3995 break;
3997 case 'middle':
3998 echo '<td id="middle-column">';
3999 print_container_start(true);
4000 $THEME->open_header_containers++; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
4001 break;
4003 case 'right':
4004 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
4005 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
4006 print_container_start();
4007 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
4008 print_container_end();
4009 echo '</td>';
4011 break;
4014 } else {
4015 print_header();
4020 * Print footer on admin page - please use normal print_footer() instead
4022 function admin_externalpage_print_footer() {
4024 global $CFG, $PAGE, $SITE, $THEME;
4026 define('ADMIN_EXT_FOOTER_PRINTED', 'true');
4028 if (!empty($SITE->fullname)) {
4029 $pageblocks = blocks_setup($PAGE);
4030 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
4031 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
4032 BLOCK_L_MAX_WIDTH);
4033 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
4034 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
4035 BLOCK_R_MAX_WIDTH);
4037 $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
4038 foreach ($lt as $column) {
4039 if ($column != 'middle') {
4040 array_shift($lt);
4041 } else if ($column == 'middle') {
4042 break;
4045 foreach ($lt as $column) {
4046 switch ($column) {
4047 case 'left':
4048 echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
4049 print_container_start();
4050 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
4051 print_container_end();
4052 echo '</td>';
4053 break;
4055 case 'middle':
4056 print_container_end();
4057 $THEME->open_header_containers--; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
4058 echo '</td>';
4059 break;
4061 case 'right':
4062 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
4063 echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
4064 print_container_start();
4065 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
4066 print_container_end();
4067 echo '</td>';
4069 break;
4072 echo '</tr></table>';
4074 print_footer();
4078 * Returns the reference to admin tree root
4079 * @return reference
4081 function &admin_get_root($reload=false, $requirefulltree=true) {
4082 global $CFG;
4084 static $ADMIN = NULL;
4086 if (!is_null($ADMIN)) {
4087 $olderrors = $ADMIN->errors;
4088 $oldsearch = $ADMIN->search;
4089 $oldfulltree = $ADMIN->fulltree;
4090 } else {
4091 $olderrors = array();
4092 $oldsearch = '';
4093 $oldfulltree = false;
4096 if ($reload or ($requirefulltree and !$oldfulltree)) {
4097 $ADMIN = NULL;
4100 if (is_null($ADMIN)) {
4101 // start the admin tree!
4102 $ADMIN = new admin_root();
4103 // array of error messages and search query
4104 $ADMIN->errors = $olderrors;
4105 $ADMIN->search = $oldsearch;
4106 if ($requirefulltree) {
4107 $ADMIN->fulltree = true;
4108 } else {
4109 $ADMIN->fulltree = $oldfulltree;
4112 // we process this file first to create categories first and in correct order
4113 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
4115 // now we process all other files in admin/settings to build the admin tree
4116 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
4117 if ($file != $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
4118 include($file);
4121 if (file_exists($CFG->dirroot.'/local/settings.php')) {
4122 include_once($CFG->dirroot.'/local/settings.php');
4126 return $ADMIN;
4129 /// settings utility functions
4132 * This function applies default settings.
4133 * @param object $node, NULL means complete tree
4134 * @param bool $uncoditional if true overrides all values with defaults
4135 * @return void
4137 function admin_apply_default_settings($node=NULL, $unconditional=true) {
4138 global $CFG;
4140 if (is_null($node)) {
4141 $node =& admin_get_root();
4144 if (is_a($node, 'admin_category')) {
4145 $entries = array_keys($node->children);
4146 foreach ($entries as $entry) {
4147 admin_apply_default_settings($node->children[$entry], $unconditional);
4150 } else if (is_a($node, 'admin_settingpage')) {
4151 foreach ($node->settings as $setting) {
4152 if (!$unconditional and !is_null($setting->get_setting())) {
4153 //do not override existing defaults
4154 continue;
4156 $defaultsetting = $setting->get_defaultsetting();
4157 if (is_null($defaultsetting)) {
4158 // no value yet - default maybe applied after admin user creation or in upgradesettings
4159 continue;
4161 $setting->write_setting($defaultsetting);
4167 * Store changed settings, this function updates the errors variable in $ADMIN
4168 * @param object $formdata from form (without magic quotes)
4169 * @return int number of changed settings
4171 function admin_write_settings($formdata) {
4172 global $CFG, $SITE, $COURSE;
4174 $olddbsessions = !empty($CFG->dbsessions);
4175 $formdata = (array)stripslashes_recursive($formdata);
4177 $data = array();
4178 foreach ($formdata as $fullname=>$value) {
4179 if (strpos($fullname, 's_') !== 0) {
4180 continue; // not a config value
4182 $data[$fullname] = $value;
4185 $adminroot =& admin_get_root();
4186 $settings = admin_find_write_settings($adminroot, $data);
4188 $count = 0;
4189 foreach ($settings as $fullname=>$setting) {
4190 $original = serialize($setting->get_setting()); // comparison must work for arrays too
4191 $error = $setting->write_setting($data[$fullname]);
4192 if ($error !== '') {
4193 $adminroot->errors[$fullname] = new object();
4194 $adminroot->errors[$fullname]->data = $data[$fullname];
4195 $adminroot->errors[$fullname]->id = $setting->get_id();
4196 $adminroot->errors[$fullname]->error = $error;
4198 if ($original !== serialize($setting->get_setting())) {
4199 $count++;
4200 $callbackfunction = $setting->updatedcallback;
4201 if (function_exists($callbackfunction)) {
4202 $callbackfunction($fullname);
4207 if ($olddbsessions != !empty($CFG->dbsessions)) {
4208 require_logout();
4211 // now update $SITE - it might have been changed
4212 $SITE = get_record('course', 'id', $SITE->id);
4213 $COURSE = clone($SITE);
4215 // now reload all settings - some of them might depend on the changed
4216 admin_get_root(true);
4217 return $count;
4221 * Internal recursive function - finds all settings from submitted form
4223 function admin_find_write_settings($node, $data) {
4224 $return = array();
4226 if (empty($data)) {
4227 return $return;
4230 if (is_a($node, 'admin_category')) {
4231 $entries = array_keys($node->children);
4232 foreach ($entries as $entry) {
4233 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
4236 } else if (is_a($node, 'admin_settingpage')) {
4237 foreach ($node->settings as $setting) {
4238 $fullname = $setting->get_full_name();
4239 if (array_key_exists($fullname, $data)) {
4240 $return[$fullname] = $setting;
4246 return $return;
4250 * Internal function - prints the search results
4252 function admin_search_settings_html($query) {
4253 global $CFG;
4255 $textlib = textlib_get_instance();
4256 if ($textlib->strlen($query) < 2) {
4257 return '';
4259 $query = $textlib->strtolower($query);
4261 $adminroot =& admin_get_root();
4262 $findings = $adminroot->search($query);
4263 $return = '';
4264 $savebutton = false;
4266 foreach ($findings as $found) {
4267 $page = $found->page;
4268 $settings = $found->settings;
4269 if ($page->is_hidden()) {
4270 // hidden pages are not displayed in search results
4271 continue;
4273 if (is_a($page, 'admin_externalpage')) {
4274 $return .= print_heading(get_string('searchresults','admin').' - <a href="'.$page->url.'">'.highlight($query, $page->visiblename).'</a>', '', 2, 'main', true);
4275 } else if (is_a($page, 'admin_settingpage')) {
4276 $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);
4277 } else {
4278 continue;
4280 if (!empty($settings)) {
4281 $savebutton = true;
4282 $return .= '<fieldset class="adminsettings">'."\n";
4283 foreach ($settings as $setting) {
4284 $return .= '<div class="clearer"><!-- --></div>'."\n";
4285 $fullname = $setting->get_full_name();
4286 if (array_key_exists($fullname, $adminroot->errors)) {
4287 $data = $adminroot->errors[$fullname]->data;
4288 } else {
4289 $data = $setting->get_setting();
4290 if (is_null($data)) {
4291 $data = $setting->get_defaultsetting();
4294 $return .= $setting->output_html($data, $query);
4296 $return .= '</fieldset>';
4300 if ($savebutton) {
4301 $return .= '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges','admin').'" /></div>';
4304 return $return;
4308 * Internal function - prints list of uninitialised settings
4310 function admin_output_new_settings_by_page($node) {
4311 $return = '';
4313 if (is_a($node, 'admin_category')) {
4314 $entries = array_keys($node->children);
4315 foreach ($entries as $entry) {
4316 $return .= admin_output_new_settings_by_page($node->children[$entry]);
4319 } else if (is_a($node, 'admin_settingpage')) {
4320 $newsettings = array();
4321 foreach ($node->settings as $setting) {
4322 if (is_null($setting->get_setting())) {
4323 $newsettings[] = $setting;
4326 if (count($newsettings) > 0) {
4327 $adminroot =& admin_get_root();
4328 $return .= print_heading(get_string('upgradesettings','admin').' - '.$node->visiblename, '', 2, 'main', true);
4329 $return .= '<fieldset class="adminsettings">'."\n";
4330 foreach ($newsettings as $setting) {
4331 $fullname = $setting->get_full_name();
4332 if (array_key_exists($fullname, $adminroot->errors)) {
4333 $data = $adminroot->errors[$fullname]->data;
4334 } else {
4335 $data = $setting->get_setting();
4336 if (is_null($data)) {
4337 $data = $setting->get_defaultsetting();
4340 $return .= '<div class="clearer"><!-- --></div>'."\n";
4341 $return .= $setting->output_html($data);
4343 $return .= '</fieldset>';
4347 return $return;
4351 * Unconditionally applies default admin settings in main config table
4352 * @param array $defaults array of string values
4354 function apply_default_exception_settings($defaults) {
4355 foreach($defaults as $key => $value) {
4356 set_config($key, $value, NULL);
4361 * Format admin settings
4362 * @param string $object setting
4363 * @param string $title label element
4364 * @param string $form form fragment, html code - not highlighed automaticaly
4365 * @param string $description
4366 * @param bool $label link label to id
4367 * @param string $warning warning text
4368 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string
4369 * @param string $query search query to be highlighted
4371 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
4372 global $CFG;
4374 $name = $setting->name;
4375 $fullname = $setting->get_full_name();
4377 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
4378 if ($label) {
4379 $labelfor = 'for = "'.$setting->get_id().'"';
4380 } else {
4381 $labelfor = '';
4384 if (empty($setting->plugin) and array_key_exists($name, $CFG->config_php_settings)) {
4385 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
4386 } else {
4387 $override = '';
4390 if ($warning !== '') {
4391 $warning = '<div class="form-warning">'.$warning.'</div>';
4394 if (is_null($defaultinfo)) {
4395 $defaultinfo = '';
4396 } else {
4397 if ($defaultinfo === '') {
4398 $defaultinfo = get_string('emptysettingvalue', 'admin');
4400 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
4401 $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>';
4405 $str = '
4406 <div class="form-item clearfix" id="admin-'.$setting->name.'">
4407 <div class="form-label">
4408 <label '.$labelfor.'>'.highlightfast($query, $title).'<span class="form-shortname">'.highlightfast($query, $name).'</span>
4409 '.$override.$warning.'
4410 </label>
4411 </div>
4412 <div class="form-setting">'.$form.$defaultinfo.'</div>
4413 <div class="form-description">'.highlight($query, $description).'</div>
4414 </div>';
4416 $adminroot =& admin_get_root();
4417 if (array_key_exists($fullname, $adminroot->errors)) {
4418 $str = '<fieldset class="error"><legend>'.$adminroot->errors[$fullname]->error.'</legend>'.$str.'</fieldset>';
4421 return $str;
4425 * Try to upgrade the given language pack (or current language)
4426 * If it doesn't work, fail silently and return false
4428 function upgrade_language_pack($lang='') {
4429 global $CFG;
4431 if (empty($lang)) {
4432 $lang = current_language();
4435 if ($lang == 'en_utf8') {
4436 return true; // Nothing to do
4439 notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
4441 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
4442 @mkdir ($CFG->dataroot.'/lang/');
4444 require_once($CFG->libdir.'/componentlib.class.php');
4446 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
4447 $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
4449 if ($status == COMPONENT_INSTALLED) {
4450 debugging('Downloading successful: '.$lang);
4451 @unlink($CFG->dataroot.'/cache/languages');
4452 return true;
4456 return false;
4460 * Based on find_new_settings{@link ()} in upgradesettings.php
4461 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
4463 * @param string $node The node at which to start searching.
4464 * @return boolen true if any settings haven't been initialised, false if they all have
4466 function any_new_admin_settings($node) {
4468 if (is_a($node, 'admin_category')) {
4469 $entries = array_keys($node->children);
4470 foreach ($entries as $entry) {
4471 if (any_new_admin_settings($node->children[$entry])){
4472 return true;
4476 } else if (is_a($node, 'admin_settingpage')) {
4477 foreach ($node->settings as $setting) {
4478 if ($setting->get_setting() === NULL) {
4479 return true;
4484 return false;
4489 * Moved from admin/replace.php so that we can use this in cron
4490 * @param string $search - string to look for (with magic quotes)
4491 * @param string $replace - string to replace (with magic quotes)
4492 * @return bool - success or fail
4494 function db_replace($search, $replace) {
4496 global $db, $CFG;
4498 /// Turn off time limits, sometimes upgrades can be slow.
4499 @set_time_limit(0);
4500 @ob_implicit_flush(true);
4501 while(@ob_end_flush());
4503 if (!$tables = $db->Metatables() ) { // No tables yet at all.
4504 return false;
4506 foreach ($tables as $table) {
4508 if (in_array($table, array($CFG->prefix.'config'))) { // Don't process these
4509 continue;
4512 if ($columns = $db->MetaColumns($table, false)) {
4513 foreach ($columns as $column => $data) {
4514 if (in_array($data->type, array('text','mediumtext','longtext','varchar'))) { // Text stuff only
4515 $db->debug = true;
4516 execute_sql("UPDATE $table SET $column = REPLACE($column, '$search', '$replace');");
4517 $db->debug = false;
4523 return true;
4527 * Prints tables of detected plugins, one table per plugin type,
4528 * and prints whether they are part of the standard Moodle
4529 * distribution or not.
4531 function print_plugin_tables() {
4532 $plugins_standard = array();
4533 $plugins_standard['mod'] = array('assignment',
4534 'chat',
4535 'choice',
4536 'data',
4537 'exercise',
4538 'forum',
4539 'glossary',
4540 'hotpot',
4541 'journal',
4542 'label',
4543 'lams',
4544 'lesson',
4545 'quiz',
4546 'resource',
4547 'scorm',
4548 'survey',
4549 'wiki',
4550 'workshop');
4552 $plugins_standard['blocks'] = array('activity_modules',
4553 'admin',
4554 'admin_bookmarks',
4555 'admin_tree',
4556 'blog_menu',
4557 'blog_tags',
4558 'calendar_month',
4559 'calendar_upcoming',
4560 'course_list',
4561 'course_summary',
4562 'glossary_random',
4563 'html',
4564 'loancalc',
4565 'login',
4566 'mentees',
4567 'messages',
4568 'mnet_hosts',
4569 'news_items',
4570 'online_users',
4571 'participants',
4572 'quiz_results',
4573 'recent_activity',
4574 'rss_client',
4575 'search',
4576 'search_forums',
4577 'section_links',
4578 'site_main_menu',
4579 'social_activities',
4580 'tag_flickr',
4581 'tag_youtube',
4582 'tags');
4584 $plugins_standard['filter'] = array('activitynames',
4585 'algebra',
4586 'censor',
4587 'emailprotect',
4588 'filter',
4589 'mediaplugin',
4590 'multilang',
4591 'tex',
4592 'tidy');
4594 $plugins_installed = array();
4595 $installed_mods = get_records_list('modules', '', '', '', 'name');
4596 $installed_blocks = get_records_list('block', '', '', '', 'name');
4598 foreach($installed_mods as $mod) {
4599 $plugins_installed['mod'][] = $mod->name;
4602 foreach($installed_blocks as $block) {
4603 $plugins_installed['blocks'][] = $block->name;
4606 $plugins_ondisk = array();
4607 $plugins_ondisk['mod'] = get_list_of_plugins('mod', 'db');
4608 $plugins_ondisk['blocks'] = get_list_of_plugins('blocks', 'db');
4609 $plugins_ondisk['filter'] = get_list_of_plugins('filter', 'db');
4611 $strstandard = get_string('standard');
4612 $strnonstandard = get_string('nonstandard');
4613 $strmissingfromdisk = '(' . get_string('missingfromdisk') . ')';
4614 $strabouttobeinstalled = '(' . get_string('abouttobeinstalled') . ')';
4616 $html = '';
4618 $html .= '<table class="generaltable plugincheckwrapper" cellspacing="4" cellpadding="1"><tr valign="top">';
4620 foreach ($plugins_ondisk as $cat => $list_ondisk) {
4621 $strcaption = get_string($cat);
4622 if ($cat == 'mod') {
4623 $strcaption = get_string('activitymodule');
4624 } elseif ($cat == 'filter') {
4625 $strcaption = get_string('managefilters');
4628 $html .= '<td><table class="plugincompattable generaltable boxaligncenter" cellspacing="1" cellpadding="5" '
4629 . 'id="' . $cat . 'compattable" summary="compatibility table"><caption>' . $strcaption . '</caption>' . "\n";
4630 $html .= '<tr class="r0"><th class="header c0">' . get_string('directory') . "</th>\n"
4631 . '<th class="header c1">' . get_string('name') . "</th>\n"
4632 . '<th class="header c2">' . get_string('status') . "</th>\n</tr>\n";
4634 $row = 1;
4636 foreach ($list_ondisk as $k => $plugin) {
4637 $status = 'ok';
4638 $standard = 'standard';
4639 $note = '';
4641 if (!in_array($plugin, $plugins_standard[$cat])) {
4642 $standard = 'nonstandard';
4643 $status = 'warning';
4646 // Get real name and full path of plugin
4647 $plugin_name = "[[$plugin]]";
4649 $plugin_path = "$cat/$plugin";
4651 $plugin_name = get_plugin_name($plugin, $cat);
4653 // Determine if the plugin is about to be installed
4654 if ($cat != 'filter' && !in_array($plugin, $plugins_installed[$cat])) {
4655 $note = $strabouttobeinstalled;
4656 $plugin_name = $plugin;
4659 $html .= "<tr class=\"r$row\">\n"
4660 . "<td class=\"cell c0\">$plugin_path</td>\n"
4661 . "<td class=\"cell c1\">$plugin_name</td>\n"
4662 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $note</td>\n</tr>\n";
4663 $row++;
4665 // If the plugin was both on disk and in the db, unset the value from the installed plugins list
4666 if ($key = array_search($plugin, $plugins_installed[$cat])) {
4667 unset($plugins_installed[$cat][$key]);
4671 // If there are plugins left in the plugins_installed list, it means they are missing from disk
4672 foreach ($plugins_installed[$cat] as $k => $missing_plugin) {
4673 // Make sure the plugin really is missing from disk
4674 if (!in_array($missing_plugin, $plugins_ondisk[$cat])) {
4675 $standard = 'standard';
4676 $status = 'warning';
4678 if (!in_array($missing_plugin, $plugins_standard[$cat])) {
4679 $standard = 'nonstandard';
4682 $plugin_name = $missing_plugin;
4683 $html .= "<tr class=\"r$row\">\n"
4684 . "<td class=\"cell c0\">?</td>\n"
4685 . "<td class=\"cell c1\">$plugin_name</td>\n"
4686 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $strmissingfromdisk</td>\n</tr>\n";
4687 $row++;
4691 $html .= '</table></td>';
4694 $html .= '</tr></table><br />';
4696 echo $html;