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