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