MDL-9506
[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
eef868d1 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 }
db8bd7a6 49 if (is_readable($fullplug . '/db/upgrade.php')) {
7c006e34 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) {
acdd790f 60 $info = new object();
ead29342 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) {
eef868d1 66 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
371a32e3 67 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
583fad99 68 }
69 upgrade_log_start();
ead29342 70 notify(get_string('pluginrequirementsnotmet', 'error', $info));
583fad99 71 $updated_plugins = true;
173cc1c3 72 continue;
73 }
74 }
75
ead29342 76 $plugin->name = $plug; // The name MUST match the directory
173cc1c3 77
ead29342 78 $pluginversion = $type.'_'.$plug.'_version';
173cc1c3 79
ead29342 80 if (!isset($CFG->$pluginversion)) {
81 set_config($pluginversion, 0);
173cc1c3 82 }
eef868d1 83
ead29342 84 if ($CFG->$pluginversion == $plugin->version) {
173cc1c3 85 // do nothing
ead29342 86 } else if ($CFG->$pluginversion < $plugin->version) {
583fad99 87 if (!$updated_plugins) {
eef868d1 88 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
371a32e3 89 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
173cc1c3 90 }
e79a09a2 91 $updated_plugins = true;
583fad99 92 upgrade_log_start();
ead29342 93 print_heading($plugin->name .' plugin needs upgrading');
e79a09a2 94 $db->debug = true;
95 @set_time_limit(0); // To allow slow databases to complete the long SQL
96
d87a9d73 97 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
e79a09a2 98 /// Both old .sql files and new install.xml are supported
99 /// but we priorize install.xml (XMLDB) if present
100 $status = false;
db8bd7a6 101 if (file_exists($fullplug . '/db/install.xml')) {
450cf307 102 $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
e79a09a2 103 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
104 $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
eef868d1 105 } else {
7c006e34 106 $status = true;
d87a9d73 107 }
e79a09a2 108
109 $db->debug = false;
eef868d1 110 /// Continue with the instalation, roles and other stuff
e79a09a2 111 if ($status) {
112 // OK so far, now update the plugins record
113 set_config($pluginversion, $plugin->version);
ae628043 114 if (!update_capabilities($type.'/'.$plug)) {
e79a09a2 115 error('Could not set up the capabilities for '.$module->name.'!');
116 }
0856223c 117 events_update_definition($type.'/'.$plug);
118
e79a09a2 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);
ae628043 153 if (!update_capabilities($type.'/'.$plug)) {
e79a09a2 154 error('Could not update '.$plugin->name.' capabilities!');
d87a9d73 155 }
0856223c 156 events_update_definition($type.'/'.$plug);
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);
acdd790f 173 print_footer('none');
173cc1c3 174 die;
175 }
176}
177
88a7228a 178/**
179 * Find and check all modules and load them up or upgrade them if necessary
180 *
181 * @uses $db
182 * @uses $CFG
183 * @param string $return The url to prompt the user to continue to
184 * @todo Finish documenting this function
eef868d1 185 */
173cc1c3 186function upgrade_activity_modules($return) {
173cc1c3 187
e69ef14b 188 global $CFG, $db;
173cc1c3 189
88a7228a 190 if (!$mods = get_list_of_plugins('mod') ) {
191 error('No modules installed!');
173cc1c3 192 }
193
583fad99 194 $updated_modules = false;
195 $strmodulesetup = get_string('modulesetup');
196
173cc1c3 197 foreach ($mods as $mod) {
198
88a7228a 199 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
173cc1c3 200 continue;
201 }
202
88a7228a 203 $fullmod = $CFG->dirroot .'/mod/'. $mod;
173cc1c3 204
205 unset($module);
206
88a7228a 207 if ( is_readable($fullmod .'/version.php')) {
208 include_once($fullmod .'/version.php'); // defines $module with version etc
173cc1c3 209 } else {
88a7228a 210 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
173cc1c3 211 continue;
212 }
213
d6eb06b6 214 $oldupgrade = false;
215 $newupgrade = false;
7c006e34 216 if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
217 include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function
d6eb06b6 218 $oldupgrade = true;
219 }
db8bd7a6 220 if ( is_readable($fullmod . '/db/upgrade.php')) {
7c006e34 221 include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
d6eb06b6 222 $newupgrade = true;
173cc1c3 223 }
224
225 if (!isset($module)) {
226 continue;
227 }
228
229 if (!empty($module->requires)) {
230 if ($module->requires > $CFG->version) {
acdd790f 231 $info = new object();
173cc1c3 232 $info->modulename = $mod;
233 $info->moduleversion = $module->version;
234 $info->currentmoodle = $CFG->version;
235 $info->requiremoodle = $module->requires;
583fad99 236 if (!$updated_modules) {
eef868d1 237 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
371a32e3 238 upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
583fad99 239 }
240 upgrade_log_start();
173cc1c3 241 notify(get_string('modulerequirementsnotmet', 'error', $info));
583fad99 242 $updated_modules = true;
173cc1c3 243 continue;
244 }
245 }
246
247 $module->name = $mod; // The name MUST match the directory
eef868d1 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) {
eef868d1 260 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
371a32e3 261 upgrade_get_javascript(), 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 }
0856223c 309 events_update_definition('mod/'.$module->name);
bbbf2d40 310
173cc1c3 311 $updated_modules = true;
eef868d1 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 }
eef868d1 317
173cc1c3 318 } else { // module not installed yet, so install it
583fad99 319 if (!$updated_modules) {
eef868d1 320 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
371a32e3 321 upgrade_get_javascript(), 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
db8bd7a6 331 if (file_exists($fullmod . '/db/install.xml')) {
d6eb06b6 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 }
0856223c 344
345 events_update_definition('mod/'.$module->name);
a8f68426 346 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
88a7228a 347 echo '<hr />';
173cc1c3 348 } else {
88a7228a 349 error($module->name .' module could not be added to the module list!');
173cc1c3 350 }
eef868d1 351 } else {
88a7228a 352 error($module->name .' tables could NOT be set up successfully!');
173cc1c3 353 }
354 }
e5bd4e58 355
356 /// Check submodules of this module if necessary
357
358 include_once($fullmod.'/lib.php'); // defines upgrading function
359
360 $submoduleupgrade = $module->name.'_upgrade_submodules';
361 if (function_exists($submoduleupgrade)) {
362 $submoduleupgrade();
363 }
364
365
366 /// Run any defaults or final code that is necessary for this module
367
a5c0990e 368 if ( is_readable($fullmod .'/defaults.php')) {
369 // Insert default values for any important configuration variables
9e6e7502 370 unset($defaults);
eef868d1 371 include_once($fullmod .'/defaults.php');
f9a2e515 372 if (!empty($defaults)) {
373 foreach ($defaults as $name => $value) {
374 if (!isset($CFG->$name)) {
375 set_config($name, $value);
376 }
a5c0990e 377 }
378 }
379 }
173cc1c3 380 }
381
583fad99 382 upgrade_log_finish(); // finish logging if started
383
384 if ($updated_modules) {
173cc1c3 385 print_continue($return);
acdd790f 386 print_footer('none');
173cc1c3 387 die;
388 }
389}
390
eef868d1 391/**
f3221af9 392 * This function will return FALSE if the lock fails to be set (ie, if it's already locked)
80be7ee3 393 *
394 * @param string $name ?
395 * @param bool $value ?
396 * @param int $staleafter ?
397 * @param bool $clobberstale ?
398 * @todo Finish documenting this function
f3221af9 399 */
400function set_cron_lock($name,$value=true,$staleafter=7200,$clobberstale=false) {
401
402 if (empty($name)) {
403 mtrace("Tried to get a cron lock for a null fieldname");
404 return false;
405 }
406
407 if (empty($value)) {
408 set_config($name,0);
409 return true;
410 }
411
412 if ($config = get_record('config','name',$name)) {
413 if (empty($config->value)) {
414 set_config($name,time());
415 } else {
416 // check for stale.
417 if ((time() - $staleafter) > $config->value) {
418 mtrace("STALE LOCKFILE FOR $name - was $config->value");
419 if (!empty($clobberstale)) {
420 set_config($name,time());
421 return true;
422 }
423 } else {
424 return false; // was not stale - ie, we're ok to still be running.
425 }
426 }
427 }
428 else {
429 set_config($name,time());
430 }
431 return true;
432}
a597f8a8 433
fb06b255 434function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
a597f8a8 435 static $starttime;
436 static $lasttime;
437
26ea4888 438 if ($total < 2) { // No need to show anything
439 return;
440 }
441
a597f8a8 442 if (empty($starttime)) {
443 $starttime = $lasttime = time();
444 $lasttime = $starttime - $updatetime;
445 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
72da5046 446 echo '<div id="bar'.$total.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
447 echo '<div id="slider'.$total.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
a597f8a8 448 echo '</div>';
72da5046 449 echo '<div id="text'.$total.'" align="center" style="width:500px;"></div>';
a597f8a8 450 echo '</td></tr></table>';
451 echo '</div>';
452 }
453
a597f8a8 454 $now = time();
455
456 if ($done && (($now - $lasttime) >= $updatetime)) {
457 $elapsedtime = $now - $starttime;
458 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
459 $percentage = format_float((float)$done / (float)$total, 2);
460 $width = (int)(500 * $percentage);
461
fb06b255 462 if ($projectedtime > 10) {
463 $projectedtext = ' Ending: '.format_time($projectedtime);
464 } else {
465 $projectedtext = '';
466 }
467
a597f8a8 468 echo '<script>';
aae37b63 469 echo 'document.getElementById("text'.$total.'").innerHTML = "'.addslashes($donetext).' ('.$done.'/'.$total.') '.$projectedtext.'";'."\n";
470 echo 'document.getElementById("slider'.$total.'").style.width = \''.$width.'px\';'."\n";
a597f8a8 471 echo '</script>';
472
473 $lasttime = $now;
474 sleep($sleeptime);
475 }
476}
583fad99 477
371a32e3 478function upgrade_get_javascript() {
479 global $CFG;
480
481 if (!empty($_SESSION['installautopilot'])) {
482 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
483 } else {
484 $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
485 }
486 $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>';
487
488 return $linktoscrolltoerrors;
489}
ad6226fb 490
491function create_admin_user() {
492 global $CFG, $USER;
493
494 if (empty($CFG->rolesactive)) { // No admin user yet.
495
496 $user = new object();
497 $user->auth = 'manual';
498 $user->firstname = get_string('admin');
499 $user->lastname = get_string('user');
500 $user->username = 'admin';
501 $user->password = hash_internal_user_password('admin');
502 $user->email = 'root@localhost';
503 $user->confirmed = 1;
504 $user->mnethostid = $CFG->mnet_localhost_id;
505 $user->lang = $CFG->lang;
506 $user->maildisplay = 1;
507 $user->timemodified = time();
508
509 if (!$user->id = insert_record('user', $user)) {
510 error('SERIOUS ERROR: Could not create admin user record !!!');
511 }
512
513 if (!$user = get_record('user', 'id', $user->id)) { // Double check.
514 error('User ID was incorrect (can\'t find it)');
515 }
516
517 // Assign the default admin roles to the new user.
518 if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW)) {
519 error('No admin role could be found');
520 }
84c8ede0 521 $sitecontext = get_context_instance(CONTEXT_SYSTEM);
ad6226fb 522 foreach ($adminroles as $adminrole) {
523 role_assign($adminrole->id, $user->id, 0, $sitecontext->id);
524 }
525
526 set_config('rolesactive', 1);
527
528 // Log the user in.
529 $USER = get_complete_user_data('username', 'admin');
530 $USER->newadminuser = 1;
531 load_all_capabilities();
532
533 redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id"); // Edit thyself
534 } else {
535 error('Can not create admin!');
536 }
537}
538
583fad99 539////////////////////////////////////////////////
540/// upgrade logging functions
541////////////////////////////////////////////////
542
543$upgradeloghandle = false;
26c91c73 544$upgradelogbuffer = '';
545// I did not find out how to use static variable in callback function,
546// the problem was that I could not flush the static buffer :-(
547global $upgradeloghandle, $upgradelogbuffer;
583fad99 548
549/**
550 * Check if upgrade is already running.
551 *
552 * If anything goes wrong due to missing call to upgrade_log_finish()
553 * just restart the browser.
554 *
555 * @param string warning message indicating upgrade is already running
556 * @param int page reload timeout
557 */
558function upgrade_check_running($message, $timeout) {
559 if (!empty($_SESSION['upgraderunning'])) {
560 print_header();
561 redirect(me(), $message, $timeout);
562 }
563}
564
565/**
566 * Start logging of output into file (if not disabled) and
567 * prevent aborting and concurrent execution of upgrade script.
568 *
569 * Please note that you can not write into session variables after calling this function!
570 *
571 * This function may be called repeatedly.
572 */
573function upgrade_log_start() {
426a369b 574 global $CFG, $upgradeloghandle;
583fad99 575
576 if (!empty($_SESSION['upgraderunning'])) {
577 return; // logging already started
578 }
579
580 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
581 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
426a369b 582 if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
583 session_write_close(); // from now on user can reload page - will be displayed warning
584 }
583fad99 585 make_upload_directory('upgradelogs');
586 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
dedb2304 587 register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
583fad99 588}
589
590/**
591 * Terminate logging of output, flush all data, allow script aborting
592 * and reopen session for writing. Function error() does terminate the logging too.
593 *
594 * Please make sure that each upgrade_log_start() is properly terminated by
595 * this function or error().
596 *
597 * This function may be called repeatedly.
598 */
599function upgrade_log_finish() {
426a369b 600 global $CFG, $upgradeloghandle, $upgradelogbuffer;
583fad99 601
602 if (empty($_SESSION['upgraderunning'])) {
603 return; // logging already terminated
604 }
605
606 @ob_end_flush();
26c91c73 607 if ($upgradelogbuffer !== '') {
608 @fwrite($upgradeloghandle, $upgradelogbuffer);
40896537 609 $upgradelogbuffer = '';
26c91c73 610 }
611 if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
612 @fclose($upgradeloghandle);
40896537 613 $upgradeloghandle = false;
26c91c73 614 }
426a369b 615 if (empty($CFG->dbsessions)) {
616 @session_start(); // ignore header errors, we only need to reopen session
617 }
583fad99 618 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
619 if (connection_aborted()) {
620 die;
621 }
622 @ignore_user_abort(false);
623}
624
625/**
626 * Callback function for logging into files. Not more than one file is created per minute,
627 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
628 *
629 * This function must not output any characters or throw warnigns and errors!
630 */
631function upgrade_log_callback($string) {
26c91c73 632 global $CFG, $upgradeloghandle, $upgradelogbuffer;
583fad99 633
634 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
635 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
26c91c73 636 $upgradelogbuffer .= $string;
637 if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
638 @fwrite($upgradeloghandle, $upgradelogbuffer);
639 $upgradelogbuffer = '';
640 }
583fad99 641 } else {
642 $upgradeloghandle = 'error';
643 }
644 }
645 return $string;
646}
647
57e35f32 648/**
649 * Try to verify that dataroot is not accessible from web.
650 * It is not 100% correct but might help to reduce number of vulnerable sites.
651 *
652 * Protection from httpd.conf and .htaccess is not detected properly.
653 */
654function is_dataroot_insecure() {
655 global $CFG;
656
657 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
658
659 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
660 $rp = strrev(trim($rp, '/'));
661 $rp = explode('/', $rp);
662 foreach($rp as $r) {
663 if (strpos($siteroot, '/'.$r.'/') === 0) {
664 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
665 } else {
666 break; // probably alias root
667 }
668 }
669
670 $siteroot = strrev($siteroot);
671 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
672
673 if (strpos($dataroot, $siteroot) === 0) {
674 return true;
675 }
676 return false;
677}
6e4dc10f 678
679/// =============================================================================================================
680/// administration tree classes and functions
681
682
683// n.b. documentation is still in progress for this code
684
685/// INTRODUCTION
686
687/// This file performs the following tasks:
688/// -it defines the necessary objects and interfaces to build the Moodle
689/// admin hierarchy
eef868d1 690/// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
6e4dc10f 691/// and admin_externalpage_print_footer() functions used on admin pages
692
693/// ADMIN_SETTING OBJECTS
694
eef868d1 695/// Moodle settings are represented by objects that inherit from the admin_setting
6e4dc10f 696/// class. These objects encapsulate how to read a setting, how to write a new value
697/// to a setting, and how to appropriately display the HTML to modify the setting.
698
699/// ADMIN_SETTINGPAGE OBJECTS
700
701/// The admin_setting objects are then grouped into admin_settingpages. The latter
702/// appear in the Moodle admin tree block. All interaction with admin_settingpage
703/// objects is handled by the admin/settings.php file.
704
705/// ADMIN_EXTERNALPAGE OBJECTS
706
707/// There are some settings in Moodle that are too complex to (efficiently) handle
708/// with admin_settingpages. (Consider, for example, user management and displaying
709/// lists of users.) In this case, we use the admin_externalpage object. This object
710/// places a link to an external PHP file in the admin tree block.
711
712/// If you're using an admin_externalpage object for some settings, you can take
713/// advantage of the admin_externalpage_* functions. For example, suppose you wanted
714/// to add a foo.php file into admin. First off, you add the following line to
715/// admin/settings/first.php (at the end of the file) or to some other file in
716/// admin/settings:
717
eef868d1 718/// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
6e4dc10f 719/// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
720
721/// Next, in foo.php, your file structure would resemble the following:
722
723/// require_once('.../config.php');
724/// require_once($CFG->libdir.'/adminlib.php');
1ae083e4 725/// admin_externalpage_setup('foo');
6e4dc10f 726/// // functionality like processing form submissions goes here
1ae083e4 727/// admin_externalpage_print_header();
6e4dc10f 728/// // your HTML goes here
1ae083e4 729/// admin_externalpage_print_footer();
6e4dc10f 730
731/// The admin_externalpage_setup() function call ensures the user is logged in,
732/// and makes sure that they have the proper role permission to access the page.
733
734/// The admin_externalpage_print_header() function prints the header (it figures
735/// out what category and subcategories the page is classified under) and ensures
736/// that you're using the admin pagelib (which provides the admin tree block and
737/// the admin bookmarks block).
738
739/// The admin_externalpage_print_footer() function properly closes the tables
740/// opened up by the admin_externalpage_print_header() function and prints the
741/// standard Moodle footer.
742
743/// ADMIN_CATEGORY OBJECTS
744
745/// Above and beyond all this, we have admin_category objects. These objects
746/// appear as folders in the admin tree block. They contain admin_settingpage's,
747/// admin_externalpage's, and other admin_category's.
748
749/// OTHER NOTES
750
751/// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
752/// from part_of_admin_tree (a pseudointerface). This interface insists that
753/// a class has a check_access method for access permissions, a locate method
754/// used to find a specific node in the admin tree, and a path method used
755/// to determine the path to a specific node in the $ADMIN tree.
756
757/// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
758/// interface ensures that the class implements a recursive add function which
759/// accepts a part_of_admin_tree object and searches for the proper place to
760/// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
761
762/// Please note that the $this->name field of any part_of_admin_tree must be
763/// UNIQUE throughout the ENTIRE admin tree.
764
765/// The $this->name field of an admin_setting object (which is *not* part_of_
766/// admin_tree) must be unique on the respective admin_settingpage where it is
767/// used.
768
769
770/// MISCELLANEOUS STUFF (used by classes defined below) ///////////////////////
771include_once($CFG->dirroot . '/backup/lib.php');
772
773/// CLASS DEFINITIONS /////////////////////////////////////////////////////////
774
775/**
776 * Pseudointerface for anything appearing in the admin tree
777 *
778 * The pseudointerface that is implemented by anything that appears in the admin tree
779 * block. It forces inheriting classes to define a method for checking user permissions
780 * and methods for finding something in the admin tree.
781 *
782 * @author Vincenzo K. Marcovecchio
783 * @package admin
784 */
785class part_of_admin_tree {
786
787 /**
788 * Finds a named part_of_admin_tree.
789 *
790 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
791 * and not parentable_part_of_admin_tree, then this function should only check if
792 * $this->name matches $name. If it does, it should return a reference to $this,
793 * otherwise, it should return a reference to NULL.
794 *
795 * If a class inherits parentable_part_of_admin_tree, this method should be called
796 * recursively on all child objects (assuming, of course, the parent object's name
797 * doesn't match the search criterion).
798 *
799 * @param string $name The internal name of the part_of_admin_tree we're searching for.
800 * @return mixed An object reference or a NULL reference.
801 */
eef868d1 802 function &locate($name) {
803 trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
804 return;
6e4dc10f 805 }
4672d955 806
807 /**
808 * Removes named part_of_admin_tree.
809 *
810 * @param string $name The internal name of the part_of_admin_tree we want to remove.
a8a66c96 811 * @return bool success.
4672d955 812 */
813 function prune($name) {
eef868d1 814 trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
4672d955 815 return;
eef868d1 816 }
4672d955 817
6e4dc10f 818 /**
819 * Verifies current user's access to this part_of_admin_tree.
820 *
821 * Used to check if the current user has access to this part of the admin tree or
822 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
823 * then this method is usually just a call to has_capability() in the site context.
824 *
825 * If a class inherits parentable_part_of_admin_tree, this method should return the
826 * logical OR of the return of check_access() on all child objects.
827 *
828 * @return bool True if the user has access, false if she doesn't.
829 */
eef868d1 830 function check_access() {
831 trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
832 return;
6e4dc10f 833 }
eef868d1 834
a8a66c96 835 /**
836 * Mostly usefull for removing of some parts of the tree in admin tree block.
837 *
838 * @return True is hidden from normal list view
839 */
840 function is_hidden() {
841 trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
842 return;
843 }
844
6e4dc10f 845 /**
846 * Determines the path to $name in the admin tree.
847 *
848 * Used to determine the path to $name in the admin tree. If a class inherits only
849 * part_of_admin_tree and not parentable_part_of_admin_tree, then this method should
850 * check if $this->name matches $name. If it does, $name is pushed onto the $path
851 * array (at the end), and $path should be returned. If it doesn't, NULL should be
852 * returned.
853 *
854 * If a class inherits parentable_part_of_admin_tree, it should do the above, but not
855 * return NULL on failure. Instead, it pushes $this->name onto $path, and then
856 * recursively calls path() on its child objects. If any are non-NULL, it should
857 * return $path (being certain that the last element of $path is equal to $name).
858 * If they are all NULL, it returns NULL.
859 *
860 * @param string $name The internal name of the part_of_admin_tree we're searching for.
861 * @param array $path Not used on external calls. Defaults to empty array.
862 * @return mixed If found, an array containing the internal names of each part_of_admin_tree that leads to $name. If not found, NULL.
863 */
eef868d1 864 function path($name, $path = array()) {
865 trigger_error('Admin class does not implement method <strong>path()</strong>', E_USER_WARNING);
866 return;
6e4dc10f 867 }
868}
869
870/**
871 * Pseudointerface implemented by any part_of_admin_tree that has children.
872 *
873 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
874 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
eef868d1 875 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
6e4dc10f 876 * include an add method for adding other part_of_admin_tree objects as children.
877 *
878 * @author Vincenzo K. Marcovecchio
879 * @package admin
880 */
881class parentable_part_of_admin_tree extends part_of_admin_tree {
eef868d1 882
6e4dc10f 883 /**
884 * Adds a part_of_admin_tree object to the admin tree.
885 *
886 * Used to add a part_of_admin_tree object to this object or a child of this
887 * object. $something should only be added if $destinationname matches
888 * $this->name. If it doesn't, add should be called on child objects that are
889 * also parentable_part_of_admin_tree's.
890 *
891 * @param string $destinationname The internal name of the new parent for $something.
892 * @param part_of_admin_tree &$something The object to be added.
893 * @return bool True on success, false on failure.
894 */
eef868d1 895 function add($destinationname, &$something) {
896 trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
897 return;
6e4dc10f 898 }
eef868d1 899
6e4dc10f 900}
901
902/**
903 * The object used to represent folders (a.k.a. categories) in the admin tree block.
eef868d1 904 *
6e4dc10f 905 * Each admin_category object contains a number of part_of_admin_tree objects.
906 *
907 * @author Vincenzo K. Marcovecchio
908 * @package admin
909 */
910class admin_category extends parentable_part_of_admin_tree {
911
912 /**
913 * @var mixed An array of part_of_admin_tree objects that are this object's children
914 */
915 var $children;
eef868d1 916
6e4dc10f 917 /**
918 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
919 */
920 var $name;
eef868d1 921
6e4dc10f 922 /**
923 * @var string The displayed name for this category. Usually obtained through get_string()
924 */
925 var $visiblename;
eef868d1 926
a8a66c96 927 /**
928 * @var bool Should this category be hidden in admin tree block?
929 */
930 var $hidden;
931
6e4dc10f 932 // constructor for an empty admin category
933 // $name is the internal name of the category. it MUST be unique in the entire hierarchy
934 // $visiblename is the displayed name of the category. use a get_string for this
935
936 /**
937 * Constructor for an empty admin category
938 *
939 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
940 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
a8a66c96 941 * @param bool $hidden hide category in admin tree block
6e4dc10f 942 * @return mixed Returns the new object.
943 */
a8a66c96 944 function admin_category($name, $visiblename, $hidden = false) {
6e4dc10f 945 $this->children = array();
946 $this->name = $name;
947 $this->visiblename = $visiblename;
a8a66c96 948 $this->hidden = $hidden;
6e4dc10f 949 }
eef868d1 950
6e4dc10f 951 /**
952 * Finds the path to the part_of_admin_tree called $name.
953 *
954 * @param string $name The internal name that we're searching for.
955 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
956 * @return mixed An array of internal names that leads to $name, or NULL if not found.
957 */
958 function path($name, $path = array()) {
eef868d1 959
6e4dc10f 960 $path[count($path)] = $this->name;
eef868d1 961
6e4dc10f 962 if ($this->name == $name) {
963 return $path;
964 }
eef868d1 965
6e4dc10f 966 foreach($this->children as $child) {
967 if ($return = $child->path($name, $path)) {
968 return $return;
969 }
970 }
eef868d1 971
6e4dc10f 972 return NULL;
eef868d1 973
6e4dc10f 974 }
975
976 /**
977 * Returns a reference to the part_of_admin_tree object with internal name $name.
978 *
979 * @param string $name The internal name of the object we want.
980 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
981 */
982 function &locate($name) {
eef868d1 983
6e4dc10f 984 if ($this->name == $name) {
985 return $this;
986 }
eef868d1 987
6e4dc10f 988 foreach($this->children as $child) {
989 if ($return =& $child->locate($name)) {
990 return $return;
991 }
992 }
993 $return = NULL;
994 return $return;
995 }
996
4672d955 997 /**
998 * Removes part_of_admin_tree object with internal name $name.
999 *
1000 * @param string $name The internal name of the object we want to remove.
a8a66c96 1001 * @return bool success
4672d955 1002 */
1003 function prune($name) {
1004
1005 if ($this->name == $name) {
1006 return false; //can not remove itself
1007 }
1008
1009 foreach($this->children as $precedence => $child) {
1010 if ($child->name == $name) {
1011 // found it!
eef868d1 1012 unset($this->children[$precedence]);
4672d955 1013 return true;
1014 }
1015 if ($this->children[$precedence]->prune($name)) {
1016 return true;
1017 }
1018 }
1019 return false;
1020 }
1021
6e4dc10f 1022 /**
1023 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1024 *
1025 * @param string $destinationame The internal name of the immediate parent that we want for &$something.
1026 * @param mixed &$something A part_of_admin_tree object to be added.
1027 * @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".
1028 * @return bool True if successfully added, false if &$something is not a part_of_admin_tree or if $name is not found.
1029 */
1030 function add($destinationname, &$something, $precedence = '') {
eef868d1 1031
6e4dc10f 1032 if (!is_a($something, 'part_of_admin_tree')) {
1033 return false;
1034 }
1035
1036 if ($destinationname == $this->name) {
1037 if ($precedence === '') {
1038 $this->children[] = $something;
1039 } else {
1040 if (isset($this->children[$precedence])) { // this should never, ever be triggered in a release version of moodle.
1041 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 />');
1042 }
1043 $this->children[$precedence] = $something;
1044 }
1045 return true;
1046 }
eef868d1 1047
6e4dc10f 1048 unset($entries);
eef868d1 1049
6e4dc10f 1050 $entries = array_keys($this->children);
eef868d1 1051
6e4dc10f 1052 foreach($entries as $entry) {
1053 $child =& $this->children[$entry];
1054 if (is_a($child, 'parentable_part_of_admin_tree')) {
1055 if ($child->add($destinationname, $something, $precedence)) {
1056 return true;
1057 }
1058 }
1059 }
eef868d1 1060
6e4dc10f 1061 return false;
eef868d1 1062
6e4dc10f 1063 }
eef868d1 1064
6e4dc10f 1065 /**
1066 * Checks if the user has access to anything in this category.
1067 *
1068 * @return bool True if the user has access to atleast one child in this category, false otherwise.
1069 */
1070 function check_access() {
eef868d1 1071
6e4dc10f 1072 $return = false;
1073 foreach ($this->children as $child) {
1074 $return = $return || $child->check_access();
1075 }
eef868d1 1076
6e4dc10f 1077 return $return;
eef868d1 1078
6e4dc10f 1079 }
eef868d1 1080
a8a66c96 1081 /**
1082 * Is this category hidden in admin tree block?
1083 *
1084 * @return bool True if hidden
1085 */
1086 function is_hidden() {
1087 return $this->hidden;
1088 }
6e4dc10f 1089}
1090
1091/**
1092 * Links external PHP pages into the admin tree.
1093 *
1094 * See detailed usage example at the top of this document (adminlib.php)
1095 *
1096 * @author Vincenzo K. Marcovecchio
1097 * @package admin
1098 */
1099class admin_externalpage extends part_of_admin_tree {
1100
eef868d1 1101 /**
6e4dc10f 1102 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1103 */
1104 var $name;
eef868d1 1105
6e4dc10f 1106 /**
1107 * @var string The displayed name for this external page. Usually obtained through get_string().
1108 */
1109 var $visiblename;
eef868d1 1110
6e4dc10f 1111 /**
1112 * @var string The external URL that we should link to when someone requests this external page.
1113 */
1114 var $url;
eef868d1 1115
6e4dc10f 1116 /**
1117 * @var string The role capability/permission a user must have to access this external page.
1118 */
2ce38b70 1119 var $req_capability;
eef868d1 1120
84c8ede0 1121 /**
1122 * @var object The context in which capability/permission should be checked, default is site context.
1123 */
1124 var $context;
1125
a8a66c96 1126 /**
1127 * @var bool hidden in admin tree block.
1128 */
1129 var $hidden;
1130
6e4dc10f 1131 /**
1132 * Constructor for adding an external page into the admin tree.
1133 *
1134 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1135 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1136 * @param string $url The external URL that we should link to when someone requests this external page.
38d2d43b 1137 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
6e4dc10f 1138 */
01e85af9 1139 function admin_externalpage($name, $visiblename, $url, $req_capability = 'moodle/site:config', $hidden=false, $context=NULL) {
6e4dc10f 1140 $this->name = $name;
1141 $this->visiblename = $visiblename;
1142 $this->url = $url;
38d2d43b 1143 if (is_array($req_capability)) {
1144 $this->req_capability = $req_capability;
1145 } else {
1146 $this->req_capability = array($req_capability);
1147 }
a8a66c96 1148 $this->hidden = $hidden;
84c8ede0 1149 $this->context = $context;
6e4dc10f 1150 }
eef868d1 1151
6e4dc10f 1152 /**
1153 * Finds the path to the part_of_admin_tree called $name.
1154 *
1155 * @param string $name The internal name that we're searching for.
1156 * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
1157 * @return mixed An array of internal names that leads to $name, or NULL if not found.
1158 */
1159 function path($name, $path = array()) {
1160 if ($name == $this->name) {
1161 array_push($path, $this->name);
1162 return $path;
1163 } else {
1164 return NULL;
1165 }
1166 }
eef868d1 1167
6e4dc10f 1168 /**
1169 * Returns a reference to the part_of_admin_tree object with internal name $name.
1170 *
1171 * @param string $name The internal name of the object we want.
1172 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1173 */
1174 function &locate($name) {
1175 $return = ($this->name == $name ? $this : NULL);
1176 return $return;
1177 }
4672d955 1178
1179 function prune($name) {
1180 return false;
1181 }
1182
6e4dc10f 1183 /**
2ce38b70 1184 * Determines if the current user has access to this external page based on $this->req_capability.
6e4dc10f 1185 *
1186 * @uses CONTEXT_SYSTEM
1187 * @uses SITEID
1188 * @return bool True if user has access, false otherwise.
1189 */
1190 function check_access() {
1191 if (!get_site()) {
1192 return true; // no access check before site is fully set up
1193 }
84c8ede0 1194 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
38d2d43b 1195 foreach($this->req_capability as $cap) {
1196 if (has_capability($cap, $context)) {
1197 return true;
1198 }
1199 }
1200 return false;
6e4dc10f 1201 }
1202
a8a66c96 1203 /**
1204 * Is this external page hidden in admin tree block?
1205 *
1206 * @return bool True if hidden
1207 */
1208 function is_hidden() {
1209 return $this->hidden;
1210 }
1211
6e4dc10f 1212}
1213
1214/**
1215 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1216 *
1217 * @author Vincenzo K. Marcovecchio
1218 * @package admin
1219 */
1220class admin_settingpage extends part_of_admin_tree {
1221
eef868d1 1222 /**
6e4dc10f 1223 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1224 */
1225 var $name;
eef868d1 1226
6e4dc10f 1227 /**
1228 * @var string The displayed name for this external page. Usually obtained through get_string().
1229 */
1230 var $visiblename;
1231 /**
1232 * @var mixed An array of admin_setting objects that are part of this setting page.
1233 */
1234 var $settings;
eef868d1 1235
6e4dc10f 1236 /**
1237 * @var string The role capability/permission a user must have to access this external page.
1238 */
2ce38b70 1239 var $req_capability;
eef868d1 1240
84c8ede0 1241 /**
1242 * @var object The context in which capability/permission should be checked, default is site context.
1243 */
1244 var $context;
1245
a8a66c96 1246 /**
1247 * @var bool hidden in admin tree block.
1248 */
1249 var $hidden;
1250
6e4dc10f 1251 // see admin_category
1252 function path($name, $path = array()) {
1253 if ($name == $this->name) {
1254 array_push($path, $this->name);
1255 return $path;
1256 } else {
1257 return NULL;
1258 }
1259 }
eef868d1 1260
6e4dc10f 1261 // see admin_category
1262 function &locate($name) {
1263 $return = ($this->name == $name ? $this : NULL);
1264 return $return;
1265 }
4672d955 1266
1267 function prune($name) {
1268 return false;
1269 }
1270
6e4dc10f 1271 // see admin_externalpage
01e85af9 1272 function admin_settingpage($name, $visiblename, $req_capability = 'moodle/site:config', $hidden=false, $context=NULL) {
6e4dc10f 1273 global $CFG;
1274 $this->settings = new stdClass();
1275 $this->name = $name;
1276 $this->visiblename = $visiblename;
38d2d43b 1277 if (is_array($req_capability)) {
1278 $this->req_capability = $req_capability;
1279 } else {
1280 $this->req_capability = array($req_capability);
1281 }
a8a66c96 1282 $this->hidden = false;
84c8ede0 1283 $this->context = $context;
6e4dc10f 1284 }
eef868d1 1285
6e4dc10f 1286 // 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
1287 // n.b. each admin_setting in an admin_settingpage must have a unique internal name
1288 // &$setting is the admin_setting object you want to add
1289 // returns true if successful, false if not (will fail if &$setting is an admin_setting or child thereof)
1290 function add(&$setting) {
1291 if (is_a($setting, 'admin_setting')) {
1292 $this->settings->{$setting->name} =& $setting;
1293 return true;
1294 }
1295 return false;
1296 }
eef868d1 1297
6e4dc10f 1298 // see admin_externalpage
1299 function check_access() {
1300 if (!get_site()) {
1301 return true; // no access check before site is fully set up
1302 }
84c8ede0 1303 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
38d2d43b 1304 foreach($this->req_capability as $cap) {
1305 if (has_capability($cap, $context)) {
1306 return true;
1307 }
1308 }
1309 return false;
6e4dc10f 1310 }
eef868d1 1311
6e4dc10f 1312 // outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1313 // returns a string of the html
1314 function output_html() {
15a16922 1315 $return = '<fieldset>' . "\n";
6153cf58 1316 $return .= '<div class="clearer"><!-- --></div>' . "\n";
6e4dc10f 1317 foreach($this->settings as $setting) {
15a16922 1318 $return .= $setting->output_html();
6e4dc10f 1319 }
6153cf58 1320 $return .= '</fieldset>';
6e4dc10f 1321 return $return;
1322 }
1323
1324 // 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
1325 // -- calls write_setting() to each child setting, sending it only the data that matches each setting's internal name
1326 // $data should be the result from data_submitted()
1327 // returns an empty string if everything went well, otherwise returns a printable error string (that's language-specific)
1328 function write_settings($data) {
1329 $return = '';
1330 foreach($this->settings as $setting) {
1331 if (isset($data['s_' . $setting->name])) {
1332 $return .= $setting->write_setting($data['s_' . $setting->name]);
1333 } else {
1334 $return .= $setting->write_setting('');
1335 }
1336 }
1337 return $return;
1338 }
1339
a8a66c96 1340 /**
1341 * Is this settigns page hidden in admin tree block?
1342 *
1343 * @return bool True if hidden
1344 */
1345 function is_hidden() {
1346 return $this->hidden;
1347 }
1348
6e4dc10f 1349}
1350
1351
1352// read & write happens at this level; no authentication
1353class admin_setting {
1354
1355 var $name;
1356 var $visiblename;
1357 var $description;
1358 var $defaultsetting;
1359
1360 function admin_setting($name, $visiblename, $description, $defaultsetting) {
1361 $this->name = $name;
1362 $this->visiblename = $visiblename;
1363 $this->description = $description;
1364 $this->defaultsetting = $defaultsetting;
1365 }
eef868d1 1366
6e4dc10f 1367 function get_setting() {
1368 return NULL; // has to be overridden
1369 }
eef868d1 1370
6e4dc10f 1371 function write_setting($data) {
1372 return; // has to be overridden
1373 }
eef868d1 1374
6e4dc10f 1375 function output_html() {
1376 return; // has to be overridden
1377 }
eef868d1 1378
6e4dc10f 1379}
1380
1381
1382class admin_setting_configtext extends admin_setting {
1383
1384 var $paramtype;
1385
50999a0b 1386 function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
6e4dc10f 1387 $this->paramtype = $paramtype;
1388 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1389 }
1390
cc73de71 1391 // returns a string or NULL
6e4dc10f 1392 function get_setting() {
1393 global $CFG;
c8218a42 1394 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
6e4dc10f 1395 }
eef868d1 1396
cc73de71 1397 // $data is a string
6e4dc10f 1398 function write_setting($data) {
9e24fbd1 1399 if (!$this->validate($data)) {
1400 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
c235598d 1401 }
6e4dc10f 1402 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1403 }
1404
c235598d 1405 function validate($data) {
9e24fbd1 1406 if (is_string($this->paramtype)) {
1407 return preg_match($this->paramtype, $data);
1408 } else if ($this->paramtype === PARAM_RAW) {
1409 return true;
1410 } else {
1411 $cleaned = clean_param($data, $this->paramtype);
1412 return ("$data" == "$cleaned"); // implicit conversion to string is needed to do exact comparison
1413 }
c235598d 1414 }
1415
6e4dc10f 1416 function output_html() {
c8218a42 1417 if ($this->get_setting() === NULL) {
1418 $current = $this->defaultsetting;
1419 } else {
1420 $current = $this->get_setting();
1421 }
9e24fbd1 1422 return format_admin_setting($this->name, $this->visiblename,
5259d5d8 1423 '<input type="text" class="form-text" id="id_s_'.$this->name.'" name="s_'.$this->name.'" value="'.s($current).'" />',
6153cf58 1424 $this->description);
6e4dc10f 1425 }
1426
1427}
1428
54bb33eb 1429class admin_setting_configpasswordunmask extends admin_setting_configtext {
eba8cd63 1430
54bb33eb 1431 function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
eba8cd63 1432 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
1433 }
1434
1435 function output_html() {
1436 if ($this->get_setting() === NULL) {
1437 $current = $this->defaultsetting;
1438 } else {
1439 $current = $this->get_setting();
1440 }
1441 $id = 'id_s_'.$this->name;
54bb33eb 1442 $unmask = get_string('unmaskpassword', 'form');
1443 $unmaskjs = '<script type="text/javascript">
eba8cd63 1444//<![CDATA[
54bb33eb 1445document.write(\'<div class="unmask"><input id="'.$id.'unmask" value="1" type="checkbox" onclick="unmaskPassword(\\\''.$id.'\\\')"/><label for="'.$id.'unmask">'.addslashes_js($unmask).'<\/label><\/div>\');
eba8cd63 1446//]]>
1447</script>';
1448 return format_admin_setting($this->name, $this->visiblename,
54bb33eb 1449 '<input type="password" class="form-text" id="id_s_'.$this->name.'" name="s_'.$this->name.'" value="'.s($current).'" />'.$unmaskjs,
eba8cd63 1450 $this->description);
1451 }
1452
1453}
1454
6e4dc10f 1455class admin_setting_configcheckbox extends admin_setting {
1456
1457 function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting) {
1458 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1459 }
1460
1461 function get_setting() {
1462 global $CFG;
1463 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1464 }
eef868d1 1465
6e4dc10f 1466 function write_setting($data) {
1467 if ($data == '1') {
1468 return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1469 } else {
1470 return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1471 }
1472 }
1473
1474 function output_html() {
c8218a42 1475 if ($this->get_setting() === NULL) {
1476 $current = $this->defaultsetting;
1477 } else {
1478 $current = $this->get_setting();
1479 }
9e24fbd1 1480 return format_admin_setting($this->name, $this->visiblename,
3c6f7a78 1481 '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($current == true ? 'checked="checked"' : '') . ' />',
6153cf58 1482 $this->description);
6e4dc10f 1483 }
1484
1485}
1486
1487class admin_setting_configselect extends admin_setting {
1488
1489 var $choices;
eef868d1 1490
6e4dc10f 1491 function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
1492 $this->choices = $choices;
1493 parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1494 }
1495
1496 function get_setting() {
1497 global $CFG;
1498 return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1499 }
eef868d1 1500
6e4dc10f 1501 function write_setting($data) {
1502 // check that what we got was in the original choices
1503 // or that the data is the default setting - needed during install when choices can not be constructed yet
1504 if ($data != $this->defaultsetting and ! in_array($data, array_keys($this->choices))) {
1505 return 'Error setting ' . $this->visiblename . '<br />';
1506 }
eef868d1 1507
6e4dc10f 1508 return (set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1509 }
eef868d1 1510
6e4dc10f 1511 function output_html() {
c8218a42 1512 if ($this->get_setting() === NULL) {
1513 $current = $this->defaultsetting;
1514 } else {
1515 $current = $this->get_setting();
1516 }
afee9864 1517 $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'">';
6e4dc10f 1518 foreach ($this->choices as $key => $value) {
a1069b07 1519 // the string cast is needed because key may be integer - 0 is equal to most strings!
1520 $return .= '<option value="'.$key.'"'.((string)$key==$current ? ' selected="selected"' : '').'>'.$value.'</option>';
6e4dc10f 1521 }
6153cf58 1522 $return .= '</select>';
1523
fc52aa6e 1524 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
6e4dc10f 1525 }
1526
1527}
1528
1529// 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
1530// internally for the setting)
1531class admin_setting_configtime extends admin_setting {
1532
1533 var $name2;
1534 var $choices;
1535 var $choices2;
6e4dc10f 1536
1537 function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
1538 $this->name2 = $minutesname;
1539 $this->choices = array();
1540 for ($i = 0; $i < 24; $i++) {
1541 $this->choices[$i] = $i;
1542 }
1543 $this->choices2 = array();
1544 for ($i = 0; $i < 60; $i += 5) {
1545 $this->choices2[$i] = $i;
1546 }
1547 parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
1548 }
1549
1550 function get_setting() {
1551 global $CFG;
cc73de71 1552 return (isset($CFG->{$this->name}) && isset($CFG->{$this->name2}) ? array('h' => $CFG->{$this->name}, 'm' => $CFG->{$this->name2}) : NULL);
6e4dc10f 1553 }
eef868d1 1554
6e4dc10f 1555 function write_setting($data) {
1556 // check that what we got was in the original choices
1557 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
1558 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1559 }
eef868d1 1560
6e4dc10f 1561 return (set_config($this->name, $data['h']) && set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1562 }
eef868d1 1563
6e4dc10f 1564 function output_html() {
cc73de71 1565 if ($this->get_setting() === NULL) {
1566 $currentsetting = $this->defaultsetting;
1567 } else {
1568 $currentsetting = $this->get_setting();
6e4dc10f 1569 }
2e0c11dd 1570 $return = '<div class="form-group">'.
1571 '<select class="form-select" id="id_s_'.$this->name.'h" name="s_' . $this->name .'[h]">';
6e4dc10f 1572 foreach ($this->choices as $key => $value) {
cc73de71 1573 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['h'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
6e4dc10f 1574 }
2e0c11dd 1575 $return .= '</select>:<select class="form-select" id="id_s_'.$this->name.'m" name="s_' . $this->name . '[m]">';
6e4dc10f 1576 foreach ($this->choices2 as $key => $value) {
cc73de71 1577 $return .= '<option value="' . $key . '"' . ($key == $currentsetting['m'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
eef868d1 1578 }
2e0c11dd 1579 $return .= '</select></div>';
fbe31d22 1580 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 1581 }
1582
1583}
1584
1585class admin_setting_configmultiselect extends admin_setting_configselect {
1586
1587 function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
1588 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1589 }
1590
1591 function get_setting() {
1592 global $CFG;
d7933a55 1593 if (isset($CFG->{$this->name})) {
1594 if ($CFG->{$this->name}) {
1595 return explode(',', $CFG->{$this->name});
1596 } else {
1597 return array();
1598 }
1599 } else {
1600 return NULL;
1601 }
6e4dc10f 1602 }
eef868d1 1603
6e4dc10f 1604 function write_setting($data) {
d7933a55 1605 if (empty($data)) {
1606 $data = array();
1607 }
6e4dc10f 1608 foreach ($data as $datum) {
1609 if (! in_array($datum, array_keys($this->choices))) {
1610 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1611 }
1612 }
eef868d1 1613
6e4dc10f 1614 return (set_config($this->name, implode(',',$data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1615 }
eef868d1 1616
6e4dc10f 1617 function output_html() {
cc73de71 1618 if ($this->get_setting() === NULL) {
1619 $currentsetting = $this->defaultsetting;
0b0f7c00 1620 if (!$currentsetting) {
1621 $currentsetting = array();
1622 }
cc73de71 1623 } else {
1624 $currentsetting = $this->get_setting();
6e4dc10f 1625 }
afee9864 1626 $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'[]" size="10" multiple="multiple">';
6e4dc10f 1627 foreach ($this->choices as $key => $value) {
1628 $return .= '<option value="' . $key . '"' . (in_array($key,$currentsetting) ? ' selected="selected"' : '') . '>' . $value . '</option>';
1629 }
6153cf58 1630 $return .= '</select>';
fc52aa6e 1631 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
6e4dc10f 1632 }
1633
1634}
1635
1636class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
eef868d1 1637
6e4dc10f 1638 function admin_setting_special_adminseesall() {
1639 $name = 'calendar_adminseesall';
1640 $visiblename = get_string('adminseesall', 'admin');
1641 $description = get_string('helpadminseesall', 'admin');
1642 parent::admin_setting($name, $visiblename, $description, 0);
1643 }
1644
1645 function write_setting($data) {
1646 global $SESSION;
1647 unset($SESSION->cal_courses_shown);
1648 parent::write_setting($data);
1649 }
1650}
1651
1652class admin_setting_sitesetselect extends admin_setting_configselect {
1653
1654 var $id;
1655
1656 function admin_setting_sitesetselect($name, $visiblename, $description, $defaultsetting, $choices) {
1657
1658 $this->id = SITEID;
1659 parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
eef868d1 1660
6e4dc10f 1661 }
eef868d1 1662
6e4dc10f 1663 function get_setting() {
1664 $site = get_site();
1665 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1666 }
eef868d1 1667
6e4dc10f 1668 function write_setting($data) {
1669 if (!in_array($data, array_keys($this->choices))) {
1670 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1671 }
1672 $record = new stdClass();
1673 $record->id = $this->id;
1674 $temp = $this->name;
1675 $record->$temp = $data;
1676 $record->timemodified = time();
1677 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1678 }
eef868d1 1679
6e4dc10f 1680}
1681
1682
e0f6e995 1683class admin_setting_courselist_frontpage extends admin_setting_configselect {
6e4dc10f 1684
e0f6e995 1685 function admin_setting_courselist_frontpage($loggedin) {
6e4dc10f 1686 global $CFG;
1687 require_once($CFG->dirroot . '/course/lib.php');
1688 $name = 'frontpage' . ($loggedin ? 'loggedin' : '');
1689 $visiblename = get_string('frontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1690 $description = get_string('configfrontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1691 $choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
1692 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
1693 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
1694 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
1695 '' => get_string('none'));
9fec4e33 1696 if (!$loggedin and count_records("course") > FRONTPAGECOURSELIMIT) {
6e4dc10f 1697 unset($choices[FRONTPAGECOURSELIST]);
1698 }
4672d955 1699 $defaults = FRONTPAGECOURSELIST.',,,';
e0f6e995 1700 parent::admin_setting_configselect($name, $visiblename, $description, $defaults, $choices);
6e4dc10f 1701 }
eef868d1 1702
6e4dc10f 1703 function get_setting() {
1704 global $CFG;
1c1e7af4 1705 return (isset($CFG->{$this->name}) ? explode(',', $CFG->{$this->name}) : ',1,,');
6e4dc10f 1706 }
eef868d1 1707
6e4dc10f 1708 function write_setting($data) {
1709 if (empty($data)) {
1710 $data = array();
e0f6e995 1711 } if (!is_array($data)) {
1712 $data = explode(',', $data);
6e4dc10f 1713 }
1714 foreach($data as $datum) {
1715 if (! in_array($datum, array_keys($this->choices))) {
1716 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1717 }
1718 }
1719 return (set_config($this->name, implode(',', $data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1720 }
eef868d1 1721
6e4dc10f 1722 function output_html() {
cc73de71 1723 if ($this->get_setting() === NULL) {
1724 $currentsetting = $this->defaultsetting;
1725 } else {
1726 $currentsetting = $this->get_setting();
6e4dc10f 1727 }
1728 for ($i = 0; $i < count($this->choices) - 1; $i++) {
1729 if (!isset($currentsetting[$i])) {
1730 $currentsetting[$i] = 0;
1731 }
1732 }
0a7e84c3 1733 $return = '<div class="form-group">';
6e4dc10f 1734 for ($i = 0; $i < count($this->choices) - 1; $i++) {
a1d52643 1735 $return .='<select class="form-select" id="id_s_'.$this->name.$i.'" name="s_' . $this->name .'[]">';
6e4dc10f 1736 foreach ($this->choices as $key => $value) {
1737 $return .= '<option value="' . $key . '"' . ($key == $currentsetting[$i] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1738 }
1739 $return .= '</select>';
1740 if ($i !== count($this->choices) - 2) {
975211bb 1741 $return .= '<br />';
6e4dc10f 1742 }
1743 }
0a7e84c3 1744 $return .= '</div>';
1745
fbe31d22 1746 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 1747 }
1748}
1749
1750class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
1751
1752 var $id;
1753
1754 function admin_setting_sitesetcheckbox($name, $visiblename, $description, $defaultsetting) {
1755
1756 $this->id = SITEID;
1757 parent::admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting);
eef868d1 1758
6e4dc10f 1759 }
eef868d1 1760
6e4dc10f 1761 function get_setting() {
1762 $site = get_site();
1763 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1764 }
eef868d1 1765
6e4dc10f 1766 function write_setting($data) {
1767 $record = new stdClass();
1768 $record->id = $this->id;
1769 $temp = $this->name;
1770 $record->$temp = ($data == '1' ? 1 : 0);
1771 $record->timemodified = time();
1772 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1773 }
eef868d1 1774
6e4dc10f 1775}
1776
1777class admin_setting_sitesettext extends admin_setting_configtext {
1778
1779 var $id;
1780
b89639f9 1781 function admin_setting_sitesettext($name, $visiblename, $description, $defaultsetting) {
6e4dc10f 1782
1783 $this->id = SITEID;
b89639f9 1784 parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting);
eef868d1 1785
6e4dc10f 1786 }
eef868d1 1787
6e4dc10f 1788 function get_setting() {
1789 $site = get_site();
1790 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1791 }
90cfbd0a 1792
b89639f9 1793 function validate($data) {
b0abd282 1794 $cleaned = stripslashes(clean_param($data, PARAM_MULTILANG));
b89639f9 1795 if ($cleaned == '') {
1796 return false; // can not be empty
1797 }
b0abd282 1798 return ($data == $cleaned); // implicit conversion to string is needed to do exact comparison
b89639f9 1799 }
1800
6e4dc10f 1801 function write_setting($data) {
b89639f9 1802 $data = trim($data);
9e24fbd1 1803 if (!$this->validate($data)) {
1804 return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
90cfbd0a 1805 }
eef868d1 1806
6e4dc10f 1807 $record = new stdClass();
1808 $record->id = $this->id;
87fa8a17 1809 $record->{$this->name} = addslashes($data);
6e4dc10f 1810 $record->timemodified = time();
23a97d83 1811 return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
6e4dc10f 1812 }
90cfbd0a 1813
6e4dc10f 1814}
1815
1816class admin_setting_special_frontpagedesc extends admin_setting {
1817
1818 var $id;
eef868d1 1819
6e4dc10f 1820 function admin_setting_special_frontpagedesc() {
1821 $this->id = SITEID;
1822 $name = 'summary';
1823 $visiblename = get_string('frontpagedescription');
1824 $description = get_string('frontpagedescriptionhelp');
1825 parent::admin_setting($name, $visiblename, $description, '');
1826 }
1827
1828 function output_html() {
eef868d1 1829
fa040029 1830 global $CFG;
1831
cc73de71 1832 if ($this->get_setting() === NULL) {
1833 $currentsetting = $this->defaultsetting;
1834 } else {
1835 $currentsetting = $this->get_setting();
1836 }
eef868d1 1837
fa040029 1838 $CFG->adminusehtmleditor = can_use_html_editor();
eef868d1 1839
fa040029 1840 $return = print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, 's_' . $this->name, $currentsetting, 0, true);
eef868d1 1841
fbe31d22 1842 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 1843 }
eef868d1 1844
6e4dc10f 1845 function get_setting() {
eef868d1 1846
6e4dc10f 1847 $site = get_site();
1848 return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
eef868d1 1849
6e4dc10f 1850 }
eef868d1 1851
6e4dc10f 1852 function write_setting($data) {
eef868d1 1853
6e4dc10f 1854 $data = addslashes(clean_param($data, PARAM_CLEANHTML));
eef868d1 1855
6e4dc10f 1856 $record = new stdClass();
1857 $record->id = $this->id;
1858 $temp = $this->name;
1859 $record->$temp = $data;
1860 $record->timemodified = time();
eef868d1 1861
6e4dc10f 1862 return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
eef868d1 1863
6e4dc10f 1864 }
1865
1866}
1867
1868
1869class admin_setting_special_editorfontlist extends admin_setting {
1870
1871 var $items;
1872
1873 function admin_setting_special_editorfontlist() {
1874 global $CFG;
1875 $name = 'editorfontlist';
1876 $visiblename = get_string('editorfontlist', 'admin');
1877 $description = get_string('configeditorfontlist', 'admin');
6e4dc10f 1878 $defaults = array('k0' => 'Trebuchet',
1879 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
1880 'k1' => 'Arial',
1881 'v1' => 'arial,helvetica,sans-serif',
1882 'k2' => 'Courier New',
1883 'v2' => 'courier new,courier,monospace',
1884 'k3' => 'Georgia',
1885 'v3' => 'georgia,times new roman,times,serif',
1886 'k4' => 'Tahoma',
1887 'v4' => 'tahoma,arial,helvetica,sans-serif',
1888 'k5' => 'Times New Roman',
1889 'v5' => 'times new roman,times,serif',
1890 'k6' => 'Verdana',
1891 'v6' => 'verdana,arial,helvetica,sans-serif',
1892 'k7' => 'Impact',
1893 'v7' => 'impact',
1894 'k8' => 'Wingdings',
1895 'v8' => 'wingdings');
1896 parent::admin_setting($name, $visiblename, $description, $defaults);
1897 }
eef868d1 1898
6e4dc10f 1899 function get_setting() {
cc73de71 1900 global $CFG;
1901 if (isset($CFG->editorfontlist)) {
1902 $i = 0;
1903 $currentsetting = array();
1904 $items = explode(';', $CFG->editorfontlist);
1905 foreach ($items as $item) {
1906 $item = explode(':', $item);
1907 $currentsetting['k' . $i] = $item[0];
1908 $currentsetting['v' . $i] = $item[1];
1909 $i++;
1910 }
1911 return $currentsetting;
1912 } else {
1913 return NULL;
1914 }
6e4dc10f 1915 }
eef868d1 1916
6e4dc10f 1917 function write_setting($data) {
eef868d1 1918
6e4dc10f 1919 // there miiight be an easier way to do this :)
1920 // if this is changed, make sure the $defaults array above is modified so that this
1921 // function processes it correctly
eef868d1 1922
6e4dc10f 1923 $keys = array();
1924 $values = array();
eef868d1 1925
6e4dc10f 1926 foreach ($data as $key => $value) {
1927 if (substr($key,0,1) == 'k') {
1928 $keys[substr($key,1)] = $value;
1929 } elseif (substr($key,0,1) == 'v') {
1930 $values[substr($key,1)] = $value;
1931 }
1932 }
eef868d1 1933
6e4dc10f 1934 $result = '';
1935 for ($i = 0; $i < count($keys); $i++) {
1936 if (($keys[$i] !== '') && ($values[$i] !== '')) {
1937 $result .= clean_param($keys[$i],PARAM_NOTAGS) . ':' . clean_param($values[$i], PARAM_NOTAGS) . ';';
1938 }
1939 }
eef868d1 1940
6e4dc10f 1941 $result = substr($result, 0, -1); // trim the last semicolon
eef868d1 1942
6e4dc10f 1943 return (set_config($this->name, $result) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1944 }
eef868d1 1945
6e4dc10f 1946 function output_html() {
eef868d1 1947
cc73de71 1948 if ($this->get_setting() === NULL) {
1949 $currentsetting = $this->defaultsetting;
1950 } else {
1951 $currentsetting = $this->get_setting();
6e4dc10f 1952 }
eef868d1 1953
1beed35f 1954 $return = '<div class="form-group">';
cc73de71 1955 for ($i = 0; $i < count($currentsetting) / 2; $i++) {
3c6f7a78 1956 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="' . $currentsetting['k' . $i] . '" />';
6e4dc10f 1957 $return .= '&nbsp;&nbsp;';
3c6f7a78 1958 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="' . $currentsetting['v' . $i] . '" /><br />';
6e4dc10f 1959 }
3c6f7a78 1960 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="" />';
6e4dc10f 1961 $return .= '&nbsp;&nbsp;';
3c6f7a78 1962 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="" /><br />';
1963 $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . ($i + 1) . ']" value="" />';
6e4dc10f 1964 $return .= '&nbsp;&nbsp;';
3c6f7a78 1965 $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . ($i + 1) . ']" value="" />';
1beed35f 1966 $return .= '</div>';
6153cf58 1967
60a9a6ea 1968 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 1969 }
eef868d1 1970
6e4dc10f 1971}
1972
1973class admin_setting_special_editordictionary extends admin_setting_configselect {
1974
1975 function admin_setting_special_editordictionary() {
1976 $name = 'editordictionary';
1977 $visiblename = get_string('editordictionary','admin');
1978 $description = get_string('configeditordictionary', 'admin');
1979 $choices = $this->editor_get_dictionaries();
1980 if (! is_array($choices)) {
1981 $choices = array('');
1982 }
eef868d1 1983
6e4dc10f 1984 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
1985 }
1986
1987 // function borrowed from the old moodle/admin/editor.php, slightly modified
1988 function editor_get_dictionaries () {
1989 /// Get all installed dictionaries in the system
1990
1991 global $CFG;
eef868d1 1992
6e4dc10f 1993// error_reporting(E_ALL); // for debug, final version shouldn't have this...
1994 clearstatcache();
1995
1996 // If aspellpath isn't set don't even bother ;-)
1997 if (empty($CFG->aspellpath)) {
1998 return 'Empty aspell path!';
1999 }
2000
2001 // Do we have access to popen function?
2002 if (!function_exists('popen')) {
2003 return 'Popen function disabled!';
2004 }
eef868d1 2005
6e4dc10f 2006 $cmd = $CFG->aspellpath;
2007 $output = '';
2008 $dictionaries = array();
2009 $dicts = array();
2010
2011 if(!($handle = @popen(escapeshellarg($cmd) .' dump dicts', 'r'))) {
2012 return 'Couldn\'t create handle!';
2013 }
2014
2015 while(!feof($handle)) {
2016 $output .= fread($handle, 1024);
2017 }
2018 @pclose($handle);
2019
2020 $dictionaries = explode(chr(10), $output);
2021
2022 // Get rid of possible empty values
2023 if (is_array($dictionaries)) {
2024
2025 $cnt = count($dictionaries);
2026
2027 for ($i = 0; $i < $cnt; $i++) {
2028 if (!empty($dictionaries[$i])) {
2c41b2d7 2029 $dicts[$dictionaries[$i]] = $dictionaries[$i];
6e4dc10f 2030 }
2031 }
2032 }
2033
2034 if (count($dicts) >= 1) {
2035 return $dicts;
2036 }
2037
2038 return 'Error! Check your aspell installation!';
2039 }
2040
eef868d1 2041
6e4dc10f 2042
2043}
2044
2045
2046class admin_setting_special_editorhidebuttons extends admin_setting {
2047
2048 var $name;
2049 var $visiblename;
2050 var $description;
2051 var $items;
2052
2053 function admin_setting_special_editorhidebuttons() {
2054 $this->name = 'editorhidebuttons';
2055 $this->visiblename = get_string('editorhidebuttons', 'admin');
2056 $this->description = get_string('confeditorhidebuttons', 'admin');
2057 $this->defaultsetting = array();
2058 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
2059 $this->items = array('fontname' => '',
2060 'fontsize' => '',
2061 'formatblock' => '',
2062 'bold' => 'ed_format_bold.gif',
2063 'italic' => 'ed_format_italic.gif',
2064 'underline' => 'ed_format_underline.gif',
2065 'strikethrough' => 'ed_format_strike.gif',
2066 'subscript' => 'ed_format_sub.gif',
2067 'superscript' => 'ed_format_sup.gif',
2068 'copy' => 'ed_copy.gif',
2069 'cut' => 'ed_cut.gif',
2070 'paste' => 'ed_paste.gif',
2071 'clean' => 'ed_wordclean.gif',
2072 'undo' => 'ed_undo.gif',
2073 'redo' => 'ed_redo.gif',
2074 'justifyleft' => 'ed_align_left.gif',
2075 'justifycenter' => 'ed_align_center.gif',
2076 'justifyright' => 'ed_align_right.gif',
2077 'justifyfull' => 'ed_align_justify.gif',
2078 'lefttoright' => 'ed_left_to_right.gif',
2079 'righttoleft' => 'ed_right_to_left.gif',
2080 'insertorderedlist' => 'ed_list_num.gif',
2081 'insertunorderedlist' => 'ed_list_bullet.gif',
2082 'outdent' => 'ed_indent_less.gif',
2083 'indent' => 'ed_indent_more.gif',
2084 'forecolor' => 'ed_color_fg.gif',
2085 'hilitecolor' => 'ed_color_bg.gif',
2086 'inserthorizontalrule' => 'ed_hr.gif',
2087 'createanchor' => 'ed_anchor.gif',
2088 'createlink' => 'ed_link.gif',
2089 'unlink' => 'ed_unlink.gif',
2090 'insertimage' => 'ed_image.gif',
2091 'inserttable' => 'insert_table.gif',
2092 'insertsmile' => 'em.icon.smile.gif',
2093 'insertchar' => 'icon_ins_char.gif',
2094 'spellcheck' => 'spell-check.gif',
2095 'htmlmode' => 'ed_html.gif',
2096 'popupeditor' => 'fullscreen_maximize.gif',
2097 'search_replace' => 'ed_replace.gif');
2098 }
2099
2100 function get_setting() {
2101 global $CFG;
2102 return (isset($CFG->{$this->name}) ? explode(' ', $CFG->{$this->name}) : NULL);
2103 }
2104
2105 function write_setting($data) {
2106 $result = array();
2107 if (empty($data)) { $data = array(); }
2108 foreach ($data as $key => $value) {
2109 if (!in_array($key, array_keys($this->items))) {
2110 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2111 }
2112 if ($value == '1') {
2113 $result[] = $key;
2114 }
2115 }
2116 return (set_config($this->name, implode(' ',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2117 }
2118
2119 function output_html() {
eef868d1 2120
6e4dc10f 2121 global $CFG;
eef868d1 2122
6e4dc10f 2123 // checkboxes with input name="$this->name[$key]" value="1"
2124 // we do 15 fields per column
eef868d1 2125
cc73de71 2126 if ($this->get_setting() === NULL) {
2127 $currentsetting = $this->defaultsetting;
2128 } else {
2129 $currentsetting = $this->get_setting();
6e4dc10f 2130 }
eef868d1 2131
1beed35f 2132 $return = '<div class="form-group">';
2133 $return .= '<table><tr><td valign="top" align="right">';
eef868d1 2134
6e4dc10f 2135 $count = 0;
eef868d1 2136
6e4dc10f 2137 foreach($this->items as $key => $value) {
8ddbd7a6 2138 if ($count % 15 == 0 and $count != 0) {
2139 $return .= '</td><td valign="top" align="right">';
6e4dc10f 2140 }
eef868d1 2141
6e4dc10f 2142 $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;';
afee9864 2143 $return .= '<input type="checkbox" class="form-checkbox" value="1" id="id_s_'.$this->name.$key.'" name="s_' . $this->name . '[' . $key . ']"' . (in_array($key,$currentsetting) ? ' checked="checked"' : '') . ' />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
6e4dc10f 2144 $count++;
2145 if ($count % 15 != 0) {
2146 $return .= '<br /><br />';
2147 }
2148 }
eef868d1 2149
2150 $return .= '</td></tr>';
6e4dc10f 2151 $return .= '</table>';
1beed35f 2152 $return .= '</div>';
6e4dc10f 2153
60a9a6ea 2154 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
6e4dc10f 2155 }
2156
2157}
2158
4642650f 2159class admin_setting_langlist extends admin_setting_configtext {
2160 function admin_setting_langlist() {
2161 parent::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
2162 }
2163
2164 function write_setting($data) {
2165 $return = parent::write_setting($data);
2166 get_list_of_languages(true);//refresh the list
2167 return $return;
2168 }
2169}
2170
6e4dc10f 2171class admin_setting_backupselect extends admin_setting_configselect {
2172
2173 function admin_setting_backupselect($name, $visiblename, $description, $default, $choices) {
2174 parent::admin_setting_configselect($name, $visiblename, $description, $default, $choices);
2175 }
2176
2177 function get_setting() {
2178 $backup_config = backup_get_config();
2179 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2180 }
eef868d1 2181
6e4dc10f 2182 function write_setting($data) {
2183 // check that what we got was in the original choices
2184 if (! in_array($data, array_keys($this->choices))) {
2185 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2186 }
eef868d1 2187
6e4dc10f 2188 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2189 }
2190
2191}
2192
2193class admin_setting_special_backupsaveto extends admin_setting_configtext {
2194
2195 function admin_setting_special_backupsaveto() {
2196 $name = 'backup_sche_destination';
2197 $visiblename = get_string('saveto');
2198 $description = get_string('backupsavetohelp');
348d6827 2199 parent::admin_setting_configtext($name, $visiblename, $description, '');
6e4dc10f 2200 }
eef868d1 2201
6e4dc10f 2202 function get_setting() {
2203 $backup_config = backup_get_config();
2204 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2205 }
eef868d1 2206
6e4dc10f 2207 function write_setting($data) {
348d6827 2208 $data = trim($data);
2209 if (!empty($data) and !is_dir($data)) {
6e4dc10f 2210 return get_string('pathnotexists') . '<br />';
2211 }
2212 return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2213 }
2214
2215}
2216
2217class admin_setting_backupcheckbox extends admin_setting_configcheckbox {
2218
2219 function admin_setting_backupcheckbox($name, $visiblename, $description, $default) {
2220 parent::admin_setting_configcheckbox($name, $visiblename, $description, $default);
2221 }
2222
2223 function write_setting($data) {
2224 if ($data == '1') {
2225 return (backup_set_config($this->name, 1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2226 } else {
2227 return (backup_set_config($this->name, 0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2228 }
2229 }
eef868d1 2230
6e4dc10f 2231 function get_setting() {
2232 $backup_config = backup_get_config();
2233 return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2234 }
2235
2236}
2237
2238class admin_setting_special_backuptime extends admin_setting_configtime {
2239
2240 function admin_setting_special_backuptime() {
2241 $name = 'backup_sche_hour';
2242 $name2 = 'backup_sche_minute';
2243 $visiblename = get_string('executeat');
2244 $description = get_string('backupexecuteathelp');
2245 $default = array('h' => 0, 'm' => 0);
2246 parent::admin_setting_configtime($name, $name2, $visiblename, $description, $default);
2247 }
eef868d1 2248
6e4dc10f 2249 function get_setting() {
2250 $backup_config = backup_get_config();
9fd9df20 2251 return (isset($backup_config->{$this->name}) && isset($backup_config->{$this->name}) ? array('h'=>$backup_config->{$this->name}, 'm'=>$backup_config->{$this->name2}) : NULL);
6e4dc10f 2252 }
eef868d1 2253
6e4dc10f 2254 function write_setting($data) {
2255 // check that what we got was in the original choices
2256 if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
2257 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2258 }
eef868d1 2259
2260 return (backup_set_config($this->name, $data['h']) && backup_set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
6e4dc10f 2261 }
eef868d1 2262
6e4dc10f 2263}
2264
2265class admin_setting_special_backupdays extends admin_setting {
2266
2267 function admin_setting_special_backupdays() {
2268 $name = 'backup_sche_weekdays';
2269 $visiblename = get_string('schedule');
2270 $description = get_string('backupschedulehelp');
6727c175 2271 $default = array('u' => 0, 'm' => 0, 't' => 0, 'w' => 0, 'r' => 0, 'f' => 0, 's' => 0);
2272 parent::admin_setting($name, $visiblename, $description, $default);
6e4dc10f 2273 }
eef868d1 2274
6e4dc10f 2275 function get_setting() {
2276 $backup_config = backup_get_config();
cc73de71 2277 if (isset($backup_config->{$this->name})) {
2278 $currentsetting = $backup_config->{$this->name};
2279 return array('u' => substr($currentsetting, 0, 1),
2280 'm' => substr($currentsetting, 1, 1),
2281 't' => substr($currentsetting, 2, 1),
2282 'w' => substr($currentsetting, 3, 1),
2283 'r' => substr($currentsetting, 4, 1),
2284 'f' => substr($currentsetting, 5, 1),
2285 's' => substr($currentsetting, 6, 1));
2286 } else {
2287 return NULL;
2288 }
6e4dc10f 2289 }
eef868d1 2290
6e4dc10f 2291 function output_html() {
eef868d1 2292
cc73de71 2293 if ($this->get_setting() === NULL) {
2294 $currentsetting = $this->defaultsetting;
2295 } else {
2296 $currentsetting = $this->get_setting();
6e4dc10f 2297 }
eef868d1 2298
cc73de71 2299 // rewrite for simplicity
eef868d1 2300 $currentsetting = $currentsetting['u'] . $currentsetting['m'] . $currentsetting['t'] . $currentsetting['w'] .
cc73de71 2301 $currentsetting['r'] . $currentsetting['f'] . $currentsetting['s'];
eef868d1 2302
60a9a6ea 2303 $return = '<table><tr><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2304 get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2305 get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' .
2306 get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div style="text-align:center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2307 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'u" name="s_'. $this->name .'[u]" value="1" ' . (substr($currentsetting,0,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2308 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'m" name="s_'. $this->name .'[m]" value="1" ' . (substr($currentsetting,1,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2309 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'t" name="s_'. $this->name .'[t]" value="1" ' . (substr($currentsetting,2,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2310 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'w" name="s_'. $this->name .'[w]" value="1" ' . (substr($currentsetting,3,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2311 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'r" name="s_'. $this->name .'[r]" value="1" ' . (substr($currentsetting,4,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2312 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'f" name="s_'. $this->name .'[f]" value="1" ' . (substr($currentsetting,5,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
2313 '<td><div style="text-align:center"><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'s" name="s_'. $this->name .'[s]" value="1" ' . (substr($currentsetting,6,1) == '1' ? 'checked="checked"' : '') . ' /></div></td>' .
6153cf58 2314 '</tr></table>';
2315
60a9a6ea 2316 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
eef868d1 2317
6e4dc10f 2318 }
eef868d1 2319
6e4dc10f 2320 // 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
2321 // admin_settingpage (note that admin_settingpage only calls write_setting with the data that matches $this->name... so if we have multiple form fields,
2322 // they MUST go into an array named $this->name, or else we won't receive them here
2323 function write_setting($data) {
2324 $week = 'umtwrfs';
2325 $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
9fd9df20 2326 if (!empty($data)) {
2327 foreach($data as $key => $value) {
2328 if ($value == '1') {
2329 $result[strpos($week, $key)] = 1;
2330 }
2331 }
6e4dc10f 2332 }
2333 return (backup_set_config($this->name, implode('',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2334 }
2335}
2336
ee437bbc 2337class admin_setting_special_debug extends admin_setting_configselect {
6e4dc10f 2338
2339 function admin_setting_special_debug() {
2340 $name = 'debug';
2341 $visiblename = get_string('debug', 'admin');
2342 $description = get_string('configdebug', 'admin');
7eb0b60a 2343 $choices = array( DEBUG_NONE => get_string('debugnone', 'admin'),
2344 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
2345 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
38d2d43b 2346 DEBUG_ALL => get_string('debugall', 'admin'),
2347 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin')
ee437bbc 2348 );
2349 parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
6e4dc10f 2350 }
2351
ee437bbc 2352 function get_setting() {
2353 global $CFG;
cc73de71 2354 if (isset($CFG->debug)) {
cc73de71 2355 return $CFG->debug;
2356 } else {
2357 return NULL;
ee437bbc 2358 }
6e4dc10f 2359 }
2360
ee437bbc 2361 function write_setting($data) {
2362 return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
6e4dc10f 2363 }
2364
2365}
2366
2367
2368class admin_setting_special_calendar_weekend extends admin_setting {
2369
2370 function admin_setting_special_calendar_weekend() {
2371 $name = 'calendar_weekend';
2372 $visiblename = get_string('calendar_weekend', 'admin');
2373 $description = get_string('helpweekenddays', 'admin');
5eaa6aa0 2374 $default = array ('0', '6'); // Saturdays and Sundays
b91b1f92 2375 parent::admin_setting($name, $visiblename, $description, $default);
6e4dc10f 2376 }
2377
2378 function get_setting() {
2379 global $CFG;
4af8d5d3 2380 return isset($CFG->{$this->name}) ? $CFG->{$this->name} : 0;
6e4dc10f 2381 }
eef868d1 2382
6e4dc10f 2383 function write_setting($data) {
4af8d5d3 2384 $result = 0;
b91b1f92 2385 if (!empty($data)) {
4af8d5d3 2386 foreach($data as $index) {
2387 $result |= 1 << $index;
b91b1f92 2388 }
6e4dc10f 2389 }
4af8d5d3 2390 return (set_config($this->name, $result) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
6e4dc10f 2391 }
eef868d1 2392
6e4dc10f 2393 function output_html() {
cc73de71 2394 if ($this->get_setting() === NULL) {
2395 $currentsetting = $this->defaultsetting;
2396 } else {
2397 $currentsetting = $this->get_setting();
6e4dc10f 2398 }
cc73de71 2399
4af8d5d3 2400 // The order matters very much because of the implied numeric keys
2401 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
2402 $return = '<table><thead><tr>';
2403 foreach($days as $index => $day) {
2404 $return .= '<td><label for="id_s_'.$this->name.$index.'">'.get_string($day, 'calendar').'</label></td>';
2405 }
2406 $return .= '</tr></thead><tbody><tr>';
2407 foreach($days as $index => $day) {
2408 $return .= '<td><input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.$index.'" name="s_'.$this->name.'[]" value="'.$index.'" '.($currentsetting & (1 << $index) ? 'checked="checked"' : '') . ' /></td>';
2409 }
2410 $return .= '</tr></tbody></table>';
6153cf58 2411
038bf621 2412 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
eef868d1 2413
6e4dc10f 2414 }
2415
2416}
2417
73afaf5b 2418/*
2419 * this is used in config->appearance->gradeconfig
5a412dbf 2420 */
0909d44e 2421class admin_setting_special_gradebookroles extends admin_setting {
5a412dbf 2422
0909d44e 2423 function admin_setting_special_gradebookroles() {
2424 $name = 'gradebookroles';
73afaf5b 2425 $visiblename = get_string('gradebookroles', 'admin');
2426 $description = get_string('configgradebookroles', 'admin');
7aa3e196 2427 $default = array(5=>'1'); // The student role in a default install
8a2cb2fa 2428 parent::admin_setting($name, $visiblename, $description, $default);
5a412dbf 2429 }
2430
2431 function get_setting() {
2432 global $CFG;
8a2cb2fa 2433 if (!empty($CFG->{$this->name})) {
60f7d402 2434 $result = explode(',', $CFG->{$this->name});
2435 foreach ($result as $roleid) {
2436 $array[$roleid] = 1;
2437 }
2438 return $array;
5a412dbf 2439 } else {
3fae9f57 2440 return null;
5a412dbf 2441 }
2442 }
2443
2444 function write_setting($data) {
2445 if (!empty($data)) {
2446 $str = '';
0909d44e 2447 foreach ($data as $key => $value) {
5a412dbf 2448 if ($value) {
2449 $str .= $key.',';
2450 }
2451 }
2452 return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2453 } else {
73afaf5b 2454 return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2455 }
5a412dbf 2456 }
2457
2458 function output_html() {
2459
2460 if ($this->get_setting() === NULL) {
2461 $currentsetting = $this->defaultsetting;
2462 } else {
2463 $currentsetting = $this->get_setting();
2464 }
5a412dbf 2465 // from to process which roles to display
2466 if ($roles = get_records('role')) {
73afaf5b 2467 $return = '<div class="form-group">';
2468 $first = true;
2469 foreach ($roles as $roleid=>$role) {
60f7d402 2470 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
fb132873 2471 $checked = ' checked="checked"';
5a412dbf 2472 } else {
73afaf5b 2473 $checked = '';
5a412dbf 2474 }
73afaf5b 2475 if ($first) {
2476 $first = false;
2477 } else {
2478 $return .= '<br />';
2479 }
b0abd282 2480 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$roleid.']" value="1"'.$checked.' />&nbsp;'.format_string($role->name);
5a412dbf 2481 }
73afaf5b 2482 $return .= '</div>';
5a412dbf 2483 }
73afaf5b 2484
60a9a6ea 2485 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
5a412dbf 2486
2487 }
2488
2489}
6e4dc10f 2490
d42c64ba 2491/*
2492 * this is used in config->appearance->coursemanager
2493 * (which roles to show on course decription page)
2494 */
2495class admin_setting_special_coursemanager extends admin_setting {
2496
2497 function admin_setting_special_coursemanager() {
2498 $name = 'coursemanager';
2499 $visiblename = get_string('coursemanager', 'admin');
2500 $description = get_string('configcoursemanager', 'admin');
2501 $default = array(3=>'1'); // The teahcer role in a default install
2502 parent::admin_setting($name, $visiblename, $description, $default);
2503 }
2504
2505 function get_setting() {
2506
2507 global $CFG;
2508 if (!empty($CFG->{$this->name})) {
2509 $result = explode(',', $CFG->{$this->name});
2510 foreach ($result as $roleid) {
2511 $array[$roleid] = 1;
2512 }
2513 return $array;
b107549c 2514 } else if (isset($CFG->{$this->name})) {
2515 return array();
d42c64ba 2516 } else {
2517 return null;
2518 }
2519 }
2520
2521 function write_setting($data) {
2522
2523 if (!empty($data)) {
2524 $str = '';
2525 foreach ($data as $key => $value) {
2526 if ($value) {
2527 $str .= $key.',';
2528 }
2529 }
2530 return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2531 } else {
2532 return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2533 }
2534 }
2535
2536 function output_html() {
2537
2538 if ($this->get_setting() === NULL) {
2539 $currentsetting = $this->defaultsetting;
2540 } else {
2541 $currentsetting = $this->get_setting();
2542 }
2543 // from to process which roles to display
2544 if ($roles = get_records('role')) {
2545 $return = '<div class="form-group">';
2546 $first = true;
2547 foreach ($roles as $roleid=>$role) {
2548 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
2549 $checked = 'checked="checked"';
2550 } else {
2551 $checked = '';
2552 }
2553 if ($first) {
2554 $first = false;
2555 } else {
2556 $return .= '<br />';
2557 }
7203167d 2558 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$roleid.']" value="1" '.$checked.' />&nbsp;'.$role->name;
d42c64ba 2559 }
2560 $return .= '</div>';
2561 }
60a9a6ea 2562 return format_admin_setting($this->name, $this->visiblename, $return, $this->description, false);
d42c64ba 2563 }
2564}
2565
6e4dc10f 2566class admin_setting_special_perfdebug extends admin_setting_configcheckbox {
2567
2568 function admin_setting_special_perfdebug() {
2569 $name = 'perfdebug';
2570 $visiblename = get_string('perfdebug', 'admin');
2571 $description = get_string('configperfdebug', 'admin');
2572 parent::admin_setting_configcheckbox($name, $visiblename, $description, '');
2573 }
2574
2575 function write_setting($data) {
d42c64ba 2576
6e4dc10f 2577 if ($data == '1') {
2578 return (set_config($this->name,15) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2579 } else {
2580 return (set_config($this->name,7) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2581 }
2582 }
2583
2584 function output_html() {
d42c64ba 2585
cc73de71 2586 if ($this->get_setting() === NULL) {
2587 $currentsetting = $this->defaultsetting;
2588 } else {
2589 $currentsetting = $this->get_setting();
2590 }
eef868d1 2591
3c6f7a78 2592 $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 15 ? 'checked="checked"' : '') . ' />';
fc52aa6e 2593 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
6e4dc10f 2594 }
2595
2596}
2597
47b8b9eb 2598class admin_setting_special_debugdisplay extends admin_setting_configcheckbox {
2599
2600 function admin_setting_special_debugdisplay() {
2601 $name = 'debugdisplay';
2602 $visiblename = get_string('debugdisplay', 'admin');
2603 $description = get_string('configdebugdisplay', 'admin');
6349a3ba 2604 $default = ini_get('display_errors');
2605 parent::admin_setting_configcheckbox($name, $visiblename, $description, $default);
47b8b9eb 2606 }
2607
2608 function write_setting($data) {
2609
2610 if ($data == '1') {
2611 return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2612 } else {
2613 return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2614 }
2615 }
2616
2617 function output_html() {
2618
2619 if ($this->get_setting() === NULL) {
6349a3ba 2620 $currentsetting = $this->defaultsetting;
47b8b9eb 2621 } else {
2622 $currentsetting = $this->get_setting();
2623 }
2624
2625 $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 1 ? 'checked="checked"' : '') . ' />';
2626 return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2627 }
2628
2629}
2630
2631
6e4dc10f 2632// Code for a function that helps externalpages print proper headers and footers
2633// N.B.: THIS FUNCTION HANDLES AUTHENTICATION
1ae083e4 2634function admin_externalpage_setup($section) {
6e4dc10f 2635
2636 global $CFG, $PAGE, $USER;
eef868d1 2637
1ae083e4 2638 $adminroot = admin_get_root();
2639
6e4dc10f 2640 require_once($CFG->libdir . '/blocklib.php');
02cc05a7 2641 require_once($CFG->dirroot . '/'.$CFG->admin.'/pagelib.php');
eef868d1 2642
02cc05a7 2643 page_map_class(PAGE_ADMIN, 'page_admin');
6e4dc10f 2644
e9a20759 2645 $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
6e4dc10f 2646
02cc05a7 2647 $PAGE->init_extra($section); // hack alert!
6e4dc10f 2648
2649 $root = $adminroot->locate($PAGE->section);
2650
2651 if ($site = get_site()) {
2652 require_login();
2653 } else {
6859360c 2654 redirect($CFG->wwwroot . '/'.$CFG->admin.'/index.php');
6e4dc10f 2655 die;
2656 }
2657
2658 if (!is_a($root, 'admin_externalpage')) {
2659 error(get_string('sectionerror','admin'));
2660 die;
2661 }
2662
2663 // this eliminates our need to authenticate on the actual pages
2664 if (!($root->check_access())) {
2665 error(get_string('accessdenied', 'admin'));
2666 die;
2667 }
eef868d1 2668
6e4dc10f 2669 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
eef868d1 2670
6e4dc10f 2671 if (!isset($USER->adminediting)) {
2672 $USER->adminediting = false;
2673 }
eef868d1 2674
6e4dc10f 2675 if ($PAGE->user_allowed_editing()) {
2676 if ($adminediting == 1) {
2677 $USER->adminediting = true;
2678 } elseif ($adminediting == 0) {
2679 $USER->adminediting = false;
2680 }
2681 }
eef868d1 2682
6e4dc10f 2683}
2684
1ae083e4 2685function admin_externalpage_print_header() {
6e4dc10f 2686
ce821fda 2687 global $CFG, $PAGE, $SITE, $THEME;
f145c248 2688
2689 if (!empty($THEME->customcorners)) {
2690 require_once($CFG->dirroot.'/lib/custom_corners_lib.php');
2691 }
eef868d1 2692
1ae083e4 2693 define('ADMIN_EXT_HEADER_PRINTED', 'true');
2694
b1ce7811 2695 if (!empty($SITE->fullname)) {
2696 $pageblocks = blocks_setup($PAGE);
6e4dc10f 2697
e524c0ed 2698 $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
2699 blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
b1ce7811 2700 BLOCK_L_MAX_WIDTH);
b1ce7811 2701 $PAGE->print_header();
5577ceb3 2702 echo '<table id="layout-table" summary=""><tr>';
b1ce7811 2703 echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">';
f145c248 2704 if (!empty($THEME->customcorners)) print_custom_corners_start();
b1ce7811 2705 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
f145c248 2706 if (!empty($THEME->customcorners)) print_custom_corners_end();
b1ce7811 2707 echo '</td>';
a06c8c2c 2708 echo '<td id="middle-column">';
f145c248 2709 if (!empty($THEME->customcorners)) print_custom_corners_start();
b1ce7811 2710 } else {
2711 print_header();
2712 }
6e4dc10f 2713}
2714
1ae083e4 2715function admin_externalpage_print_footer() {
6e4dc10f 2716
ce821fda 2717 global $CFG, $PAGE, $SITE, $THEME;
f145c248 2718
2719 if (!empty($THEME->customcorners)) {
2720 require_once($CFG->dirroot.'/lib/custom_corners_lib.php');
2721 }
2722
1ae083e4 2723 define('ADMIN_EXT_FOOTER_PRINTED', 'true');
2724
b1ce7811 2725 if (!empty($SITE->fullname)) {
2726 $pageblocks = blocks_setup($PAGE);
e524c0ed 2727 $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
2728 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
b1ce7811 2729 BLOCK_R_MAX_WIDTH);
f145c248 2730 if (!empty($THEME->customcorners)) print_custom_corners_end();
b1ce7811 2731 echo '</td>';
d5271d3d 2732 if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
ec3938f3 2733 echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">';
f145c248 2734 if (!empty($THEME->customcorners)) print_custom_corners_start();
ec3938f3 2735 blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
f145c248 2736 if (!empty($THEME->customcorners)) print_custom_corners_end();
ec3938f3 2737 echo '</td>';
ce821fda 2738 }
ec3938f3 2739 echo '</tr></table>';
b1ce7811 2740 }
6e4dc10f 2741 print_footer();
6e4dc10f 2742}
2743
2744function admin_get_root() {
2745 global $CFG;
2746
2747 static $ADMIN;
2748
2749 if (!isset($ADMIN)) {
2750 // start the admin tree!
2058a0a1 2751 $ADMIN = new admin_category('root', get_string("administration"));
6e4dc10f 2752 // we process this file first to get categories up and running
6859360c 2753 include($CFG->dirroot . '/'.$CFG->admin.'/settings/top.php');
6e4dc10f 2754
2755 // now we process all other files in admin/settings to build the
2756 // admin tree
6859360c 2757 foreach (glob($CFG->dirroot . '/'.$CFG->admin.'/settings/*.php') as $file) {
2758 if ($file != $CFG->dirroot . '/'.$CFG->admin.'/settings/top.php') {
6e4dc10f 2759 include_once($file);
2760 }
2761 }
2762 }
eef868d1 2763
6e4dc10f 2764 return $ADMIN;
2765}
2766
2767/// settings utiliti functions
2768
2769// n.b. this function unconditionally applies default settings
2770function apply_default_settings(&$node) {
2771
2772 global $CFG;
2773
2774 if (is_a($node, 'admin_category')) {
2775 $entries = array_keys($node->children);
2776 foreach ($entries as $entry) {
2777 apply_default_settings($node->children[$entry]);
2778 }
2779 return;
eef868d1 2780 }
6e4dc10f 2781
eef868d1 2782 if (is_a($node, 'admin_settingpage')) {
6e4dc10f 2783 foreach ($node->settings as $setting) {
2784 $CFG->{$setting->name} = $setting->defaultsetting;
2785 $setting->write_setting($setting->defaultsetting);
2786 unset($setting); // needed to prevent odd (imho) reference behaviour
2787 // see http://www.php.net/manual/en/language.references.whatdo.php#AEN6399
2788 }
2789 return;
2790 }
2791
2792 return;
2793
2794}
2795
2796// n.b. this function unconditionally applies default settings
2797function apply_default_exception_settings($defaults) {
2798
2799 global $CFG;
2800
2801 foreach($defaults as $key => $value) {
2802 $CFG->$key = $value;
2803 set_config($key, $value);
2804 }
2805
2806}
2807
fbe31d22 2808function format_admin_setting($name, $title='', $form='', $description='', $label=true) {
2809
2810 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
2811 if ($label) {
2812 $labelfor = 'for = "id_s_'.$name.'"';
2813 } else {
2814 $labelfor = '';
2815 }
2816
2817 $str = "\n".
fc52aa6e 2818 '<div class="form-item" id="admin-'.$name.'">'."\n".
fbe31d22 2819 '<label '.$labelfor.'>'.$title."\n".
6153cf58 2820 ' <span class="form-shortname">'.$name.'</span>'."\n".
2821 '</label>'."\n".
2822 $form."\n".
edb6cba4 2823 '<div class="description">'.$description.'</div>'."\n".
23586aca 2824 '</div>'.
2825 "\n\n";
fbe31d22 2826
2827 return $str;
2c8766df 2828}
2829
d210e12e 2830/*
2831 * Try to upgrade the given language pack (or current language)
2832 * If it doesn't work, fail silently and return false
2833 */
2834function upgrade_language_pack($lang='') {
2835 global $CFG;
2836
2837 if (empty($lang)) {
2838 $lang = current_language();
2839 }
2840
2841 if ($lang == 'en_utf8') {
2842 return true; // Nothing to do
2843 }
2844
2845 notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
2846
2847 @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
2848 @mkdir ($CFG->dataroot.'/lang/');
2849
2850 require_once($CFG->libdir.'/componentlib.class.php');
2851
2852 if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
2853 $status = $cd->install(); //returns ERROR | UPTODATE | INSTALLED
2854
2855 if ($status == INSTALLED) {
2856 debugging('Downloading successful: '.$lang);
2857 @unlink($CFG->dataroot.'/cache/languages');
2858 return true;
2859 }
2860 }
2861
2862 return false;
2863}
2864
2acc1f96 2865/**
2866 * Based on find_new_settings{@link ()} in upgradesettings.php
2867 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
2868 *
2869 * @param string &$node The node at which to start searching.
2870 * @return int Returns 1 if any settings haven't been initialised, 0 if they all have
2871 */
2872function any_new_admin_settings(&$node) {
2873
2874 if (is_a($node, 'admin_category')) {
2875 $entries = array_keys($node->children);
2876 foreach ($entries as $entry) {
2877 if( any_new_admin_settings($node->children[$entry]) ){
2878 return 1;
2879 }
2880 }
2881 }
2882
2883 if (is_a($node, 'admin_settingpage')) {
2884 foreach ($node->settings as $setting) {
2885 if ($setting->get_setting() === NULL) {
2886 return 1;
2887 }
2888 }
2889 }
2890
2891
2892 return 0;
2893
2894}
2895
6153cf58 2896?>