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