major whitespace cleanup - fixed tabs
[moodle.git] / lib / adminlib.php
CommitLineData
a4e10845 1<?php
88a7228a 2
3/**
4 * adminlib.php - Contains functions that only administrators will ever need to use
5 *
a4e10845 6 * @author Martin Dougiamas and many others
88a7228a 7 * @version $Id$
8 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
9 * @package moodlecore
10 */
11
12/**
ead29342 13 * Upgrade plugins
88a7228a 14 *
15 * @uses $db
16 * @uses $CFG
ead29342 17 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
18 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
19 * @param string $return The url to prompt the user to continue to
88a7228a 20 */
ead29342 21function upgrade_plugins($type, $dir, $return) {
e69ef14b 22 global $CFG, $db;
173cc1c3 23
ead29342 24 if (!$plugs = get_list_of_plugins($dir) ) {
25 error('No '.$type.' plugins installed!');
173cc1c3 26 }
27
583fad99 28 $updated_plugins = false;
29 $strpluginsetup = get_string('pluginsetup');
30
ead29342 31 foreach ($plugs as $plug) {
173cc1c3 32
ead29342 33 $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
173cc1c3 34
ead29342 35 unset($plugin);
173cc1c3 36
bbbf2d40 37 if (is_readable($fullplug .'/version.php')) {
ead29342 38 include_once($fullplug .'/version.php'); // defines $plugin with version etc
173cc1c3 39 } else {
40 continue; // Nothing to do.
41 }
42
e79a09a2 43 $oldupgrade = false;
44 $newupgrade = false;
7c006e34 45 if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) {
46 include_once($fullplug . '/db/'. $CFG->dbtype . '.php'); // defines old upgrading function
e79a09a2 47 $oldupgrade = true;
48 }
7c006e34 49 if (is_readable($fullplug . '/db/upgrade.php') && $CFG->xmldb_enabled) {
50 include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
e79a09a2 51 $newupgrade = true;
52 }
53
ead29342 54 if (!isset($plugin)) {
173cc1c3 55 continue;
56 }
57
ead29342 58 if (!empty($plugin->requires)) {
59 if ($plugin->requires > $CFG->version) {
60 $info->pluginname = $plug;
61 $info->pluginversion = $plugin->version;
173cc1c3 62 $info->currentmoodle = $CFG->version;
ead29342 63 $info->requiremoodle = $plugin->requires;
583fad99 64 if (!$updated_plugins) {
65 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
66 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
67 false, '&nbsp;', '&nbsp;');
68 }
69 upgrade_log_start();
ead29342 70 notify(get_string('pluginrequirementsnotmet', 'error', $info));
583fad99 71 $updated_plugins = true;
173cc1c3 72 unset($info);
73 continue;
74 }
75 }
76
ead29342 77 $plugin->name = $plug; // The name MUST match the directory
173cc1c3 78
ead29342 79 $pluginversion = $type.'_'.$plug.'_version';
173cc1c3 80
ead29342 81 if (!isset($CFG->$pluginversion)) {
82 set_config($pluginversion, 0);
173cc1c3 83 }
84
ead29342 85 if ($CFG->$pluginversion == $plugin->version) {
173cc1c3 86 // do nothing
ead29342 87 } else if ($CFG->$pluginversion < $plugin->version) {
583fad99 88 if (!$updated_plugins) {
a36f058e 89 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
90 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
91 false, '&nbsp;', '&nbsp;');
173cc1c3 92 }
e79a09a2 93 $updated_plugins = true;
583fad99 94 upgrade_log_start();
ead29342 95 print_heading($plugin->name .' plugin needs upgrading');
e79a09a2 96 $db->debug = true;
97 @set_time_limit(0); // To allow slow databases to complete the long SQL
98
d87a9d73 99 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
e79a09a2 100 /// Both old .sql files and new install.xml are supported
101 /// but we priorize install.xml (XMLDB) if present
102 $status = false;
450cf307 103 if (file_exists($fullplug . '/db/install.xml') && $CFG->xmldb_enabled) {
104 $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
e79a09a2 105 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
106 $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
7c006e34 107 } else {
108 $status = true;
d87a9d73 109 }
e79a09a2 110
111 $db->debug = false;
112 /// Continue with the instalation, roles and other stuff
113 if ($status) {
114 // OK so far, now update the plugins record
115 set_config($pluginversion, $plugin->version);
116 if (!update_capabilities($dir.'/'.$plug)) {
117 error('Could not set up the capabilities for '.$module->name.'!');
118 }
119 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
120 } else {
121 notify('Installing '. $plugin->name .' FAILED!');
122 }
d87a9d73 123 } else { // Upgrade existing install
e79a09a2 124 /// Run de old and new upgrade functions for the module
125 $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade';
126 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
127
128 /// First, the old function if exists
129 $oldupgrade_status = true;
130 if ($oldupgrade && function_exists($oldupgrade_function)) {
131 $db->debug = true;
132 $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
133 } else if ($oldupgrade) {
134 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
135 $fullplug . '/db/' . $CFG->dbtype . '.php');
136 }
137
138 /// Then, the new function if exists and the old one was ok
139 $newupgrade_status = true;
140 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
141 $db->debug = true;
142 $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
143 } else if ($newupgrade) {
144 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
145 $fullplug . '/db/upgrade.php');
146 }
147
148 $db->debug=false;
149 /// Now analyze upgrade results
150 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
151 // OK so far, now update the plugins record
152 set_config($pluginversion, $plugin->version);
153 if (!update_capabilities($dir.'/'.$plug)) {
154 error('Could not update '.$plugin->name.' capabilities!');
d87a9d73 155 }
e79a09a2 156 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
157 } else {
158 notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
173cc1c3 159 }
160 }
d87a9d73 161 echo '<hr />';
173cc1c3 162 } else {
583fad99 163 upgrade_log_start();
ead29342 164 error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
173cc1c3 165 }
166 }
167
583fad99 168 upgrade_log_finish();
169
170 if ($updated_plugins) {
173cc1c3 171 print_continue($return);
172 die;
173 }
174}
175
88a7228a 176/**
177 * Find and check all modules and load them up or upgrade them if necessary
178 *
179 * @uses $db
180 * @uses $CFG
181 * @param string $return The url to prompt the user to continue to
182 * @todo Finish documenting this function
183 */
173cc1c3 184function upgrade_activity_modules($return) {
173cc1c3 185
e69ef14b 186 global $CFG, $db;
173cc1c3 187
88a7228a 188 if (!$mods = get_list_of_plugins('mod') ) {
189 error('No modules installed!');
173cc1c3 190 }
191
583fad99 192 $updated_modules = false;
193 $strmodulesetup = get_string('modulesetup');
194
173cc1c3 195 foreach ($mods as $mod) {
196
88a7228a 197 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
173cc1c3 198 continue;
199 }
200
88a7228a 201 $fullmod = $CFG->dirroot .'/mod/'. $mod;
173cc1c3 202
203 unset($module);
204
88a7228a 205 if ( is_readable($fullmod .'/version.php')) {
206 include_once($fullmod .'/version.php'); // defines $module with version etc
173cc1c3 207 } else {
88a7228a 208 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
173cc1c3 209 continue;
210 }
211
d6eb06b6 212 $oldupgrade = false;
213 $newupgrade = false;
7c006e34 214 if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
215 include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function
d6eb06b6 216 $oldupgrade = true;
217 }
7c006e34 218 if ( is_readable($fullmod . '/db/upgrade.php') && $CFG->xmldb_enabled) {
219 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
d6eb06b6 220 $newupgrade = true;
173cc1c3 221 }
222
223 if (!isset($module)) {
224 continue;
225 }
226
227 if (!empty($module->requires)) {
228 if ($module->requires > $CFG->version) {
229 $info->modulename = $mod;
230 $info->moduleversion = $module->version;
231 $info->currentmoodle = $CFG->version;
232 $info->requiremoodle = $module->requires;
583fad99 233 if (!$updated_modules) {
234 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
235 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
236 false, '&nbsp;', '&nbsp;');
237 }
238 upgrade_log_start();
173cc1c3 239 notify(get_string('modulerequirementsnotmet', 'error', $info));
583fad99 240 $updated_modules = true;
173cc1c3 241 unset($info);
242 continue;
243 }
244 }
245
246 $module->name = $mod; // The name MUST match the directory
247
88a7228a 248 if ($currmodule = get_record('modules', 'name', $module->name)) {
173cc1c3 249 if ($currmodule->version == $module->version) {
250 // do nothing
251 } else if ($currmodule->version < $module->version) {
d6eb06b6 252 /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
253 if (!$oldupgrade && !$newupgrade) {
254 notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' .
255 $fullmod . '/db/upgrade.php were not readable');
256 continue;
257 }
583fad99 258 if (!$updated_modules) {
a36f058e 259 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
260 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
261 false, '&nbsp;', '&nbsp;');
173cc1c3 262 }
583fad99 263 upgrade_log_start();
88a7228a 264 print_heading($module->name .' module needs upgrading');
d6eb06b6 265
266 /// Run de old and new upgrade functions for the module
267 $oldupgrade_function = $module->name . '_upgrade';
268 $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
269
270 /// First, the old function if exists
271 $oldupgrade_status = true;
272 if ($oldupgrade && function_exists($oldupgrade_function)) {
273 $db->debug = true;
274 $oldupgrade_status = $oldupgrade_function($currmodule->version, $module);
ba05965e 275 } else if ($oldupgrade) {
d6eb06b6 276 notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
277 $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php');
d6eb06b6 278 }
279
280 /// Then, the new function if exists and the old one was ok
281 $newupgrade_status = true;
ba05965e 282 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
d6eb06b6 283 $db->debug = true;
284 $newupgrade_status = $newupgrade_function($currmodule->version, $module);
ba05965e 285 } else if ($newupgrade) {
d6eb06b6 286 notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
287 $mod . ': ' . $fullmod . '/db/upgrade.php');
d6eb06b6 288 }
289
e79a09a2 290 $db->debug=false;
d6eb06b6 291 /// Now analyze upgrade results
668896e5 292 if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
d6eb06b6 293 // OK so far, now update the modules record
294 $module->id = $currmodule->id;
295 if (! update_record('modules', $module)) {
296 error('Could not update '. $module->name .' record in modules table!');
173cc1c3 297 }
d6eb06b6 298 remove_dir($CFG->dataroot . '/cache', true); // flush cache
299 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
300 echo '<hr />';
301 } else {
d6eb06b6 302 notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
173cc1c3 303 }
bbbf2d40 304
d6eb06b6 305 /// Update the capabilities table?
bbbf2d40 306 if (!update_capabilities('mod/'.$module->name)) {
307 error('Could not update '.$module->name.' capabilities!');
308 }
309
173cc1c3 310 $updated_modules = true;
bbbf2d40 311
173cc1c3 312 } else {
583fad99 313 upgrade_log_start();
88a7228a 314 error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
173cc1c3 315 }
316
317 } else { // module not installed yet, so install it
583fad99 318 if (!$updated_modules) {
a36f058e 319 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
320 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
321 false, '&nbsp;', '&nbsp;');
173cc1c3 322 }
583fad99 323 upgrade_log_start();
173cc1c3 324 print_heading($module->name);
325 $updated_modules = true;
326 $db->debug = true;
327 @set_time_limit(0); // To allow slow databases to complete the long SQL
d6eb06b6 328
329 /// Both old .sql files and new install.xml are supported
330 /// but we priorize install.xml (XMLDB) if present
331 if (file_exists($fullmod . '/db/install.xml') && $CFG->xmldb_enabled) {
332 $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
333 } else {
334 $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method
335 }
336
e79a09a2 337 $db->debug = false;
d6eb06b6 338 /// Continue with the instalation, roles and other stuff
339 if ($status) {
88a7228a 340 if ($module->id = insert_record('modules', $module)) {
bbbf2d40 341 if (!update_capabilities('mod/'.$module->name)) {
342 error('Could not set up the capabilities for '.$module->name.'!');
343 }
a8f68426 344 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
88a7228a 345 echo '<hr />';
173cc1c3 346 } else {
88a7228a 347 error($module->name .' module could not be added to the module list!');
173cc1c3 348 }
349 } else {
88a7228a 350 error($module->name .' tables could NOT be set up successfully!');
173cc1c3 351 }
352 }
e5bd4e58 353
354 /// Check submodules of this module if necessary
355
356 include_once($fullmod.'/lib.php'); // defines upgrading function
357
358 $submoduleupgrade = $module->name.'_upgrade_submodules';
359 if (function_exists($submoduleupgrade)) {
360 $submoduleupgrade();
361 }
362
363
364 /// Run any defaults or final code that is necessary for this module
365
a5c0990e 366 if ( is_readable($fullmod .'/defaults.php')) {
367 // Insert default values for any important configuration variables
9e6e7502 368 unset($defaults);
a5c0990e 369 include_once($fullmod .'/defaults.php');
f9a2e515 370 if (!empty($defaults)) {
371 foreach ($defaults as $name => $value) {
372 if (!isset($CFG->$name)) {
373 set_config($name, $value);
374 }
a5c0990e 375 }
376 }
377 }
173cc1c3 378 }
379
583fad99 380 upgrade_log_finish(); // finish logging if started
381
382 if ($updated_modules) {
173cc1c3 383 print_continue($return);
136f43dc 384 print_footer();
173cc1c3 385 die;
386 }
387}
388
f3221af9 389/**
390 * This function will return FALSE if the lock fails to be set (ie, if it's already locked)
80be7ee3 391 *
392 * @param string $name ?
393 * @param bool $value ?
394 * @param int $staleafter ?
395 * @param bool $clobberstale ?
396 * @todo Finish documenting this function
f3221af9 397 */
398function set_cron_lock($name,$value=true,$staleafter=7200,$clobberstale=false) {
399
400 if (empty($name)) {
401 mtrace("Tried to get a cron lock for a null fieldname");
402 return false;
403 }
404
405 if (empty($value)) {
406 set_config($name,0);
407 return true;
408 }
409
410 if ($config = get_record('config','name',$name)) {
411 if (empty($config->value)) {
412 set_config($name,time());
413 } else {
414 // check for stale.
415 if ((time() - $staleafter) > $config->value) {
416 mtrace("STALE LOCKFILE FOR $name - was $config->value");
417 if (!empty($clobberstale)) {
418 set_config($name,time());
419 return true;
420 }
421 } else {
422 return false; // was not stale - ie, we're ok to still be running.
423 }
424 }
425 }
426 else {
427 set_config($name,time());
428 }
429 return true;
430}
a597f8a8 431
fb06b255 432function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
a597f8a8 433 static $starttime;
434 static $lasttime;
435
436 if (empty($starttime)) {
437 $starttime = $lasttime = time();
438 $lasttime = $starttime - $updatetime;
439 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
440 echo '<div id="bar" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
441 echo '<div id="slider" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
442 echo '</div>';
443 echo '<div id="text" align="center" style="width:500px;"></div>';
444 echo '</td></tr></table>';
445 echo '</div>';
446 }
447
a597f8a8 448 $now = time();
449
450 if ($done && (($now - $lasttime) >= $updatetime)) {
451 $elapsedtime = $now - $starttime;
452 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
453 $percentage = format_float((float)$done / (float)$total, 2);
454 $width = (int)(500 * $percentage);
455
fb06b255 456 if ($projectedtime > 10) {
457 $projectedtext = ' Ending: '.format_time($projectedtime);
458 } else {
459 $projectedtext = '';
460 }
461
a597f8a8 462 echo '<script>';
fb06b255 463 echo 'document.getElementById("text").innerHTML = "'.addslashes($donetext).' '.$done.' done.'.$projectedtext.'";'."\n";
a597f8a8 464 echo 'document.getElementById("slider").style.width = \''.$width.'px\';'."\n";
465 echo '</script>';
466
467 $lasttime = $now;
468 sleep($sleeptime);
469 }
470}
583fad99 471
472////////////////////////////////////////////////
473/// upgrade logging functions
474////////////////////////////////////////////////
475
476$upgradeloghandle = false;
26c91c73 477$upgradelogbuffer = '';
478// I did not find out how to use static variable in callback function,
479// the problem was that I could not flush the static buffer :-(
480global $upgradeloghandle, $upgradelogbuffer;
583fad99 481
482/**
483 * Check if upgrade is already running.
484 *
485 * If anything goes wrong due to missing call to upgrade_log_finish()
486 * just restart the browser.
487 *
488 * @param string warning message indicating upgrade is already running
489 * @param int page reload timeout
490 */
491function upgrade_check_running($message, $timeout) {
492 if (!empty($_SESSION['upgraderunning'])) {
493 print_header();
494 redirect(me(), $message, $timeout);
495 }
496}
497
498/**
499 * Start logging of output into file (if not disabled) and
500 * prevent aborting and concurrent execution of upgrade script.
501 *
502 * Please note that you can not write into session variables after calling this function!
503 *
504 * This function may be called repeatedly.
505 */
506function upgrade_log_start() {
426a369b 507 global $CFG, $upgradeloghandle;
583fad99 508
509 if (!empty($_SESSION['upgraderunning'])) {
510 return; // logging already started
511 }
512
513 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
514 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
426a369b 515 if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
516 session_write_close(); // from now on user can reload page - will be displayed warning
517 }
583fad99 518 make_upload_directory('upgradelogs');
519 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
dedb2304 520 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
583fad99 521}
522
523/**
524 * Terminate logging of output, flush all data, allow script aborting
525 * and reopen session for writing. Function error() does terminate the logging too.
526 *
527 * Please make sure that each upgrade_log_start() is properly terminated by
528 * this function or error().
529 *
530 * This function may be called repeatedly.
531 */
532function upgrade_log_finish() {
426a369b 533 global $CFG, $upgradeloghandle, $upgradelogbuffer;
583fad99 534
535 if (empty($_SESSION['upgraderunning'])) {
536 return; // logging already terminated
537 }
538
539 @ob_end_flush();
26c91c73 540 if ($upgradelogbuffer !== '') {
541 @fwrite($upgradeloghandle, $upgradelogbuffer);
40896537 542 $upgradelogbuffer = '';
26c91c73 543 }
544 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
545 @fclose($upgradeloghandle);
40896537 546 $upgradeloghandle = false;
26c91c73 547 }
426a369b 548 if (empty($CFG->dbsessions)) {
549 @session_start(); // ignore header errors, we only need to reopen session
550 }
583fad99 551 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
552 if (connection_aborted()) {
553 die;
554 }
555 @ignore_user_abort(false);
556}
557
558/**
559 * Callback function for logging into files. Not more than one file is created per minute,
560 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
561 *
562 * This function must not output any characters or throw warnigns and errors!
563 */
564function upgrade_log_callback($string) {
26c91c73 565 global $CFG, $upgradeloghandle, $upgradelogbuffer;
583fad99 566
567 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
568 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
26c91c73 569 $upgradelogbuffer .= $string;
570 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
571 @fwrite($upgradeloghandle, $upgradelogbuffer);
572 $upgradelogbuffer = '';
573 }
583fad99 574 } else {
575 $upgradeloghandle = 'error';
576 }
577 }
578 return $string;
579}
580
57e35f32 581/**
582 * Try to verify that dataroot is not accessible from web.
583 * It is not 100% correct but might help to reduce number of vulnerable sites.
584 *
585 * Protection from httpd.conf and .htaccess is not detected properly.
586 */
587function is_dataroot_insecure() {
588 global $CFG;
589
590 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
591
592 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
593 $rp = strrev(trim($rp, '/'));
594 $rp = explode('/', $rp);
595 foreach($rp as $r) {
596 if (strpos($siteroot, '/'.$r.'/') === 0) {
597 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
598 } else {
599 break; // probably alias root
600 }
601 }
602
603 $siteroot = strrev($siteroot);
604 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
605
606 if (strpos($dataroot, $siteroot) === 0) {
607 return true;
608 }
609 return false;
610}
6e4dc10f 611
612/// =============================================================================================================
613/// administration tree classes and functions
614
615
616// n.b. documentation is still in progress for this code
617
618/// INTRODUCTION
619
620/// This file performs the following tasks:
621/// -it defines the necessary objects and interfaces to build the Moodle
622/// admin hierarchy
623/// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
624/// and admin_externalpage_print_footer() functions used on admin pages
625
626/// ADMIN_SETTING OBJECTS
627
628/// Moodle settings are represented by objects that inherit from the admin_setting
629/// class. These objects encapsulate how to read a setting, how to write a new value
630/// to a setting, and how to appropriately display the HTML to modify the setting.
631
632/// ADMIN_SETTINGPAGE OBJECTS
633
634/// The admin_setting objects are then grouped into admin_settingpages. The latter
635/// appear in the Moodle admin tree block. All interaction with admin_settingpage
636/// objects is handled by the admin/settings.php file.
637
638/// ADMIN_EXTERNALPAGE OBJECTS
639
640/// There are some settings in Moodle that are too complex to (efficiently) handle
641/// with admin_settingpages. (Consider, for example, user management and displaying
642/// lists of users.) In this case, we use the admin_externalpage object. This object
643/// places a link to an external PHP file in the admin tree block.
644
645/// If you're using an admin_externalpage object for some settings, you can take
646/// advantage of the admin_externalpage_* functions. For example, suppose you wanted
647/// to add a foo.php file into admin. First off, you add the following line to
648/// admin/settings/first.php (at the end of the file) or to some other file in
649/// admin/settings:
650
651/// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
652/// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
653
654/// Next, in foo.php, your file structure would resemble the following:
655
656/// require_once('.../config.php');
657/// require_once($CFG->libdir.'/adminlib.php');
658/// $adminroot = admin_get_root();
659/// admin_externalpage_setup('foo', $adminroot);
660/// // functionality like processing form submissions goes here
661/// admin_externalpage_print_header($adminroot);
662/// // your HTML goes here
663/// admin_externalpage_print_footer($adminroot);
664
665/// The admin_externalpage_setup() function call ensures the user is logged in,
666/// and makes sure that they have the proper role permission to access the page.
667
668/// The admin_externalpage_print_header() function prints the header (it figures
669/// out what category and subcategories the page is classified under) and ensures
670/// that you're using the admin pagelib (which provides the admin tree block and
671/// the admin bookmarks block).
672
673/// The admin_externalpage_print_footer() function properly closes the tables
674/// opened up by the admin_externalpage_print_header() function and prints the
675/// standard Moodle footer.
676
677/// ADMIN_CATEGORY OBJECTS
678
679/// Above and beyond all this, we have admin_category objects. These objects
680/// appear as folders in the admin tree block. They contain admin_settingpage's,
681/// admin_externalpage's, and other admin_category's.
682
683/// OTHER NOTES
684
685/// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
686/// from part_of_admin_tree (a pseudointerface). This interface insists that
687/// a class has a check_access method for access permissions, a locate method
688/// used to find a specific node in the admin tree, and a path method used
689/// to determine the path to a specific node in the $ADMIN tree.
690
691/// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
692/// interface ensures that the class implements a recursive add function which
693/// accepts a part_of_admin_tree object and searches for the proper place to
694/// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
695
696/// Please note that the $this->name field of any part_of_admin_tree must be
697/// UNIQUE throughout the ENTIRE admin tree.
698
699/// The $this->name field of an admin_setting object (which is *not* part_of_
700/// admin_tree) must be unique on the respective admin_settingpage where it is
701/// used.
702
703
704/// MISCELLANEOUS STUFF (used by classes defined below) ///////////////////////
705include_once($CFG->dirroot . '/backup/lib.php');
706
707/// CLASS DEFINITIONS /////////////////////////////////////////////////////////
708
709/**
710 * Pseudointerface for anything appearing in the admin tree
711 *
712 * The pseudointerface that is implemented by anything that appears in the admin tree
713 * block. It forces inheriting classes to define a method for checking user permissions
714 * and methods for finding something in the admin tree.
715 *
716 * @author Vincenzo K. Marcovecchio
717 * @package admin
718 */
719class part_of_admin_tree {
720
721 /**
722 * Finds a named part_of_admin_tree.
723 *
724 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
725 * and not parentable_part_of_admin_tree, then this function should only check if
726 * $this->name matches $name. If it does, it should return a reference to $this,
727 * otherwise, it should return a reference to NULL.
728 *
729 * If a class inherits parentable_part_of_admin_tree, this method should be called
730 * recursively on all child objects (assuming, of course, the parent object's name
731 * doesn't match the search criterion).
732 *
733 * @param string $name The internal name of the part_of_admin_tree we're searching for.
734 * @return mixed An object reference or a NULL reference.
735 */
736 function &locate($name) {
737 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
738 return;
739 }
4672d955 740
741 /**
742 * Removes named part_of_admin_tree.
743 *
744 * @param string $name The internal name of the part_of_admin_tree we want to remove.
745 * @return boolean success.
746 */
747 function prune($name) {
748 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
749 return;
750 }
751
6e4dc10f 752 /**
753 * Verifies current user's access to this part_of_admin_tree.
754 *
755 * Used to check if the current user has access to this part of the admin tree or
756 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
757 * then this method is usually just a call to has_capability() in the site context.
758 *
759 * If a class inherits parentable_part_of_admin_tree, this method should return the
760 * logical OR of the return of check_access() on all child objects.
761 *
762 * @return bool True if the user has access, false if she doesn't.
763 */
764 function check_access() {
765 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
766 return;
767 }
768
769 /**
770 * Determines the path to $name in the admin tree.
771 *
772 * Used to determine the path to $name in the admin tree. If a class inherits only
773 * part_of_admin_tree and not parentable_part_of_admin_tree, then this method should
774 * check if $this->name matches $name. If it does, $name is pushed onto the $path
775 * array (at the end), and $path should be returned. If it doesn't, NULL should be
776 * returned.
777 *
778 * If a class inherits parentable_part_of_admin_tree, it should do the above, but not
779 * return NULL on failure. Instead, it pushes $this->name onto $path, and then
780 * recursively calls path() on its child objects. If any are non-NULL, it should
781 * return $path (being certain that the last element of $path is equal to $name).
782 * If they are all NULL, it returns NULL.
783 *
784 * @param string $name The internal name of the part_of_admin_tree we're searching for.
785 * @param array $path Not used on external calls. Defaults to empty array.
786 * @return mixed If found, an array containing the internal names of each part_of_admin_tree that leads to $name. If not found, NULL.
787 */
788 function path($name, $path = array()) {
789 trigger_error('Admin class does not implement method <strong>path()</strong>', E_USER_WARNING);
790 return;
791 }
792}
793
794/**
795 * Pseudointerface implemented by any part_of_admin_tree that has children.
796 *
797 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
798 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
799 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
800 * include an add method for adding other part_of_admin_tree objects as children.
801 *
802 * @author Vincenzo K. Marcovecchio
803 * @package admin
804 */
805class parentable_part_of_admin_tree extends part_of_admin_tree {
806
807 /**
808 * Adds a part_of_admin_tree object to the admin tree.
809 *
810 * Used to add a part_of_admin_tree object to this object or a child of this
811 * object. $something should only be added if $destinationname matches
812 * $this->name. If it doesn't, add should be called on child objects that are
813 * also parentable_part_of_admin_tree's.
814 *
815 * @param string $destinationname The internal name of the new parent for $something.
816 * @param part_of_admin_tree &$something The object to be added.
817 * @return bool True on success, false on failure.
818 */
819 function add($destinationname, &$something) {
820 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
821 return;
822 }
823
824}
825
826/**
827 * The object used to represent folders (a.k.a. categories) in the admin tree block.
828 *
829 * Each admin_category object contains a number of part_of_admin_tree objects.
830 *
831 * @author Vincenzo K. Marcovecchio
832 * @package admin
833 */
834class admin_category extends parentable_part_of_admin_tree {
835
836 /**
837 * @var mixed An array of part_of_admin_tree objects that are this object's children
838 */
839 var $children;
840
841 /**
842 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
843 */
844 var $name;
845
846 /**
847 * @var string The displayed name for this category. Usually obtained through get_string()
848 */
849 var $visiblename;
850
851 // constructor for an empty admin category
852 // $name is the internal name of the category. it MUST be unique in the entire hierarchy
853 // $visiblename is the displayed name of the category. use a get_string for this
854
855 /**
856 * Constructor for an empty admin category
857 *
858 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
859 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
860 * @return mixed Returns the new object.
861 */
862 function admin_category($name, $visiblename) {
863 $this->children = array();
864 $this->name = $name;
865 $this->visiblename = $visiblename;
866 }
867
868 /**
869 * Finds the path to the part_of_admin_tree called $name.
870 *
871 * @param string $name The internal name that we're searching for.
872 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
873 * @return mixed An array of internal names that leads to $name, or NULL if not found.
874 */
875 function path($name, $path = array()) {
876
877 $path[count($path)] = $this->name;
878
879 if ($this->name == $name) {
880 return $path;
881 }
882
883 foreach($this->children as $child) {
884 if ($return = $child->path($name, $path)) {
885 return $return;
886 }
887 }
888
889 return NULL;
890
891 }
892
893 /**
894 * Returns a reference to the part_of_admin_tree object with internal name $name.
895 *
896 * @param string $name The internal name of the object we want.
897 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
898 */
899 function &locate($name) {
900
901 if ($this->name == $name) {
902 return $this;
903 }
904
905 foreach($this->children as $child) {
906 if ($return =& $child->locate($name)) {
907 return $return;
908 }
909 }
910 $return = NULL;
911 return $return;
912 }
913
4672d955 914 /**
915 * Removes part_of_admin_tree object with internal name $name.
916 *
917 * @param string $name The internal name of the object we want to remove.
918 * @return boolean success
919 */
920 function prune($name) {
921
922 if ($this->name == $name) {
923 return false; //can not remove itself
924 }
925
926 foreach($this->children as $precedence => $child) {
927 if ($child->name == $name) {
928 // found it!
929 unset($this->children[$precedence]);
930 return true;
931 }
932 if ($this->children[$precedence]->prune($name)) {
933 return true;
934 }
935 }
936 return false;
937 }
938
6e4dc10f 939 /**
940 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
941 *
942 * @param string $destinationame The internal name of the immediate parent that we want for &$something.
943 * @param mixed &$something A part_of_admin_tree object to be added.
944 * @param int $precedence The precedence of &$something when displayed. Smaller numbers mean it'll be displayed higher up in the admin menu. Defaults to '', meaning "next available position".
945 * @return bool True if successfully added, false if &$something is not a part_of_admin_tree or if $name is not found.
946 */
947 function add($destinationname, &$something, $precedence = '') {
948
949 if (!is_a($something, 'part_of_admin_tree')) {
950 return false;
951 }
952
953 if ($destinationname == $this->name) {
954 if ($precedence === '') {
955 $this->children[] = $something;
956 } else {
957 if (isset($this->children[$precedence])) { // this should never, ever be triggered in a release version of moodle.
958 echo ('<font style="color: red;">There is a precedence conflict in the category ' . $this->name . '. The object named ' . $something->name . ' is overwriting the object named ' . $this->children[$precedence]->name . '.</font><br />');
959 }
960 $this->children[$precedence] = $something;
961 }
962 return true;
963 }
964
965 unset($entries);
966
967 $entries = array_keys($this->children);
968
969 foreach($entries as $entry) {
970 $child =& $this->children[$entry];
971 if (is_a($child, 'parentable_part_of_admin_tree')) {
972 if ($child->add($destinationname, $something, $precedence)) {
973 return true;
974 }
975 }
976 }
977
978 return false;
979
980 }
981
982 /**
983 * Checks if the user has access to anything in this category.
984 *
985 * @return bool True if the user has access to atleast one child in this category, false otherwise.
986 */
987 function check_access() {
988
989 $return = false;
990 foreach ($this->children as $child) {
991 $return = $return || $child->check_access();
992 }
993
994 return $return;
995
996 }
997
998}
999
1000/**
1001 * Links external PHP pages into the admin tree.
1002 *
1003 * See detailed usage example at the top of this document (adminlib.php)
1004 *
1005 * @author Vincenzo K. Marcovecchio
1006 * @package admin
1007 */
1008class admin_externalpage extends part_of_admin_tree {
1009
1010 /**
1011 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1012 */
1013 var $name;
1014
1015 /**
1016 * @var string The displayed name for this external page. Usually obtained through get_string().
1017 */
1018 var $visiblename;
1019
1020 /**
1021 * @var string The external URL that we should link to when someone requests this external page.
1022 */
1023 var $url;
1024
1025 /**
1026 * @var string The role capability/permission a user must have to access this external page.
1027 */
1028 var $role;
1029
1030 /**
1031 * Constructor for adding an external page into the admin tree.
1032 *
1033 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1034 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1035 * @param string $url The external URL that we should link to when someone requests this external page.
1036 * @param string $role The role capability/permission a user must have to access this external page. Defaults to 'moodle/legacy:admin'.
1037 */
1038 function admin_externalpage($name, $visiblename, $url, $role = 'moodle/legacy:admin') {
1039 $this->name = $name;
1040 $this->visiblename = $visiblename;
1041 $this->url = $url;
1042 $this->role = $role;
1043 }
1044
1045 /**
1046 * Finds the path to the part_of_admin_tree called $name.
1047 *
1048 * @param string $name The internal name that we're searching for.
1049 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
1050 * @return mixed An array of internal names that leads to $name, or NULL if not found.
1051 */
1052 function path($name, $path = array()) {
1053 if ($name == $this->name) {
1054 array_push($path, $this->name);
1055 return $path;
1056 } else {
1057 return NULL;
1058 }
1059 }
1060
1061 /**
1062 * Returns a reference to the part_of_admin_tree object with internal name $name.
1063 *
1064 * @param string $name The internal name of the object we want.
1065 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1066 */
1067 function &locate($name) {
1068 $return = ($this->name == $name ? $this : NULL);
1069 return $return;
1070 }
4672d955 1071
1072 function prune($name) {
1073 return false;
1074 }
1075
6e4dc10f 1076 /**
1077 * Determines if the current user has access to this external page based on $this->role.
1078 *
1079 * @uses CONTEXT_SYSTEM
1080 * @uses SITEID
1081 * @return bool True if user has access, false otherwise.
1082 */
1083 function check_access() {
1084 if (!get_site()) {
1085 return true; // no access check before site is fully set up
1086 }
1087 $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
1088 return has_capability($this->role, $context);
1089 }
1090
1091}
1092
1093/**
1094 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1095 *
1096 * @author Vincenzo K. Marcovecchio
1097 * @package admin
1098 */
1099class admin_settingpage extends part_of_admin_tree {
1100
1101 /**
1102 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1103 */
1104 var $name;
1105
1106 /**
1107 * @var string The displayed name for this external page. Usually obtained through get_string().
1108 */
1109 var $visiblename;
1110 /**
1111 * @var mixed An array of admin_setting objects that are part of this setting page.
1112 */
1113 var $settings;
1114
1115 /**
1116 * @var string The role capability/permission a user must have to access this external page.
1117 */
1118 var $role;
1119
1120 // see admin_category
1121 function path($name, $path = array()) {
1122 if ($name == $this->name) {
1123 array_push($path, $this->name);
1124 return $path;
1125 } else {
1126 return NULL;
1127 }
1128 }
1129
1130 // see admin_category
1131 function &locate($name) {
1132 $return = ($this->name == $name ? $this : NULL);
1133 return $return;
1134 }
4672d955 1135
1136 function prune($name) {
1137 return false;
1138 }
1139
6e4dc10f 1140 // see admin_externalpage
1141 function admin_settingpage($name, $visiblename, $role = 'moodle/legacy:admin') {
1142 global $CFG;
1143 $this->settings = new stdClass();
1144 $this->name = $name;
1145 $this->visiblename = $visiblename;
1146 $this->role = $role;
1147 }
1148
1149 // 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
1150 // n.b. each admin_setting in an admin_settingpage must have a unique internal name
1151 // &$setting is the admin_setting object you want to add
1152 // returns true if successful, false if not (will fail if &$setting is an admin_setting or child thereof)
1153 function add(&$setting) {
1154 if (is_a($setting, 'admin_setting')) {
1155 $this->settings->{$setting->name} =& $setting;
1156 return true;
1157 }
1158 return false;
1159 }
1160
1161 // see admin_externalpage
1162 function check_access() {
1163 if (!get_site()) {
1164 return true; // no access check before site is fully set up
1165 }
1166 $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
1167 return has_capability($this->role, $context);
1168 }
1169
1170 // outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1171 // returns a string of the html
1172 function output_html() {
1173 $return = '<table class="generaltable" width="100%" border="0" align="center" cellpadding="5" cellspacing="1">' . "\n";
1174 foreach($this->settings as $setting) {
1175 $return .= $setting->output_html();
1176 }
1177 $return .= '</table>';
1178 return $return;
1179 }
1180
1181 // writes settings (the ones that have been added to this admin_settingpage) to the database, or wherever else they're supposed to be written to
1182 // -- calls write_setting() to each child setting, sending it only the data that matches each setting's internal name
1183 // $data should be the result from data_submitted()
1184 // returns an empty string if everything went well, otherwise returns a printable error string (that's language-specific)
1185 function write_settings($data) {
1186 $return = '';
1187 foreach($this->settings as $setting) {
1188 if (isset($data['s_' . $setting->name])) {
1189 $return .= $setting->write_setting($data['s_' . $setting->name]);
1190 } else {
1191 $return .= $setting->write_setting('');
1192 }
1193 }
1194 return $return;
1195 }
1196
1197}
1198
1199
1200// read & write happens at this level; no authentication
1201class admin_setting {
1202
1203 var $name;
1204 var $visiblename;
1205 var $description;
1206 var $defaultsetting;
1207
1208 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1209 $this->name = $name;
1210 $this->visiblename = $visiblename;
1211 $this->description = $description;
1212 $this->defaultsetting = $defaultsetting;
1213 }
1214
1215 function get_setting() {
1216 return NULL; // has to be overridden
1217 }
1218
1219 function write_setting($data) {
1220 return; // has to be overridden
1221 }
1222
1223 function output_html() {
1224 return; // has to be overridden
1225 }
1226
1227}
1228
1229
1230class admin_setting_configtext extends admin_setting {
1231
1232 var $paramtype;
1233
50999a0b 1234 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
6e4dc10f 1235 $this->paramtype = $paramtype;
1236 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1237 }
1238
cc73de71 1239 // returns a string or NULL
6e4dc10f 1240 function get_setting() {
1241 global $CFG;
c8218a42 1242 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
6e4dc10f 1243 }
1244
cc73de71 1245 // $data is a string
6e4dc10f 1246 function write_setting($data) {
c235598d 1247 if (is_string($this->paramtype)) {
1248 if (!$this->validate($data)) {
1249 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
1250 }
1251 } else {
cc73de71 1252 if ($data != clean_param($data, $this->paramtype)) {
1253 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
1254 }
c235598d 1255 }
6e4dc10f 1256 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1257 }
1258
c235598d 1259 function validate($data) {
1260 return preg_match($this->paramtype, $data);
1261 }
1262
6e4dc10f 1263 function output_html() {
c8218a42 1264 if ($this->get_setting() === NULL) {
1265 $current = $this->defaultsetting;
1266 } else {
1267 $current = $this->get_setting();
1268 }
6e4dc10f 1269 return '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td>' .
c8218a42 1270 '<td align="left"><input type="text" size="50" name="s_'. $this->name .'" value="'. $current .'" /></td></tr>' .
6e4dc10f 1271 '<tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
1272 }
1273
1274}
1275
1276class admin_setting_configcheckbox extends admin_setting {
1277
1278 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting) {
1279 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1280 }
1281
1282 function get_setting() {
1283 global $CFG;
1284 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1285 }
1286
1287 function write_setting($data) {
1288 if ($data == '1') {
1289 return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1290 } else {
1291 return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1292 }
1293 }
1294
1295 function output_html() {
c8218a42 1296 if ($this->get_setting() === NULL) {
1297 $current = $this->defaultsetting;
1298 } else {
1299 $current = $this->get_setting();
1300 }
6e4dc10f 1301 return '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td>' .
c8218a42 1302 '<td align="left"><input type="checkbox" size="50" name="s_'. $this->name .'" value="1" ' . ($current == true ? 'checked="checked"' : '') . ' /></td></tr>' .
6e4dc10f 1303 '<tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
1304 }
1305
1306}
1307
1308class admin_setting_configselect extends admin_setting {
1309
1310 var $choices;
1311
1312 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
1313 $this->choices = $choices;
1314 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1315 }
1316
1317 function get_setting() {
1318 global $CFG;
1319 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1320 }
1321
1322 function write_setting($data) {
1323 // check that what we got was in the original choices
1324 // or that the data is the default setting - needed during install when choices can not be constructed yet
1325 if ($data != $this->defaultsetting and ! in_array($data, array_keys($this->choices))) {
1326 return 'Error setting ' . $this->visiblename . '<br />';
1327 }
1328
1329 return (set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1330 }
1331
1332 function output_html() {
c8218a42 1333 if ($this->get_setting() === NULL) {
1334 $current = $this->defaultsetting;
1335 } else {
1336 $current = $this->get_setting();
1337 }
6e4dc10f 1338 $return = '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td><td align="left"><select name="s_' . $this->name .'">';
1339 foreach ($this->choices as $key => $value) {
c8218a42 1340 $return .= '<option value="' . $key . '"' . ($key == $current ? ' selected="selected"' : '') . '>' . $value . '</option>';
6e4dc10f 1341 }
1342 $return .= '</select></td></tr><tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
1343 return $return;
1344 }
1345
1346}
1347
1348// this is a liiitle bit messy. we're using two selects, but we're returning them as an array named after $name (so we only use $name2
1349// internally for the setting)
1350class admin_setting_configtime extends admin_setting {
1351
1352 var $name2;
1353 var $choices;
1354 var $choices2;
6e4dc10f 1355
1356 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
1357 $this->name2 = $minutesname;
1358 $this->choices = array();
1359 for ($i = 0; $i < 24; $i++) {
1360 $this->choices[$i] = $i;
1361 }
1362 $this->choices2 = array();
1363 for ($i = 0; $i < 60; $i += 5) {
1364 $this->choices2[$i] = $i;
1365 }
1366 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
1367 }
1368
1369 function get_setting() {
1370 global $CFG;
cc73de71 1371 return (isset($CFG->{$this->name}) && isset($CFG->{$this->name2}) ? array('h' => $CFG->{$this->name}, 'm' => $CFG->{$this->name2}) : NULL);
6e4dc10f 1372 }
1373
1374 function write_setting($data) {
1375 // check that what we got was in the original choices
1376 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
1377 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1378 }
1379
1380 return (set_config($this->name, $data['h']) && set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1381 }
1382
1383 function output_html() {
cc73de71 1384 if ($this->get_setting() === NULL) {
1385 $currentsetting = $this->defaultsetting;
1386 } else {
1387 $currentsetting = $this->get_setting();
6e4dc10f 1388 }
1389 $return = '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td><td align="left"><select name="s_' . $this->name .'[h]">';
1390 foreach ($this->choices as $key => $value) {
cc73de71 1391 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['h'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
6e4dc10f 1392 }
1393 $return .= '</select>&nbsp;&nbsp;&nbsp;<select name="s_' . $this->name . '[m]">';
1394 foreach ($this->choices2 as $key => $value) {
cc73de71 1395 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['m'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
6e4dc10f 1396 }
1397 $return .= '</select></td></tr><tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
1398 return $return;
1399 }
1400
1401}
1402
1403class admin_setting_configmultiselect extends admin_setting_configselect {
1404
1405 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
1406 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1407 }
1408
1409 function get_setting() {
1410 global $CFG;
1411 return (isset($CFG->{$this->name}) ? explode(',', $CFG->{$this->name}) : NULL);;
1412 }
1413
1414 function write_setting($data) {
1415 foreach ($data as $datum) {
1416 if (! in_array($datum, array_keys($this->choices))) {
1417 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1418 }
1419 }
1420
1421 return (set_config($this->name, implode(',',$data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1422 }
1423
1424 function output_html() {
cc73de71 1425 if ($this->get_setting() === NULL) {
1426 $currentsetting = $this->defaultsetting;
1427 } else {
1428 $currentsetting = $this->get_setting();
6e4dc10f 1429 }
1430 $return = '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td><td align="left"><select name="s_' . $this->name .'[]" size="10" multiple="multiple">';
1431 foreach ($this->choices as $key => $value) {
1432 $return .= '<option value="' . $key . '"' . (in_array($key,$currentsetting) ? ' selected="selected"' : '') . '>' . $value . '</option>';
1433 }
1434 $return .= '</select></td></tr><tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
1435 return $return;
1436 }
1437
1438}
1439
1440class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
1441
1442 function admin_setting_special_adminseesall() {
1443 $name = 'calendar_adminseesall';
1444 $visiblename = get_string('adminseesall', 'admin');
1445 $description = get_string('helpadminseesall', 'admin');
1446 parent::admin_setting($name, $visiblename, $description, 0);
1447 }
1448
1449 function write_setting($data) {
1450 global $SESSION;
1451 unset($SESSION->cal_courses_shown);
1452 parent::write_setting($data);
1453 }
1454}
1455
1456class admin_setting_sitesetselect extends admin_setting_configselect {
1457
1458 var $id;
1459
1460 function admin_setting_sitesetselect($name, $visiblename, $description, $defaultsetting, $choices) {
1461
1462 $this->id = SITEID;
1463 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1464
1465 }
1466
1467 function get_setting() {
1468 $site = get_site();
1469 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1470 }
1471
1472 function write_setting($data) {
1473 if (!in_array($data, array_keys($this->choices))) {
1474 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1475 }
1476 $record = new stdClass();
1477 $record->id = $this->id;
1478 $temp = $this->name;
1479 $record->$temp = $data;
1480 $record->timemodified = time();
1481 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1482 }
1483
1484}
1485
1486
e0f6e995 1487class admin_setting_courselist_frontpage extends admin_setting_configselect {
6e4dc10f 1488
e0f6e995 1489 function admin_setting_courselist_frontpage($loggedin) {
6e4dc10f 1490 global $CFG;
1491 require_once($CFG->dirroot . '/course/lib.php');
1492 $name = 'frontpage' . ($loggedin ? 'loggedin' : '');
1493 $visiblename = get_string('frontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1494 $description = get_string('configfrontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1495 $choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
1496 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
1497 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
1498 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
1499 '' => get_string('none'));
1500 if (count_records("course") > FRONTPAGECOURSELIMIT) {
1501 unset($choices[FRONTPAGECOURSELIST]);
1502 }
4672d955 1503 $defaults = FRONTPAGECOURSELIST.',,,';
e0f6e995 1504 parent::admin_setting_configselect($name, $visiblename, $description, $defaults, $choices);
6e4dc10f 1505 }
1506
1507 function get_setting() {
1508 global $CFG;
1509 return (isset($CFG->{$this->name}) ? explode(',', $CFG->{$this->name}) : NULL);
1510 }
1511
1512 function write_setting($data) {
1513 if (empty($data)) {
1514 $data = array();
e0f6e995 1515 } if (!is_array($data)) {
1516 $data = explode(',', $data);
6e4dc10f 1517 }
1518 foreach($data as $datum) {
1519 if (! in_array($datum, array_keys($this->choices))) {
1520 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1521 }
1522 }
1523 return (set_config($this->name, implode(',', $data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1524 }
1525
1526 function output_html() {
cc73de71 1527 if ($this->get_setting() === NULL) {
1528 $currentsetting = $this->defaultsetting;
1529 } else {
1530 $currentsetting = $this->get_setting();
6e4dc10f 1531 }
1532 for ($i = 0; $i < count($this->choices) - 1; $i++) {
1533 if (!isset($currentsetting[$i])) {
1534 $currentsetting[$i] = 0;
1535 }
1536 }
1537 $return = '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td><td align="left">';
1538 for ($i = 0; $i < count($this->choices) - 1; $i++) {
1539 $return .='<select name="s_' . $this->name .'[]">';
1540 foreach ($this->choices as $key => $value) {
1541 $return .= '<option value="' . $key . '"' . ($key == $currentsetting[$i] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1542 }
1543 $return .= '</select>';
1544 if ($i !== count($this->choices) - 2) {
1545 $return .= '&nbsp;&nbsp;' . get_string('then') . '&nbsp;&nbsp;';
1546 }
1547 }
1548 $return .= '</td></tr><tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
1549 return $return;
6e4dc10f 1550 }
1551}
1552
1553class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
1554
1555 var $id;
1556
1557 function admin_setting_sitesetcheckbox($name, $visiblename, $description, $defaultsetting) {
1558
1559 $this->id = SITEID;
1560 parent::admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting);
1561
1562 }
1563
1564 function get_setting() {
1565 $site = get_site();
1566 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1567 }
1568
1569 function write_setting($data) {
1570 $record = new stdClass();
1571 $record->id = $this->id;
1572 $temp = $this->name;
1573 $record->$temp = ($data == '1' ? 1 : 0);
1574 $record->timemodified = time();
1575 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1576 }
1577
1578}
1579
1580class admin_setting_sitesettext extends admin_setting_configtext {
1581
1582 var $id;
1583
50999a0b 1584 function admin_setting_sitesettext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
6e4dc10f 1585
1586 $this->id = SITEID;
1587 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1588
1589 }
1590
1591 function get_setting() {
1592 $site = get_site();
1593 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1594 }
90cfbd0a 1595
6e4dc10f 1596 function write_setting($data) {
90cfbd0a 1597 if (is_string($this->paramtype)) {
1598 if (!$this->validate($data)) {
1599 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
1600 }
1601 } else {
1602 $data = clean_param($data, $this->paramtype);
1603 }
1604
6e4dc10f 1605 $record = new stdClass();
1606 $record->id = $this->id;
90cfbd0a 1607 $record->{$this->name} = $data;
6e4dc10f 1608 $record->timemodified = time();
1609 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1610 }
90cfbd0a 1611
1612 function validate($data) {
1613 return preg_match($this->paramtype, $data);
1614 }
1615
6e4dc10f 1616}
1617
1618class admin_setting_special_frontpagedesc extends admin_setting {
1619
1620 var $id;
1621
1622 function admin_setting_special_frontpagedesc() {
1623 $this->id = SITEID;
1624 $name = 'summary';
1625 $visiblename = get_string('frontpagedescription');
1626 $description = get_string('frontpagedescriptionhelp');
1627 parent::admin_setting($name, $visiblename, $description, '');
1628 }
1629
1630 function output_html() {
1631
cc73de71 1632 if ($this->get_setting() === NULL) {
1633 $currentsetting = $this->defaultsetting;
1634 } else {
1635 $currentsetting = $this->get_setting();
1636 }
1637
6e4dc10f 1638 $usehtmleditor = can_use_html_editor();
1639
1640 $return = '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td>' .
1641 '<td>';
1642
1643 ob_start(); // double-check the number of columns below... might overrun some screen resolutions
cc73de71 1644 print_textarea($usehtmleditor, 20, 40, 0, 0, 's_' . $this->name, $currentsetting);
6e4dc10f 1645
1646 if ($usehtmleditor) {
1647 use_html_editor();
1648 }
1649 $return .= ob_get_contents();
1650 ob_end_clean();
1651 $return .= '</td></tr><tr><td>&nbsp;</td><td>' . $this->description . '</td></tr>';
1652 return $return;
1653
1654 }
1655
1656 function get_setting() {
1657
1658 $site = get_site();
1659 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1660
1661 }
1662
1663 function write_setting($data) {
1664
1665 $data = addslashes(clean_param($data, PARAM_CLEANHTML));
1666
1667 $record = new stdClass();
1668 $record->id = $this->id;
1669 $temp = $this->name;
1670 $record->$temp = $data;
1671 $record->timemodified = time();
1672
1673 return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1674
1675 }
1676
1677}
1678
1679
1680class admin_setting_special_editorfontlist extends admin_setting {
1681
1682 var $items;
1683
1684 function admin_setting_special_editorfontlist() {
1685 global $CFG;
1686 $name = 'editorfontlist';
1687 $visiblename = get_string('editorfontlist', 'admin');
1688 $description = get_string('configeditorfontlist', 'admin');
6e4dc10f 1689 $defaults = array('k0' => 'Trebuchet',
1690 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
1691 'k1' => 'Arial',
1692 'v1' => 'arial,helvetica,sans-serif',
1693 'k2' => 'Courier New',
1694 'v2' => 'courier new,courier,monospace',
1695 'k3' => 'Georgia',
1696 'v3' => 'georgia,times new roman,times,serif',
1697 'k4' => 'Tahoma',
1698 'v4' => 'tahoma,arial,helvetica,sans-serif',
1699 'k5' => 'Times New Roman',
1700 'v5' => 'times new roman,times,serif',
1701 'k6' => 'Verdana',
1702 'v6' => 'verdana,arial,helvetica,sans-serif',
1703 'k7' => 'Impact',
1704 'v7' => 'impact',
1705 'k8' => 'Wingdings',
1706 'v8' => 'wingdings');
1707 parent::admin_setting($name, $visiblename, $description, $defaults);
1708 }
1709
1710 function get_setting() {
cc73de71 1711 global $CFG;
1712 if (isset($CFG->editorfontlist)) {
1713 $i = 0;
1714 $currentsetting = array();
1715 $items = explode(';', $CFG->editorfontlist);
1716 foreach ($items as $item) {
1717 $item = explode(':', $item);
1718 $currentsetting['k' . $i] = $item[0];
1719 $currentsetting['v' . $i] = $item[1];
1720 $i++;
1721 }
1722 return $currentsetting;
1723 } else {
1724 return NULL;
1725 }
6e4dc10f 1726 }
1727
1728 function write_setting($data) {
1729
1730 // there miiight be an easier way to do this :)
1731 // if this is changed, make sure the $defaults array above is modified so that this
1732 // function processes it correctly
1733
1734 $keys = array();
1735 $values = array();
1736
1737 foreach ($data as $key => $value) {
1738 if (substr($key,0,1) == 'k') {
1739 $keys[substr($key,1)] = $value;
1740 } elseif (substr($key,0,1) == 'v') {
1741 $values[substr($key,1)] = $value;
1742 }
1743 }
1744
1745 $result = '';
1746 for ($i = 0; $i < count($keys); $i++) {
1747 if (($keys[$i] !== '') && ($values[$i] !== '')) {
1748 $result .= clean_param($keys[$i],PARAM_NOTAGS) . ':' . clean_param($values[$i], PARAM_NOTAGS) . ';';
1749 }
1750 }
1751
1752 $result = substr($result, 0, -1); // trim the last semicolon
1753
1754 return (set_config($this->name, $result) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1755 }
1756
1757 function output_html() {
cc73de71 1758
1759 if ($this->get_setting() === NULL) {
1760 $currentsetting = $this->defaultsetting;
1761 } else {
1762 $currentsetting = $this->get_setting();
6e4dc10f 1763 }
cc73de71 1764
1765 $return = '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td><td align="left">';
1766 for ($i = 0; $i < count($currentsetting) / 2; $i++) {
1767 $return .= '<input type="text" name="s_editorfontlist[k' . $i . ']" value="' . $currentsetting['k' . $i] . '" size="20" />';
6e4dc10f 1768 $return .= '&nbsp;&nbsp;';
cc73de71 1769 $return .= '<input type="text" name="s_editorfontlist[v' . $i . ']" value="' . $currentsetting['v' . $i] . '" size="40" /><br />';
6e4dc10f 1770 }
cc73de71 1771 $return .= '<input type="text" name="s_editorfontlist[k' . $i . ']" value="" size="20" />';
6e4dc10f 1772 $return .= '&nbsp;&nbsp;';
cc73de71 1773 $return .= '<input type="text" name="s_editorfontlist[v' . $i . ']" value="" size="40" /><br />';
1774 $return .= '<input type="text" name="s_editorfontlist[k' . ($i + 1) . ']" value="" size="20" />';
6e4dc10f 1775 $return .= '&nbsp;&nbsp;';
cc73de71 1776 $return .= '<input type="text" name="s_editorfontlist[v' . ($i + 1) . ']" value="" size="40" />';
6e4dc10f 1777 $return .= '</td></tr><tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
1778 return $return;
1779 }
1780
1781}
1782
1783class admin_setting_special_editordictionary extends admin_setting_configselect {
1784
1785 function admin_setting_special_editordictionary() {
1786 $name = 'editordictionary';
1787 $visiblename = get_string('editordictionary','admin');
1788 $description = get_string('configeditordictionary', 'admin');
1789 $choices = $this->editor_get_dictionaries();
1790 if (! is_array($choices)) {
1791 $choices = array('');
1792 }
1793
1794 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
1795 }
1796
1797 // function borrowed from the old moodle/admin/editor.php, slightly modified
1798 function editor_get_dictionaries () {
1799 /// Get all installed dictionaries in the system
1800
1801 global $CFG;
1802
1803// error_reporting(E_ALL); // for debug, final version shouldn't have this...
1804 clearstatcache();
1805
1806 // If aspellpath isn't set don't even bother ;-)
1807 if (empty($CFG->aspellpath)) {
1808 return 'Empty aspell path!';
1809 }
1810
1811 // Do we have access to popen function?
1812 if (!function_exists('popen')) {
1813 return 'Popen function disabled!';
1814 }
1815
1816 $cmd = $CFG->aspellpath;
1817 $output = '';
1818 $dictionaries = array();
1819 $dicts = array();
1820
1821 if(!($handle = @popen(escapeshellarg($cmd) .' dump dicts', 'r'))) {
1822 return 'Couldn\'t create handle!';
1823 }
1824
1825 while(!feof($handle)) {
1826 $output .= fread($handle, 1024);
1827 }
1828 @pclose($handle);
1829
1830 $dictionaries = explode(chr(10), $output);
1831
1832 // Get rid of possible empty values
1833 if (is_array($dictionaries)) {
1834
1835 $cnt = count($dictionaries);
1836
1837 for ($i = 0; $i < $cnt; $i++) {
1838 if (!empty($dictionaries[$i])) {
1839 $dicts[] = $dictionaries[$i];
1840 }
1841 }
1842 }
1843
1844 if (count($dicts) >= 1) {
1845 return $dicts;
1846 }
1847
1848 return 'Error! Check your aspell installation!';
1849 }
1850
1851
1852
1853}
1854
1855
1856class admin_setting_special_editorhidebuttons extends admin_setting {
1857
1858 var $name;
1859 var $visiblename;
1860 var $description;
1861 var $items;
1862
1863 function admin_setting_special_editorhidebuttons() {
1864 $this->name = 'editorhidebuttons';
1865 $this->visiblename = get_string('editorhidebuttons', 'admin');
1866 $this->description = get_string('confeditorhidebuttons', 'admin');
1867 $this->defaultsetting = array();
1868 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
1869 $this->items = array('fontname' => '',
1870 'fontsize' => '',
1871 'formatblock' => '',
1872 'bold' => 'ed_format_bold.gif',
1873 'italic' => 'ed_format_italic.gif',
1874 'underline' => 'ed_format_underline.gif',
1875 'strikethrough' => 'ed_format_strike.gif',
1876 'subscript' => 'ed_format_sub.gif',
1877 'superscript' => 'ed_format_sup.gif',
1878 'copy' => 'ed_copy.gif',
1879 'cut' => 'ed_cut.gif',
1880 'paste' => 'ed_paste.gif',
1881 'clean' => 'ed_wordclean.gif',
1882 'undo' => 'ed_undo.gif',
1883 'redo' => 'ed_redo.gif',
1884 'justifyleft' => 'ed_align_left.gif',
1885 'justifycenter' => 'ed_align_center.gif',
1886 'justifyright' => 'ed_align_right.gif',
1887 'justifyfull' => 'ed_align_justify.gif',
1888 'lefttoright' => 'ed_left_to_right.gif',
1889 'righttoleft' => 'ed_right_to_left.gif',
1890 'insertorderedlist' => 'ed_list_num.gif',
1891 'insertunorderedlist' => 'ed_list_bullet.gif',
1892 'outdent' => 'ed_indent_less.gif',
1893 'indent' => 'ed_indent_more.gif',
1894 'forecolor' => 'ed_color_fg.gif',
1895 'hilitecolor' => 'ed_color_bg.gif',
1896 'inserthorizontalrule' => 'ed_hr.gif',
1897 'createanchor' => 'ed_anchor.gif',
1898 'createlink' => 'ed_link.gif',
1899 'unlink' => 'ed_unlink.gif',
1900 'insertimage' => 'ed_image.gif',
1901 'inserttable' => 'insert_table.gif',
1902 'insertsmile' => 'em.icon.smile.gif',
1903 'insertchar' => 'icon_ins_char.gif',
1904 'spellcheck' => 'spell-check.gif',
1905 'htmlmode' => 'ed_html.gif',
1906 'popupeditor' => 'fullscreen_maximize.gif',
1907 'search_replace' => 'ed_replace.gif');
1908 }
1909
1910 function get_setting() {
1911 global $CFG;
1912 return (isset($CFG->{$this->name}) ? explode(' ', $CFG->{$this->name}) : NULL);
1913 }
1914
1915 function write_setting($data) {
1916 $result = array();
1917 if (empty($data)) { $data = array(); }
1918 foreach ($data as $key => $value) {
1919 if (!in_array($key, array_keys($this->items))) {
1920 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1921 }
1922 if ($value == '1') {
1923 $result[] = $key;
1924 }
1925 }
1926 return (set_config($this->name, implode(' ',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1927 }
1928
1929 function output_html() {
1930
1931 global $CFG;
1932
1933 // checkboxes with input name="$this->name[$key]" value="1"
1934 // we do 15 fields per column
1935
cc73de71 1936 if ($this->get_setting() === NULL) {
1937 $currentsetting = $this->defaultsetting;
1938 } else {
1939 $currentsetting = $this->get_setting();
6e4dc10f 1940 }
1941
1942 $return = '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td><td align="left">';
1943
1944 $return .= '<table><tr><td valign="top" align="right">';
1945
1946 $count = 0;
1947
1948 foreach($this->items as $key => $value) {
1949 if ($count % 15 == 0) {
1950 $return .= '</div></td><td valign="top" align="right">';
1951 }
1952
1953 $return .= ($value == '' ? get_string($key,'editor') : '<img width="18" height="18" src="' . $CFG->wwwroot . '/lib/editor/htmlarea/images/' . $value . '" alt="' . get_string($key,'editor') . '" title="' . get_string($key,'editor') . '" />') . '&nbsp;';
1954 $return .= '<input type="checkbox" value="1" name="s_' . $this->name . '[' . $key . ']"' . (in_array($key,$currentsetting) ? ' checked="checked"' : '') . ' />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
1955 $count++;
1956 if ($count % 15 != 0) {
1957 $return .= '<br /><br />';
1958 }
1959 }
1960
1961 $return .= '</td></tr>';
1962 $return .= '</table>';
1963 $return .= '</td></tr><tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
1964
1965 return $return;
1966 }
1967
1968}
1969
1970class admin_setting_backupselect extends admin_setting_configselect {
1971
1972 function admin_setting_backupselect($name, $visiblename, $description, $default, $choices) {
1973 parent::admin_setting_configselect($name, $visiblename, $description, $default, $choices);
1974 }
1975
1976 function get_setting() {
1977 $backup_config = backup_get_config();
1978 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
1979 }
1980
1981 function write_setting($data) {
1982 // check that what we got was in the original choices
1983 if (! in_array($data, array_keys($this->choices))) {
1984 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1985 }
1986
1987 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1988 }
1989
1990}
1991
1992class admin_setting_special_backupsaveto extends admin_setting_configtext {
1993
1994 function admin_setting_special_backupsaveto() {
1995 $name = 'backup_sche_destination';
1996 $visiblename = get_string('saveto');
1997 $description = get_string('backupsavetohelp');
1998 parent::admin_setting_configtext($name, $visiblename, $description, '', PARAM_PATH);
1999 }
2000
2001 function get_setting() {
2002 $backup_config = backup_get_config();
2003 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2004 }
2005
2006 function write_setting($data) {
2007 $data = clean_param($data, PARAM_PATH);
2008 if (!empty($data) and (substr($data,-1) == '/' or substr($data,-1) == '\\')) {
2009 return get_string('pathslasherror') . '<br />';
2010 } else if (!empty($data) and !is_dir($data)) {
2011 return get_string('pathnotexists') . '<br />';
2012 }
2013 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2014 }
2015
2016}
2017
2018class admin_setting_backupcheckbox extends admin_setting_configcheckbox {
2019
2020 function admin_setting_backupcheckbox($name, $visiblename, $description, $default) {
2021 parent::admin_setting_configcheckbox($name, $visiblename, $description, $default);
2022 }
2023
2024 function write_setting($data) {
2025 if ($data == '1') {
2026 return (backup_set_config($this->name, 1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2027 } else {
2028 return (backup_set_config($this->name, 0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2029 }
2030 }
2031
2032 function get_setting() {
2033 $backup_config = backup_get_config();
2034 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2035 }
2036
2037}
2038
2039class admin_setting_special_backuptime extends admin_setting_configtime {
2040
2041 function admin_setting_special_backuptime() {
2042 $name = 'backup_sche_hour';
2043 $name2 = 'backup_sche_minute';
2044 $visiblename = get_string('executeat');
2045 $description = get_string('backupexecuteathelp');
2046 $default = array('h' => 0, 'm' => 0);
2047 parent::admin_setting_configtime($name, $name2, $visiblename, $description, $default);
2048 }
2049
2050 function get_setting() {
2051 $backup_config = backup_get_config();
2052 return (isset($backup_config->{$this->name}) && isset($backup_config->{$this->name}) ? array($backup_config->{$this->name}, $backup_config->{$this->name2}) : NULL);
2053 }
2054
2055 function write_setting($data) {
2056 // check that what we got was in the original choices
2057 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
2058 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2059 }
2060
2061 return (backup_set_config($this->name, $data['h']) && backup_set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2062 }
2063
2064}
2065
2066class admin_setting_special_backupdays extends admin_setting {
2067
2068 function admin_setting_special_backupdays() {
2069 $name = 'backup_sche_weekdays';
2070 $visiblename = get_string('schedule');
2071 $description = get_string('backupschedulehelp');
2072 parent::admin_setting($name, $visiblename, $description, array());
2073 }
2074
2075 function get_setting() {
2076 $backup_config = backup_get_config();
cc73de71 2077 if (isset($backup_config->{$this->name})) {
2078 $currentsetting = $backup_config->{$this->name};
2079 return array('u' => substr($currentsetting, 0, 1),
2080 'm' => substr($currentsetting, 1, 1),
2081 't' => substr($currentsetting, 2, 1),
2082 'w' => substr($currentsetting, 3, 1),
2083 'r' => substr($currentsetting, 4, 1),
2084 'f' => substr($currentsetting, 5, 1),
2085 's' => substr($currentsetting, 6, 1));
2086 } else {
2087 return NULL;
2088 }
6e4dc10f 2089 }
2090
2091 function output_html() {
2092
cc73de71 2093 if ($this->get_setting() === NULL) {
2094 $currentsetting = $this->defaultsetting;
2095 } else {
2096 $currentsetting = $this->get_setting();
6e4dc10f 2097 }
2098
cc73de71 2099 // rewrite for simplicity
2100 $currentsetting = $currentsetting['u'] . $currentsetting['m'] . $currentsetting['t'] . $currentsetting['w'] .
2101 $currentsetting['r'] . $currentsetting['f'] . $currentsetting['s'];
2102
6e4dc10f 2103 return '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td><td align="left">' .
2104 '<table><tr><td><div align="center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2105 get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2106 get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2107 get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2108 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[u]" value="1" ' . (substr($currentsetting,0,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2109 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[m]" value="1" ' . (substr($currentsetting,1,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2110 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[t]" value="1" ' . (substr($currentsetting,2,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2111 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[w]" value="1" ' . (substr($currentsetting,3,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2112 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[r]" value="1" ' . (substr($currentsetting,4,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2113 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[f]" value="1" ' . (substr($currentsetting,5,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2114 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[s]" value="1" ' . (substr($currentsetting,6,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2115 '</tr></table>' .
2116 '</td></tr><tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
2117
2118 }
2119
2120 // we're using the array trick (see http://ca.php.net/manual/en/faq.html.php#faq.html.arrays) to get the data passed to use without having to modify
2121 // admin_settingpage (note that admin_settingpage only calls write_setting with the data that matches $this->name... so if we have multiple form fields,
2122 // they MUST go into an array named $this->name, or else we won't receive them here
2123 function write_setting($data) {
2124 $week = 'umtwrfs';
2125 $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
2126 foreach($data as $key => $value) {
2127 if ($value == '1') {
2128 $result[strpos($week, $key)] = 1;
2129 }
2130 }
2131 return (backup_set_config($this->name, implode('',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2132 }
2133}
2134
ee437bbc 2135class admin_setting_special_debug extends admin_setting_configselect {
6e4dc10f 2136
2137 function admin_setting_special_debug() {
2138 $name = 'debug';
2139 $visiblename = get_string('debug', 'admin');
2140 $description = get_string('configdebug', 'admin');
ee437bbc 2141 $choices = array( 0 => get_string('debugnone', 'admin'),
2142 E_ERROR => get_string('debugerror', 'admin'),
2143 E_WARNING => get_string('debugwarning', 'admin'),
2144 E_PARSE => get_string('debugparse', 'admin'),
2145 E_NOTICE => get_string('debugnotice', 'admin'),
2146 E_ALL => get_string('debugall', 'admin'),
438c5b80 2147 2048 => get_string('debugstrict', 'admin') // E_STRICT is php5 only
ee437bbc 2148 );
2149 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
6e4dc10f 2150 }
2151
ee437bbc 2152 function get_setting() {
2153 global $CFG;
cc73de71 2154 if (isset($CFG->debug)) {
2155 if ($CFG->debug == 7) { // Old values
2156 return 1;
2157 }
2158 if ($CFG->debug == 15) { // Old values
2159 return 16;
2160 }
2161 return $CFG->debug;
2162 } else {
2163 return NULL;
ee437bbc 2164 }
6e4dc10f 2165 }
2166
ee437bbc 2167 function write_setting($data) {
2168 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
6e4dc10f 2169 }
2170
2171}
2172
2173
2174class admin_setting_special_calendar_weekend extends admin_setting {
2175
2176 function admin_setting_special_calendar_weekend() {
2177 $name = 'calendar_weekend';
2178 $visiblename = get_string('calendar_weekend', 'admin');
2179 $description = get_string('helpweekenddays', 'admin');
2180 parent::admin_setting($name, $visiblename, $description, array('u' => 1, 's' => 1));
2181 }
2182
2183 function get_setting() {
2184 global $CFG;
2185 if (isset($CFG->{$this->name})) {
2186 $setting = intval($CFG->{$this->name});
2187 return array('u' => $setting & 1, 'm' => $setting & 2, 't' => $setting & 4, 'w' => $setting & 8, 'r' => $setting & 16, 'f' => $setting & 32, 's' => $setting & 64);
2188 } else {
2189 return NULL;
2190 }
2191 }
2192
2193 function write_setting($data) {
2194 $week = 'umtwrfs';
2195 $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
2196 foreach($data as $key => $value) {
2197 if ($value == '1') {
2198 $result[strpos($week, $key)] = 1;
2199 }
2200 }
2201 return (set_config($this->name, bindec(implode('',$result))) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2202 }
2203
2204 function output_html() {
2205
cc73de71 2206 if ($this->get_setting() === NULL) {
2207 $currentsetting = $this->defaultsetting;
2208 } else {
2209 $currentsetting = $this->get_setting();
6e4dc10f 2210 }
cc73de71 2211
6e4dc10f 2212 return '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td><td align="left">' .
2213 '<table><tr><td><div align="center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2214 get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2215 get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2216 get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2217 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[u]" value="1" ' . ($currentsetting['u'] ? 'checked="checked"' : '') . ' /></div></td>' .
2218 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[m]" value="1" ' . ($currentsetting['m'] ? 'checked="checked"' : '') . ' /></div></td>' .
2219 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[t]" value="1" ' . ($currentsetting['t'] ? 'checked="checked"' : '') . ' /></div></td>' .
2220 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[w]" value="1" ' . ($currentsetting['w'] ? 'checked="checked"' : '') . ' /></div></td>' .
2221 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[r]" value="1" ' . ($currentsetting['r'] ? 'checked="checked"' : '') . ' /></div></td>' .
2222 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[f]" value="1" ' . ($currentsetting['f'] ? 'checked="checked"' : '') . ' /></div></td>' .
2223 '<td><div align="center"><input type="checkbox" name="s_'. $this->name .'[s]" value="1" ' . ($currentsetting['s'] ? 'checked="checked"' : '') . ' /></div></td>' .
2224 '</tr></table>' .
2225 '</td></tr><tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
2226
2227 }
2228
2229}
2230
2231
2232class admin_setting_special_perfdebug extends admin_setting_configcheckbox {
2233
2234 function admin_setting_special_perfdebug() {
2235 $name = 'perfdebug';
2236 $visiblename = get_string('perfdebug', 'admin');
2237 $description = get_string('configperfdebug', 'admin');
2238 parent::admin_setting_configcheckbox($name, $visiblename, $description, '');
2239 }
2240
2241 function write_setting($data) {
2242 if ($data == '1') {
2243 return (set_config($this->name,15) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2244 } else {
2245 return (set_config($this->name,7) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2246 }
2247 }
2248
2249 function output_html() {
cc73de71 2250 if ($this->get_setting() === NULL) {
2251 $currentsetting = $this->defaultsetting;
2252 } else {
2253 $currentsetting = $this->get_setting();
2254 }
2255
6e4dc10f 2256 return '<tr><td width="100" align="right" valign="top">' . $this->visiblename . '</td>' .
cc73de71 2257 '<td align="left"><input type="checkbox" size="50" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 15 ? 'checked="checked"' : '') . ' /></td></tr>' .
6e4dc10f 2258 '<tr><td>&nbsp;</td><td align="left">' . $this->description . '</td></tr>';
2259 }
2260
2261}
2262
2263// Code for a function that helps externalpages print proper headers and footers
2264// N.B.: THIS FUNCTION HANDLES AUTHENTICATION
2265function admin_externalpage_setup($section, $adminroot) {
2266
2267 global $CFG, $PAGE, $USER;
2268
2269 require_once($CFG->libdir . '/blocklib.php');
02cc05a7 2270 require_once($CFG->dirroot . '/'.$CFG->admin.'/pagelib.php');
6e4dc10f 2271
02cc05a7 2272 page_map_class(PAGE_ADMIN, 'page_admin');
6e4dc10f 2273
e9a20759 2274 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
6e4dc10f 2275
02cc05a7 2276 $PAGE->init_extra($section); // hack alert!
6e4dc10f 2277
2278 $root = $adminroot->locate($PAGE->section);
2279
2280 if ($site = get_site()) {
2281 require_login();
2282 } else {
2283 redirect($CFG->wwwroot . '/admin/index.php');
2284 die;
2285 }
2286
2287 if (!is_a($root, 'admin_externalpage')) {
2288 error(get_string('sectionerror','admin'));
2289 die;
2290 }
2291
2292 // this eliminates our need to authenticate on the actual pages
2293 if (!($root->check_access())) {
2294 error(get_string('accessdenied', 'admin'));
2295 die;
2296 }
2297
2298 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
2299
2300 if (!isset($USER->adminediting)) {
2301 $USER->adminediting = false;
2302 }
2303
2304 if ($PAGE->user_allowed_editing()) {
2305 if ($adminediting == 1) {
2306 $USER->adminediting = true;
2307 } elseif ($adminediting == 0) {
2308 $USER->adminediting = false;
2309 }
2310 }
2311
2312}
2313
2314function admin_externalpage_print_header($adminroot) {
2315
b1ce7811 2316 global $CFG, $PAGE, $SITE;
6e4dc10f 2317
b1ce7811 2318 if (!empty($SITE->fullname)) {
2319 $pageblocks = blocks_setup($PAGE);
6e4dc10f 2320
b1ce7811 2321 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
2322 BLOCK_L_MAX_WIDTH);
2323
2324 $PAGE->print_header();
2325 echo '<table id="layout-table"><tr>';
2326 echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">';
2327 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
2328 echo '</td>';
2329 echo '<td id="middle-column" width="*">';
2330 } else {
2331 print_header();
2332 }
6e4dc10f 2333
2334}
2335
2336function admin_externalpage_print_footer($adminroot) {
2337
b1ce7811 2338 global $CFG, $PAGE, $SITE;
2339
2340 if (!empty($SITE->fullname)) {
2341 $pageblocks = blocks_setup($PAGE);
2342 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH, blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
2343 BLOCK_R_MAX_WIDTH);
2344 echo '</td>';
2345 echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">';
2346 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
2347 echo '</td></tr></table>';
2348 }
2349
6e4dc10f 2350 print_footer();
6e4dc10f 2351}
2352
2353function admin_get_root() {
2354 global $CFG;
2355
2356 static $ADMIN;
2357
2358 if (!isset($ADMIN)) {
2359 // start the admin tree!
2360 $ADMIN = new admin_category('root','Administration');
2361 // we process this file first to get categories up and running
50999a0b 2362 include($CFG->dirroot . '/admin/settings/top.php');
6e4dc10f 2363
2364 // now we process all other files in admin/settings to build the
2365 // admin tree
2366 foreach (glob($CFG->dirroot . '/admin/settings/*.php') as $file) {
50999a0b 2367 if ($file != $CFG->dirroot . '/admin/settings/top.php') {
6e4dc10f 2368 include_once($file);
2369 }
2370 }
2371 }
2372
2373 return $ADMIN;
2374}
2375
2376/// settings utiliti functions
2377
2378// n.b. this function unconditionally applies default settings
2379function apply_default_settings(&$node) {
2380
2381 global $CFG;
2382
2383 if (is_a($node, 'admin_category')) {
2384 $entries = array_keys($node->children);
2385 foreach ($entries as $entry) {
2386 apply_default_settings($node->children[$entry]);
2387 }
2388 return;
2389 }
2390
2391 if (is_a($node, 'admin_settingpage')) {
2392 foreach ($node->settings as $setting) {
2393 $CFG->{$setting->name} = $setting->defaultsetting;
2394 $setting->write_setting($setting->defaultsetting);
2395 unset($setting); // needed to prevent odd (imho) reference behaviour
2396 // see http://www.php.net/manual/en/language.references.whatdo.php#AEN6399
2397 }
2398 return;
2399 }
2400
2401 return;
2402
2403}
2404
2405// n.b. this function unconditionally applies default settings
2406function apply_default_exception_settings($defaults) {
2407
2408 global $CFG;
2409
2410 foreach($defaults as $key => $value) {
2411 $CFG->$key = $value;
2412 set_config($key, $value);
2413 }
2414
2415}
2416
9e6e7502 2417?>