MDL-8096 - user edit form splitting, refactoring, cleanup and fixing - work in progre...
[moodle.git] / lib / adminlib.php
1 <?php
3 /**
4  * adminlib.php - Contains functions that only administrators will ever need to use
5  *
6  * @author Martin Dougiamas and many others
7  * @version  $Id$
8  * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
9  * @package moodlecore
10  */
12 /**
13  * Upgrade plugins
14  *
15  * @uses $db
16  * @uses $CFG
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
20  */
21 function upgrade_plugins($type, $dir, $return) {
22     global $CFG, $db;
24     if (!$plugs = get_list_of_plugins($dir) ) {
25         error('No '.$type.' plugins installed!');
26     }
28     $updated_plugins = false;
29     $strpluginsetup  = get_string('pluginsetup');
31     foreach ($plugs as $plug) {
33         $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
35         unset($plugin);
37         if (is_readable($fullplug .'/version.php')) {
38             include_once($fullplug .'/version.php');  // defines $plugin with version etc
39         } else {
40             continue;                              // Nothing to do.
41         }
43         $oldupgrade = false;
44         $newupgrade = false;
45         if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) {
46             include_once($fullplug . '/db/'. $CFG->dbtype . '.php');  // defines old upgrading function
47             $oldupgrade = true;
48         }
49         if (is_readable($fullplug . '/db/upgrade.php')) {
50             include_once($fullplug . '/db/upgrade.php');  // defines new upgrading function
51             $newupgrade = true;
52         }
54         if (!isset($plugin)) {
55             continue;
56         }
58         if (!empty($plugin->requires)) {
59             if ($plugin->requires > $CFG->version) {
60                 $info = new object();
61                 $info->pluginname = $plug;
62                 $info->pluginversion  = $plugin->version;
63                 $info->currentmoodle = $CFG->version;
64                 $info->requiremoodle = $plugin->requires;
65                 if (!$updated_plugins) {
66                     print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
67                         upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
68                 }
69                 upgrade_log_start();
70                 notify(get_string('pluginrequirementsnotmet', 'error', $info));
71                 $updated_plugins = true;
72                 continue;
73             }
74         }
76         $plugin->name = $plug;   // The name MUST match the directory
78         $pluginversion = $type.'_'.$plug.'_version';
80         if (!isset($CFG->$pluginversion)) {
81             set_config($pluginversion, 0);
82         }
84         if ($CFG->$pluginversion == $plugin->version) {
85             // do nothing
86         } else if ($CFG->$pluginversion < $plugin->version) {
87             if (!$updated_plugins) {
88                 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
89                         upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
90             }
91             $updated_plugins = true;
92             upgrade_log_start();
93             print_heading($plugin->name .' plugin needs upgrading');
94             $db->debug = true;
95             @set_time_limit(0);  // To allow slow databases to complete the long SQL
97             if ($CFG->$pluginversion == 0) {    // It's a new install of this plugin
98             /// Both old .sql files and new install.xml are supported
99             /// but we priorize install.xml (XMLDB) if present
100                 $status = false;
101                 if (file_exists($fullplug . '/db/install.xml')) {
102                     $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
103                 } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
104                     $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
105                 } else {
106                     $status = true;
107                 }
109                 $db->debug = false;
110             /// Continue with the instalation, roles and other stuff
111                 if ($status) {
112                     // OK so far, now update the plugins record
113                     set_config($pluginversion, $plugin->version);
114                     if (!update_capabilities($type.'/'.$plug)) {
115                         error('Could not set up the capabilities for '.$module->name.'!');
116                     }
117                     notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
118                 } else {
119                     notify('Installing '. $plugin->name .' FAILED!');
120                 }
121             } else {                            // Upgrade existing install
122             /// Run de old and new upgrade functions for the module
123                 $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade';
124                 $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
126             /// First, the old function if exists
127                 $oldupgrade_status = true;
128                 if ($oldupgrade && function_exists($oldupgrade_function)) {
129                     $db->debug = true;
130                     $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
131                 } else if ($oldupgrade) {
132                     notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
133                              $fullplug . '/db/' . $CFG->dbtype . '.php');
134                 }
136             /// Then, the new function if exists and the old one was ok
137                 $newupgrade_status = true;
138                 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
139                     $db->debug = true;
140                     $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
141                 } else if ($newupgrade) {
142                     notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
143                              $fullplug . '/db/upgrade.php');
144                 }
146                 $db->debug=false;
147             /// Now analyze upgrade results
148                 if ($oldupgrade_status && $newupgrade_status) {    // No upgrading failed
149                     // OK so far, now update the plugins record
150                     set_config($pluginversion, $plugin->version);
151                     if (!update_capabilities($type.'/'.$plug)) {
152                         error('Could not update '.$plugin->name.' capabilities!');
153                     }
154                     notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
155                 } else {
156                     notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
157                 }
158             }
159             echo '<hr />';
160         } else {
161             upgrade_log_start();
162             error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
163         }
164     }
166     upgrade_log_finish();
168     if ($updated_plugins) {
169         print_continue($return);
170         print_footer('none');
171         die;
172     }
175 /**
176  * Find and check all modules and load them up or upgrade them if necessary
177  *
178  * @uses $db
179  * @uses $CFG
180  * @param string $return The url to prompt the user to continue to
181  * @todo Finish documenting this function
182  */
183 function upgrade_activity_modules($return) {
185     global $CFG, $db;
187     if (!$mods = get_list_of_plugins('mod') ) {
188         error('No modules installed!');
189     }
191     $updated_modules = false;
192     $strmodulesetup  = get_string('modulesetup');
194     foreach ($mods as $mod) {
196         if ($mod == 'NEWMODULE') {   // Someone has unzipped the template, ignore it
197             continue;
198         }
200         $fullmod = $CFG->dirroot .'/mod/'. $mod;
202         unset($module);
204         if ( is_readable($fullmod .'/version.php')) {
205             include_once($fullmod .'/version.php');  // defines $module with version etc
206         } else {
207             notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
208             continue;
209         }
211         $oldupgrade = false;
212         $newupgrade = false;
213         if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
214             include_once($fullmod .'/db/' . $CFG->dbtype . '.php');  // defines old upgrading function
215             $oldupgrade = true;
216         }
217         if ( is_readable($fullmod . '/db/upgrade.php')) {
218             include_once($fullmod . '/db/upgrade.php');  // defines new upgrading function
219             $newupgrade = true;
220         }
222         if (!isset($module)) {
223             continue;
224         }
226         if (!empty($module->requires)) {
227             if ($module->requires > $CFG->version) {
228                 $info = new object();
229                 $info->modulename = $mod;
230                 $info->moduleversion  = $module->version;
231                 $info->currentmoodle = $CFG->version;
232                 $info->requiremoodle = $module->requires;
233                 if (!$updated_modules) {
234                     print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
235                             upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
236                 }
237                 upgrade_log_start();
238                 notify(get_string('modulerequirementsnotmet', 'error', $info));
239                 $updated_modules = true;
240                 continue;
241             }
242         }
244         $module->name = $mod;   // The name MUST match the directory
246         if ($currmodule = get_record('modules', 'name', $module->name)) {
247             if ($currmodule->version == $module->version) {
248                 // do nothing
249             } else if ($currmodule->version < $module->version) {
250             /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
251                 if (!$oldupgrade && !$newupgrade) {
252                     notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' .
253                                                             $fullmod . '/db/upgrade.php were not readable');
254                     continue;
255                 }
256                 if (!$updated_modules) {
257                     print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
258                             upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
259                 }
260                 upgrade_log_start();
261                 print_heading($module->name .' module needs upgrading');
263             /// Run de old and new upgrade functions for the module
264                 $oldupgrade_function = $module->name . '_upgrade';
265                 $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
267             /// First, the old function if exists
268                 $oldupgrade_status = true;
269                 if ($oldupgrade && function_exists($oldupgrade_function)) {
270                     $db->debug = true;
271                     $oldupgrade_status = $oldupgrade_function($currmodule->version, $module);
272                 } else if ($oldupgrade) {
273                     notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
274                              $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php');
275                 }
277             /// Then, the new function if exists and the old one was ok
278                 $newupgrade_status = true;
279                 if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
280                     $db->debug = true;
281                     $newupgrade_status = $newupgrade_function($currmodule->version, $module);
282                 } else if ($newupgrade) {
283                     notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
284                              $mod . ': ' . $fullmod . '/db/upgrade.php');
285                 }
287                 $db->debug=false;
288             /// Now analyze upgrade results
289                 if ($oldupgrade_status && $newupgrade_status) {    // No upgrading failed
290                     // OK so far, now update the modules record
291                     $module->id = $currmodule->id;
292                     if (! update_record('modules', $module)) {
293                         error('Could not update '. $module->name .' record in modules table!');
294                     }
295                     remove_dir($CFG->dataroot . '/cache', true); // flush cache
296                     notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
297                     echo '<hr />';
298                 } else {
299                     notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
300                 }
302             /// Update the capabilities table?
303                 if (!update_capabilities('mod/'.$module->name)) {
304                     error('Could not update '.$module->name.' capabilities!');
305                 }
307                 $updated_modules = true;
309             } else {
310                 upgrade_log_start();
311                 error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
312             }
314         } else {    // module not installed yet, so install it
315             if (!$updated_modules) {
316                 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
317                         upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
318             }
319             upgrade_log_start();
320             print_heading($module->name);
321             $updated_modules = true;
322             $db->debug = true;
323             @set_time_limit(0);  // To allow slow databases to complete the long SQL
325         /// Both old .sql files and new install.xml are supported
326         /// but we priorize install.xml (XMLDB) if present
327             if (file_exists($fullmod . '/db/install.xml')) {
328                 $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
329             } else {
330                 $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method
331             }
333             $db->debug = false;
334         /// Continue with the instalation, roles and other stuff
335             if ($status) {
336                 if ($module->id = insert_record('modules', $module)) {
337                     if (!update_capabilities('mod/'.$module->name)) {
338                         error('Could not set up the capabilities for '.$module->name.'!');
339                     }
340                     notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
341                     echo '<hr />';
342                 } else {
343                     error($module->name .' module could not be added to the module list!');
344                 }
345             } else {
346                 error($module->name .' tables could NOT be set up successfully!');
347             }
348         }
350     /// Check submodules of this module if necessary
352         include_once($fullmod.'/lib.php');  // defines upgrading function
354         $submoduleupgrade = $module->name.'_upgrade_submodules';
355         if (function_exists($submoduleupgrade)) {
356             $submoduleupgrade();
357         }
360     /// Run any defaults or final code that is necessary for this module
362         if ( is_readable($fullmod .'/defaults.php')) {
363             // Insert default values for any important configuration variables
364             unset($defaults);
365             include_once($fullmod .'/defaults.php');
366             if (!empty($defaults)) {
367                 foreach ($defaults as $name => $value) {
368                     if (!isset($CFG->$name)) {
369                         set_config($name, $value);
370                     }
371                 }
372             }
373         }
374     }
376     upgrade_log_finish(); // finish logging if started
378     if ($updated_modules) {
379         print_continue($return);
380         print_footer('none');
381         die;
382     }
385 /**
386  * This function will return FALSE if the lock fails to be set (ie, if it's already locked)
387  *
388  * @param string  $name ?
389  * @param bool  $value ?
390  * @param int  $staleafter ?
391  * @param bool  $clobberstale ?
392  * @todo Finish documenting this function
393  */
394 function set_cron_lock($name,$value=true,$staleafter=7200,$clobberstale=false) {
396     if (empty($name)) {
397         mtrace("Tried to get a cron lock for a null fieldname");
398         return false;
399     }
401     if (empty($value)) {
402         set_config($name,0);
403         return true;
404     }
406     if ($config = get_record('config','name',$name)) {
407         if (empty($config->value)) {
408             set_config($name,time());
409         } else {
410             // check for stale.
411             if ((time() - $staleafter) > $config->value) {
412                 mtrace("STALE LOCKFILE FOR $name - was $config->value");
413                 if (!empty($clobberstale)) {
414                     set_config($name,time());
415                     return true;
416                 }
417             } else {
418                 return false; // was not stale - ie, we're ok to still be running.
419             }
420         }
421     }
422     else {
423         set_config($name,time());
424     }
425     return true;
428 function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
429     static $starttime;
430     static $lasttime;
432     if ($total < 2) {   // No need to show anything
433         return;
434     }
436     if (empty($starttime)) {
437         $starttime = $lasttime = time();
438         $lasttime = $starttime - $updatetime;
439         echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
440         echo '<div id="bar'.$total.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
441         echo '<div id="slider'.$total.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
442         echo '</div>';
443         echo '<div id="text'.$total.'" align="center" style="width:500px;"></div>';
444         echo '</td></tr></table>';
445         echo '</div>';
446     }
448     $now = time();
450     if ($done && (($now - $lasttime) >= $updatetime)) {
451         $elapsedtime = $now - $starttime;
452         $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
453         $percentage = format_float((float)$done / (float)$total, 2);
454         $width = (int)(500 * $percentage);
456         if ($projectedtime > 10) {
457             $projectedtext = '  Ending: '.format_time($projectedtime);
458         } else {
459             $projectedtext = '';
460         }
462         echo '<script>';
463         echo 'document.getElementById("text'.$total.'").innerHTML = "'.addslashes($donetext).' ('.$done.'/'.$total.') '.$projectedtext.'";'."\n";
464         echo 'document.getElementById("slider'.$total.'").style.width = \''.$width.'px\';'."\n";
465         echo '</script>';
467         $lasttime = $now;
468         sleep($sleeptime);
469     }
472 function upgrade_get_javascript() {
473     global $CFG;
475     if (!empty($_SESSION['installautopilot'])) {
476         $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
477     } else {
478         $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
479     }
480     $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>';
482     return $linktoscrolltoerrors;
485 function create_admin_user() {
486     global $CFG, $USER;
488     if (empty($CFG->rolesactive)) {   // No admin user yet.
490         $user = new object();
491         $user->auth         = 'manual';
492         $user->firstname    = get_string('admin');
493         $user->lastname     = get_string('user');
494         $user->username     = 'admin';
495         $user->password     = hash_internal_user_password('admin');
496         $user->email        = 'root@localhost';
497         $user->confirmed    = 1;
498         $user->mnethostid   = $CFG->mnet_localhost_id;
499         $user->lang         = $CFG->lang;
500         $user->maildisplay  = 1;
501         $user->timemodified = time();
503         if (!$user->id = insert_record('user', $user)) {
504             error('SERIOUS ERROR: Could not create admin user record !!!');
505         }
507         if (!$user = get_record('user', 'id', $user->id)) {   // Double check.
508             error('User ID was incorrect (can\'t find it)');
509         }
511         // Assign the default admin roles to the new user.
512         if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW)) {
513             error('No admin role could be found');
514         }
515         $sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID);
516         foreach ($adminroles as $adminrole) {
517             role_assign($adminrole->id, $user->id, 0, $sitecontext->id);
518         }
520         set_config('rolesactive', 1);
522         // Log the user in.
523         $USER = get_complete_user_data('username', 'admin');
524         $USER->newadminuser = 1;
525         load_all_capabilities();
527         redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id");  // Edit thyself
528     } else {
529         error('Can not create admin!');
530     }
533 ////////////////////////////////////////////////
534 /// upgrade logging functions
535 ////////////////////////////////////////////////
537 $upgradeloghandle = false;
538 $upgradelogbuffer = '';
539 // I did not find out how to use static variable in callback function,
540 // the problem was that I could not flush the static buffer :-(
541 global $upgradeloghandle, $upgradelogbuffer;
543 /**
544  * Check if upgrade is already running.
545  *
546  * If anything goes wrong due to missing call to upgrade_log_finish()
547  * just restart the browser.
548  *
549  * @param string warning message indicating upgrade is already running
550  * @param int page reload timeout
551  */
552 function upgrade_check_running($message, $timeout) {
553     if (!empty($_SESSION['upgraderunning'])) {
554         print_header();
555         redirect(me(), $message, $timeout);
556     }
559 /**
560  * Start logging of output into file (if not disabled) and
561  * prevent aborting and concurrent execution of upgrade script.
562  *
563  * Please note that you can not write into session variables after calling this function!
564  *
565  * This function may be called repeatedly.
566  */
567 function upgrade_log_start() {
568     global $CFG, $upgradeloghandle;
570     if (!empty($_SESSION['upgraderunning'])) {
571         return; // logging already started
572     }
574     @ignore_user_abort(true);            // ignore if user stops or otherwise aborts page loading
575     $_SESSION['upgraderunning'] = 1;     // set upgrade indicator
576     if (empty($CFG->dbsessions)) {       // workaround for bug in adodb, db session can not be restarted
577         session_write_close();           // from now on user can reload page - will be displayed warning
578     }
579     make_upload_directory('upgradelogs');
580     ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
581     register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
584 /**
585  * Terminate logging of output, flush all data, allow script aborting
586  * and reopen session for writing. Function error() does terminate the logging too.
587  *
588  * Please make sure that each upgrade_log_start() is properly terminated by
589  * this function or error().
590  *
591  * This function may be called repeatedly.
592  */
593 function upgrade_log_finish() {
594     global $CFG, $upgradeloghandle, $upgradelogbuffer;
596     if (empty($_SESSION['upgraderunning'])) {
597         return; // logging already terminated
598     }
600     @ob_end_flush();
601     if ($upgradelogbuffer !== '') {
602         @fwrite($upgradeloghandle, $upgradelogbuffer);
603         $upgradelogbuffer = '';
604     }
605     if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
606         @fclose($upgradeloghandle);
607         $upgradeloghandle = false;
608     }
609     if (empty($CFG->dbsessions)) {
610         @session_start();                // ignore header errors, we only need to reopen session
611     }
612     $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
613     if (connection_aborted()) {
614         die;
615     }
616     @ignore_user_abort(false);
619 /**
620  * Callback function for logging into files. Not more than one file is created per minute,
621  * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
622  *
623  * This function must not output any characters or throw warnigns and errors!
624  */
625 function upgrade_log_callback($string) {
626     global $CFG, $upgradeloghandle, $upgradelogbuffer;
628     if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
629         if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
630             $upgradelogbuffer .= $string;
631             if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
632                 @fwrite($upgradeloghandle, $upgradelogbuffer);
633                 $upgradelogbuffer = '';
634             }
635         } else {
636             $upgradeloghandle = 'error';
637         }
638     }
639     return $string;
642 /**
643  * Try to verify that dataroot is not accessible from web.
644  * It is not 100% correct but might help to reduce number of vulnerable sites.
645  *
646  * Protection from httpd.conf and .htaccess is not detected properly.
647  */
648 function is_dataroot_insecure() {
649     global $CFG;
651     $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
653     $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
654     $rp = strrev(trim($rp, '/'));
655     $rp = explode('/', $rp);
656     foreach($rp as $r) {
657         if (strpos($siteroot, '/'.$r.'/') === 0) {
658             $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
659         } else {
660             break; // probably alias root
661         }
662     }
664     $siteroot = strrev($siteroot);
665     $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
667     if (strpos($dataroot, $siteroot) === 0) {
668         return true;
669     }
670     return false;
673 /// =============================================================================================================
674 /// administration tree classes and functions
677 // n.b. documentation is still in progress for this code
679 /// INTRODUCTION
681 /// This file performs the following tasks:
682 ///  -it defines the necessary objects and interfaces to build the Moodle
683 ///   admin hierarchy
684 ///  -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
685 ///   and admin_externalpage_print_footer() functions used on admin pages
687 /// ADMIN_SETTING OBJECTS
689 /// Moodle settings are represented by objects that inherit from the admin_setting
690 /// class. These objects encapsulate how to read a setting, how to write a new value
691 /// to a setting, and how to appropriately display the HTML to modify the setting.
693 /// ADMIN_SETTINGPAGE OBJECTS
695 /// The admin_setting objects are then grouped into admin_settingpages. The latter
696 /// appear in the Moodle admin tree block. All interaction with admin_settingpage
697 /// objects is handled by the admin/settings.php file.
699 /// ADMIN_EXTERNALPAGE OBJECTS
701 /// There are some settings in Moodle that are too complex to (efficiently) handle
702 /// with admin_settingpages. (Consider, for example, user management and displaying
703 /// lists of users.) In this case, we use the admin_externalpage object. This object
704 /// places a link to an external PHP file in the admin tree block.
706 /// If you're using an admin_externalpage object for some settings, you can take
707 /// advantage of the admin_externalpage_* functions. For example, suppose you wanted
708 /// to add a foo.php file into admin. First off, you add the following line to
709 /// admin/settings/first.php (at the end of the file) or to some other file in
710 /// admin/settings:
712 ///    $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
713 ///        $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
715 /// Next, in foo.php, your file structure would resemble the following:
717 ///        require_once('.../config.php');
718 ///        require_once($CFG->libdir.'/adminlib.php');
719 ///        $adminroot = admin_get_root();
720 ///        admin_externalpage_setup('foo', $adminroot);
721 ///        // functionality like processing form submissions goes here
722 ///        admin_externalpage_print_header($adminroot);
723 ///        // your HTML goes here
724 ///        admin_externalpage_print_footer($adminroot);
726 /// The admin_externalpage_setup() function call ensures the user is logged in,
727 /// and makes sure that they have the proper role permission to access the page.
729 /// The admin_externalpage_print_header() function prints the header (it figures
730 /// out what category and subcategories the page is classified under) and ensures
731 /// that you're using the admin pagelib (which provides the admin tree block and
732 /// the admin bookmarks block).
734 /// The admin_externalpage_print_footer() function properly closes the tables
735 /// opened up by the admin_externalpage_print_header() function and prints the
736 /// standard Moodle footer.
738 /// ADMIN_CATEGORY OBJECTS
740 /// Above and beyond all this, we have admin_category objects. These objects
741 /// appear as folders in the admin tree block. They contain admin_settingpage's,
742 /// admin_externalpage's, and other admin_category's.
744 /// OTHER NOTES
746 /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
747 /// from part_of_admin_tree (a pseudointerface). This interface insists that
748 /// a class has a check_access method for access permissions, a locate method
749 /// used to find a specific node in the admin tree, and a path method used
750 /// to determine the path to a specific node in the $ADMIN tree.
752 /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
753 /// interface ensures that the class implements a recursive add function which
754 /// accepts a part_of_admin_tree object and searches for the proper place to
755 /// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
757 /// Please note that the $this->name field of any part_of_admin_tree must be
758 /// UNIQUE throughout the ENTIRE admin tree.
760 /// The $this->name field of an admin_setting object (which is *not* part_of_
761 /// admin_tree) must be unique on the respective admin_settingpage where it is
762 /// used.
765 /// MISCELLANEOUS STUFF (used by classes defined below) ///////////////////////
766 include_once($CFG->dirroot . '/backup/lib.php');
768 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
770 /**
771  * Pseudointerface for anything appearing in the admin tree
772  *
773  * The pseudointerface that is implemented by anything that appears in the admin tree
774  * block. It forces inheriting classes to define a method for checking user permissions
775  * and methods for finding something in the admin tree.
776  *
777  * @author Vincenzo K. Marcovecchio
778  * @package admin
779  */
780 class part_of_admin_tree {
782     /**
783      * Finds a named part_of_admin_tree.
784      *
785      * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
786      * and not parentable_part_of_admin_tree, then this function should only check if
787      * $this->name matches $name. If it does, it should return a reference to $this,
788      * otherwise, it should return a reference to NULL.
789      *
790      * If a class inherits parentable_part_of_admin_tree, this method should be called
791      * recursively on all child objects (assuming, of course, the parent object's name
792      * doesn't match the search criterion).
793      *
794      * @param string $name The internal name of the part_of_admin_tree we're searching for.
795      * @return mixed An object reference or a NULL reference.
796      */
797     function &locate($name) {
798         trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
799         return;
800     }
802     /**
803      * Removes named part_of_admin_tree.
804      *
805      * @param string $name The internal name of the part_of_admin_tree we want to remove.
806      * @return bool success.
807      */
808     function prune($name) {
809         trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
810         return;
811     }
813     /**
814      * Verifies current user's access to this part_of_admin_tree.
815      *
816      * Used to check if the current user has access to this part of the admin tree or
817      * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
818      * then this method is usually just a call to has_capability() in the site context.
819      *
820      * If a class inherits parentable_part_of_admin_tree, this method should return the
821      * logical OR of the return of check_access() on all child objects.
822      *
823      * @return bool True if the user has access, false if she doesn't.
824      */
825     function check_access() {
826         trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
827         return;
828     }
830     /**
831      * Mostly usefull for removing of some parts of the tree in admin tree block.
832      *
833      * @return True is hidden from normal list view
834      */
835     function is_hidden() {
836         trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
837         return;
838     }
840     /**
841      * Determines the path to $name in the admin tree.
842      *
843      * Used to determine the path to $name in the admin tree. If a class inherits only
844      * part_of_admin_tree and not parentable_part_of_admin_tree, then this method should
845      * check if $this->name matches $name. If it does, $name is pushed onto the $path
846      * array (at the end), and $path should be returned. If it doesn't, NULL should be
847      * returned.
848      *
849      * If a class inherits parentable_part_of_admin_tree, it should do the above, but not
850      * return NULL on failure. Instead, it pushes $this->name onto $path, and then
851      * recursively calls path() on its child objects. If any are non-NULL, it should
852      * return $path (being certain that the last element of $path is equal to $name).
853      * If they are all NULL, it returns NULL.
854      *
855      * @param string $name The internal name of the part_of_admin_tree we're searching for.
856      * @param array $path Not used on external calls. Defaults to empty array.
857      * @return mixed If found, an array containing the internal names of each part_of_admin_tree that leads to $name. If not found, NULL.
858      */
859     function path($name, $path = array()) {
860         trigger_error('Admin class does not implement method <strong>path()</strong>', E_USER_WARNING);
861         return;
862     }
865 /**
866  * Pseudointerface implemented by any part_of_admin_tree that has children.
867  *
868  * The pseudointerface implemented by any part_of_admin_tree that can be a parent
869  * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
870  * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
871  * include an add method for adding other part_of_admin_tree objects as children.
872  *
873  * @author Vincenzo K. Marcovecchio
874  * @package admin
875  */
876 class parentable_part_of_admin_tree extends part_of_admin_tree {
878     /**
879      * Adds a part_of_admin_tree object to the admin tree.
880      *
881      * Used to add a part_of_admin_tree object to this object or a child of this
882      * object. $something should only be added if $destinationname matches
883      * $this->name. If it doesn't, add should be called on child objects that are
884      * also parentable_part_of_admin_tree's.
885      *
886      * @param string $destinationname The internal name of the new parent for $something.
887      * @param part_of_admin_tree &$something The object to be added.
888      * @return bool True on success, false on failure.
889      */
890     function add($destinationname, &$something) {
891         trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
892         return;
893     }
897 /**
898  * The object used to represent folders (a.k.a. categories) in the admin tree block.
899  *
900  * Each admin_category object contains a number of part_of_admin_tree objects.
901  *
902  * @author Vincenzo K. Marcovecchio
903  * @package admin
904  */
905 class admin_category extends parentable_part_of_admin_tree {
907     /**
908      * @var mixed An array of part_of_admin_tree objects that are this object's children
909      */
910     var $children;
912     /**
913      * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
914      */
915     var $name;
917     /**
918      * @var string The displayed name for this category. Usually obtained through get_string()
919      */
920     var $visiblename;
922     /**
923      * @var bool Should this category be hidden in admin tree block?
924      */
925     var $hidden;
927     // constructor for an empty admin category
928     // $name is the internal name of the category. it MUST be unique in the entire hierarchy
929     // $visiblename is the displayed name of the category. use a get_string for this
931     /**
932      * Constructor for an empty admin category
933      *
934      * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
935      * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
936      * @param bool $hidden hide category in admin tree block
937      * @return mixed Returns the new object.
938      */
939     function admin_category($name, $visiblename, $hidden = false) {
940         $this->children = array();
941         $this->name = $name;
942         $this->visiblename = $visiblename;
943         $this->hidden = $hidden;
944     }
946     /**
947      * Finds the path to the part_of_admin_tree called $name.
948      *
949      * @param string $name The internal name that we're searching for.
950      * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
951      * @return mixed An array of internal names that leads to $name, or NULL if not found.
952      */
953     function path($name, $path = array()) {
955         $path[count($path)] = $this->name;
957         if ($this->name == $name) {
958             return $path;
959         }
961         foreach($this->children as $child) {
962             if ($return = $child->path($name, $path)) {
963                 return $return;
964             }
965         }
967         return NULL;
969     }
971     /**
972      * Returns a reference to the part_of_admin_tree object with internal name $name.
973      *
974      * @param string $name The internal name of the object we want.
975      * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
976      */
977     function &locate($name) {
979         if ($this->name == $name) {
980             return $this;
981         }
983         foreach($this->children as $child) {
984             if ($return =& $child->locate($name)) {
985                 return $return;
986             }
987         }
988         $return = NULL;
989         return $return;
990     }
992     /**
993      * Removes part_of_admin_tree object with internal name $name.
994      *
995      * @param string $name The internal name of the object we want to remove.
996      * @return bool success
997      */
998     function prune($name) {
1000         if ($this->name == $name) {
1001             return false;  //can not remove itself
1002         }
1004         foreach($this->children as $precedence => $child) {
1005             if ($child->name == $name) {
1006                 // found it!
1007                 unset($this->children[$precedence]);
1008                 return true;
1009             }
1010             if ($this->children[$precedence]->prune($name)) {
1011                 return true;
1012             }
1013         }
1014         return false;
1015     }
1017     /**
1018      * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
1019      *
1020      * @param string $destinationame The internal name of the immediate parent that we want for &$something.
1021      * @param mixed &$something A part_of_admin_tree object to be added.
1022      * @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".
1023      * @return bool True if successfully added, false if &$something is not a part_of_admin_tree or if $name is not found.
1024      */
1025     function add($destinationname, &$something, $precedence = '') {
1027         if (!is_a($something, 'part_of_admin_tree')) {
1028             return false;
1029         }
1031         if ($destinationname == $this->name) {
1032             if ($precedence === '') {
1033                 $this->children[] = $something;
1034             } else {
1035                 if (isset($this->children[$precedence])) { // this should never, ever be triggered in a release version of moodle.
1036                     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 />');
1037                 }
1038                 $this->children[$precedence] = $something;
1039             }
1040             return true;
1041         }
1043         unset($entries);
1045         $entries = array_keys($this->children);
1047         foreach($entries as $entry) {
1048             $child =& $this->children[$entry];
1049             if (is_a($child, 'parentable_part_of_admin_tree')) {
1050                 if ($child->add($destinationname, $something, $precedence)) {
1051                     return true;
1052                 }
1053             }
1054         }
1056         return false;
1058     }
1060     /**
1061      * Checks if the user has access to anything in this category.
1062      *
1063      * @return bool True if the user has access to atleast one child in this category, false otherwise.
1064      */
1065     function check_access() {
1067         $return = false;
1068         foreach ($this->children as $child) {
1069             $return = $return || $child->check_access();
1070         }
1072         return $return;
1074     }
1076     /**
1077      * Is this category hidden in admin tree block?
1078      *
1079      * @return bool True if hidden
1080      */
1081     function is_hidden() {
1082         return $this->hidden;
1083     }
1086 /**
1087  * Links external PHP pages into the admin tree.
1088  *
1089  * See detailed usage example at the top of this document (adminlib.php)
1090  *
1091  * @author Vincenzo K. Marcovecchio
1092  * @package admin
1093  */
1094 class admin_externalpage extends part_of_admin_tree {
1096     /**
1097      * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1098      */
1099     var $name;
1101     /**
1102      * @var string The displayed name for this external page. Usually obtained through get_string().
1103      */
1104     var $visiblename;
1106     /**
1107      * @var string The external URL that we should link to when someone requests this external page.
1108      */
1109     var $url;
1111     /**
1112      * @var string The role capability/permission a user must have to access this external page.
1113      */
1114     var $req_capability;
1116     /**
1117      * @var bool hidden in admin tree block.
1118      */
1119     var $hidden;
1121     /**
1122      * Constructor for adding an external page into the admin tree.
1123      *
1124      * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1125      * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1126      * @param string $url The external URL that we should link to when someone requests this external page.
1127      * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1128      */
1129     function admin_externalpage($name, $visiblename, $url, $req_capability = 'moodle/site:config', $hidden=false) {
1130         $this->name = $name;
1131         $this->visiblename = $visiblename;
1132         $this->url = $url;
1133         if (is_array($req_capability)) {
1134             $this->req_capability = $req_capability;
1135         } else {
1136             $this->req_capability = array($req_capability);
1137         }
1138         $this->hidden = $hidden;
1139     }
1141     /**
1142      * Finds the path to the part_of_admin_tree called $name.
1143      *
1144      * @param string $name The internal name that we're searching for.
1145      * @param array $path Used internally for recursive calls. Do not specify on external calls. Defaults to array().
1146      * @return mixed An array of internal names that leads to $name, or NULL if not found.
1147      */
1148     function path($name, $path = array()) {
1149         if ($name == $this->name) {
1150             array_push($path, $this->name);
1151             return $path;
1152         } else {
1153             return NULL;
1154         }
1155     }
1157     /**
1158      * Returns a reference to the part_of_admin_tree object with internal name $name.
1159      *
1160      * @param string $name The internal name of the object we want.
1161      * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1162      */
1163     function &locate($name) {
1164         $return = ($this->name == $name ? $this : NULL);
1165         return $return;
1166     }
1168     function prune($name) {
1169         return false;
1170     }
1172     /**
1173      * Determines if the current user has access to this external page based on $this->req_capability.
1174      *
1175      * @uses CONTEXT_SYSTEM
1176      * @uses SITEID
1177      * @return bool True if user has access, false otherwise.
1178      */
1179     function check_access() {
1180         if (!get_site()) {
1181             return true; // no access check before site is fully set up
1182         }
1183         $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
1184         foreach($this->req_capability as $cap) {
1185             if (has_capability($cap, $context)) {
1186                 return true;
1187             }
1188         }
1189         return false;
1190     }
1192     /**
1193      * Is this external page hidden in admin tree block?
1194      *
1195      * @return bool True if hidden
1196      */
1197     function is_hidden() {
1198         return $this->hidden;
1199     }
1203 /**
1204  * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1205  *
1206  * @author Vincenzo K. Marcovecchio
1207  * @package admin
1208  */
1209 class admin_settingpage extends part_of_admin_tree {
1211     /**
1212      * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
1213      */
1214     var $name;
1216     /**
1217      * @var string The displayed name for this external page. Usually obtained through get_string().
1218      */
1219     var $visiblename;
1220     /**
1221      * @var mixed An array of admin_setting objects that are part of this setting page.
1222      */
1223     var $settings;
1225     /**
1226      * @var string The role capability/permission a user must have to access this external page.
1227      */
1228     var $req_capability;
1230     /**
1231      * @var bool hidden in admin tree block.
1232      */
1233     var $hidden;
1235     // see admin_category
1236     function path($name, $path = array()) {
1237         if ($name == $this->name) {
1238             array_push($path, $this->name);
1239             return $path;
1240         } else {
1241             return NULL;
1242         }
1243     }
1245     // see admin_category
1246     function &locate($name) {
1247         $return = ($this->name == $name ? $this : NULL);
1248         return $return;
1249     }
1251     function prune($name) {
1252         return false;
1253     }
1255     // see admin_externalpage
1256     function admin_settingpage($name, $visiblename, $req_capability = 'moodle/site:config', $hidden=false) {
1257         global $CFG;
1258         $this->settings = new stdClass();
1259         $this->name = $name;
1260         $this->visiblename = $visiblename;
1261         if (is_array($req_capability)) {
1262             $this->req_capability = $req_capability;
1263         } else {
1264             $this->req_capability = array($req_capability);
1265         }
1266         $this->hidden = false;
1267     }
1269     // 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
1270     // n.b. each admin_setting in an admin_settingpage must have a unique internal name
1271     // &$setting is the admin_setting object you want to add
1272     // returns true if successful, false if not (will fail if &$setting is an admin_setting or child thereof)
1273     function add(&$setting) {
1274         if (is_a($setting, 'admin_setting')) {
1275             $this->settings->{$setting->name} =& $setting;
1276             return true;
1277         }
1278         return false;
1279     }
1281     // see admin_externalpage
1282     function check_access() {
1283         if (!get_site()) {
1284             return true; // no access check before site is fully set up
1285         }
1286         $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
1287         foreach($this->req_capability as $cap) {
1288             if (has_capability($cap, $context)) {
1289                 return true;
1290             }
1291         }
1292         return false;
1293     }
1295     // outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1296     // returns a string of the html
1297     function output_html() {
1298         $return = '<fieldset>' . "\n";
1299         $return .= '<div class="clearer"><!-- --></div>' . "\n";
1300         foreach($this->settings as $setting) {
1301             $return .= $setting->output_html();
1302         }
1303         $return .= '</fieldset>';
1304         return $return;
1305     }
1307     // 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
1308     // -- calls write_setting() to each child setting, sending it only the data that matches each setting's internal name
1309     // $data should be the result from data_submitted()
1310     // returns an empty string if everything went well, otherwise returns a printable error string (that's language-specific)
1311     function write_settings($data) {
1312         $return = '';
1313         foreach($this->settings as $setting) {
1314             if (isset($data['s_' . $setting->name])) {
1315                 $return .= $setting->write_setting($data['s_' . $setting->name]);
1316             } else {
1317                 $return .= $setting->write_setting('');
1318             }
1319         }
1320         return $return;
1321     }
1323     /**
1324      * Is this settigns page hidden in admin tree block?
1325      *
1326      * @return bool True if hidden
1327      */
1328     function is_hidden() {
1329         return $this->hidden;
1330     }
1335 // read & write happens at this level; no authentication
1336 class admin_setting {
1338     var $name;
1339     var $visiblename;
1340     var $description;
1341     var $defaultsetting;
1343     function admin_setting($name, $visiblename, $description, $defaultsetting) {
1344         $this->name = $name;
1345         $this->visiblename = $visiblename;
1346         $this->description = $description;
1347         $this->defaultsetting = $defaultsetting;
1348     }
1350     function get_setting() {
1351         return NULL; // has to be overridden
1352     }
1354     function write_setting($data) {
1355         return; // has to be overridden
1356     }
1358     function output_html() {
1359         return; // has to be overridden
1360     }
1365 class admin_setting_configtext extends admin_setting {
1367     var $paramtype;
1369     function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
1370         $this->paramtype = $paramtype;
1371         parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1372     }
1374     // returns a string or NULL
1375     function get_setting() {
1376         global $CFG;
1377         return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1378     }
1380     // $data is a string
1381     function write_setting($data) {
1382         if (!$this->validate($data)) {
1383             return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
1384         }
1385         return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1386     }
1388     function validate($data) {
1389         if (is_string($this->paramtype)) {
1390             return preg_match($this->paramtype, $data);
1391         } else if ($this->paramtype === PARAM_RAW) {
1392             return true;
1393         } else {
1394             $cleaned = clean_param($data, $this->paramtype);
1395             return ("$data" == "$cleaned"); // implicit conversion to string is needed to do exact comparison
1396         }
1397     }
1399     function output_html() {
1400         if ($this->get_setting() === NULL) {
1401             $current = $this->defaultsetting;
1402         } else {
1403             $current = $this->get_setting();
1404         }
1405         return format_admin_setting($this->name, $this->visiblename,
1406                 '<input type="text" class="form-text" id="id_s_'.$this->name.'" name="s_'.$this->name.'" value="'.s($current).'" />',
1407                 $this->description);
1408     }
1412 class admin_setting_configcheckbox extends admin_setting {
1414     function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting) {
1415         parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1416     }
1418     function get_setting() {
1419         global $CFG;
1420         return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1421     }
1423     function write_setting($data) {
1424         if ($data == '1') {
1425             return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1426         } else {
1427             return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1428         }
1429     }
1431     function output_html() {
1432         if ($this->get_setting() === NULL) {
1433             $current = $this->defaultsetting;
1434         } else {
1435             $current = $this->get_setting();
1436         }
1437         return format_admin_setting($this->name, $this->visiblename,
1438                 '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($current == true ? 'checked="checked"' : '') . ' />',
1439                 $this->description);
1440     }
1444 class admin_setting_configselect extends admin_setting {
1446     var $choices;
1448     function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
1449         $this->choices = $choices;
1450         parent::admin_setting($name, $visiblename, $description, $defaultsetting);
1451     }
1453     function get_setting() {
1454         global $CFG;
1455         return (isset($CFG->{$this->name}) ? $CFG->{$this->name} : NULL);
1456     }
1458     function write_setting($data) {
1459          // check that what we got was in the original choices
1460          // or that the data is the default setting - needed during install when choices can not be constructed yet
1461          if ($data != $this->defaultsetting and ! in_array($data, array_keys($this->choices))) {
1462              return 'Error setting ' . $this->visiblename . '<br />';
1463          }
1465          return (set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1466     }
1468     function output_html() {
1469         if ($this->get_setting() === NULL) {
1470             $current = $this->defaultsetting;
1471         } else {
1472             $current = $this->get_setting();
1473         }
1474         $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'">';
1475         foreach ($this->choices as $key => $value) {
1476             // the string cast is needed because key may be integer - 0 is equal to most strings!
1477             $return .= '<option value="'.$key.'"'.((string)$key==$current ? ' selected="selected"' : '').'>'.$value.'</option>';
1478         }
1479         $return .= '</select>';
1481         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1482     }
1486 // 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
1487 // internally for the setting)
1488 class admin_setting_configtime extends admin_setting {
1490     var $name2;
1491     var $choices;
1492     var $choices2;
1494     function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
1495         $this->name2 = $minutesname;
1496         $this->choices = array();
1497         for ($i = 0; $i < 24; $i++) {
1498             $this->choices[$i] = $i;
1499         }
1500         $this->choices2 = array();
1501         for ($i = 0; $i < 60; $i += 5) {
1502             $this->choices2[$i] = $i;
1503         }
1504         parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
1505     }
1507     function get_setting() {
1508         global $CFG;
1509         return (isset($CFG->{$this->name}) && isset($CFG->{$this->name2}) ? array('h' => $CFG->{$this->name}, 'm' => $CFG->{$this->name2}) : NULL);
1510     }
1512     function write_setting($data) {
1513          // check that what we got was in the original choices
1514          if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
1515              return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1516          }
1518          return (set_config($this->name, $data['h']) && set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1519     }
1521     function output_html() {
1522         if ($this->get_setting() === NULL) {
1523           $currentsetting = $this->defaultsetting;
1524         } else {
1525           $currentsetting = $this->get_setting();
1526         }
1527         $return = '<div class="form-group">'.
1528                   '<select class="form-select" id="id_s_'.$this->name.'h" name="s_' . $this->name .'[h]">';
1529         foreach ($this->choices as $key => $value) {
1530             $return .= '<option value="' . $key . '"' . ($key == $currentsetting['h'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1531         }
1532         $return .= '</select>:<select class="form-select" id="id_s_'.$this->name.'m" name="s_' . $this->name . '[m]">';
1533         foreach ($this->choices2 as $key => $value) {
1534             $return .= '<option value="' . $key . '"' . ($key == $currentsetting['m'] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1535         }
1536         $return .= '</select></div>';
1537         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1538     }
1542 class admin_setting_configmultiselect extends admin_setting_configselect {
1544     function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
1545         parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1546     }
1548     function get_setting() {
1549         global $CFG;
1550         if (isset($CFG->{$this->name})) {
1551             if ($CFG->{$this->name}) {
1552                 return explode(',', $CFG->{$this->name});
1553             } else {
1554                 return array();
1555             }            
1556         } else {
1557             return NULL;
1558         }
1559     }
1561     function write_setting($data) {
1562         if (empty($data)) {
1563             $data = array();
1564         }
1565         foreach ($data as $datum) {
1566             if (! in_array($datum, array_keys($this->choices))) {
1567                 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1568             }
1569         }
1571         return (set_config($this->name, implode(',',$data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1572     }
1574     function output_html() {
1575         if ($this->get_setting() === NULL) {
1576           $currentsetting = $this->defaultsetting;
1577           if (!$currentsetting) {
1578               $currentsetting = array();
1579           }
1580         } else {
1581           $currentsetting = $this->get_setting();
1582         }
1583         $return = '<select class="form-select" id="id_s_'.$this->name.'" name="s_' . $this->name .'[]" size="10" multiple="multiple">';
1584         foreach ($this->choices as $key => $value) {
1585             $return .= '<option value="' . $key . '"' . (in_array($key,$currentsetting) ? ' selected="selected"' : '') . '>' . $value . '</option>';
1586         }
1587         $return .= '</select>';
1588         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1589     }
1593 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
1595     function admin_setting_special_adminseesall() {
1596         $name = 'calendar_adminseesall';
1597         $visiblename = get_string('adminseesall', 'admin');
1598         $description = get_string('helpadminseesall', 'admin');
1599         parent::admin_setting($name, $visiblename, $description, 0);
1600     }
1602     function write_setting($data) {
1603         global $SESSION;
1604         unset($SESSION->cal_courses_shown);
1605         parent::write_setting($data);
1606     }
1609 class admin_setting_sitesetselect extends admin_setting_configselect {
1611     var $id;
1613     function admin_setting_sitesetselect($name, $visiblename, $description, $defaultsetting, $choices) {
1615         $this->id = SITEID;
1616         parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
1618     }
1620     function get_setting() {
1621         $site = get_site();
1622         return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1623     }
1625     function write_setting($data) {
1626         if (!in_array($data, array_keys($this->choices))) {
1627             return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1628         }
1629         $record = new stdClass();
1630         $record->id = $this->id;
1631         $temp = $this->name;
1632         $record->$temp = $data;
1633         $record->timemodified = time();
1634         return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1635     }
1640 class admin_setting_courselist_frontpage extends admin_setting_configselect {
1642     function admin_setting_courselist_frontpage($loggedin) {
1643         global $CFG;
1644         require_once($CFG->dirroot . '/course/lib.php');
1645         $name = 'frontpage' . ($loggedin ? 'loggedin' : '');
1646         $visiblename = get_string('frontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1647         $description = get_string('configfrontpage' . ($loggedin ? 'loggedin' : ''),'admin');
1648         $choices = array(FRONTPAGENEWS          => get_string('frontpagenews'),
1649                          FRONTPAGECOURSELIST    => get_string('frontpagecourselist'),
1650                          FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
1651                          FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
1652                          ''                     => get_string('none'));
1653         if (count_records("course") > FRONTPAGECOURSELIMIT) {
1654             unset($choices[FRONTPAGECOURSELIST]);
1655         }
1656         $defaults = FRONTPAGECOURSELIST.',,,';
1657         parent::admin_setting_configselect($name, $visiblename, $description, $defaults, $choices);
1658     }
1660     function get_setting() {
1661         global $CFG;
1662         return (isset($CFG->{$this->name}) ? explode(',', $CFG->{$this->name}) : ',1,,');
1663     }
1665     function write_setting($data) {
1666         if (empty($data)) {
1667             $data = array();
1668         } if (!is_array($data)) {
1669             $data = explode(',', $data);
1670         }
1671         foreach($data as $datum) {
1672             if (! in_array($datum, array_keys($this->choices))) {
1673                 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
1674             }
1675         }
1676         return (set_config($this->name, implode(',', $data)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1677     }
1679     function output_html() {
1680         if ($this->get_setting() === NULL) {
1681             $currentsetting = $this->defaultsetting;
1682         } else {
1683             $currentsetting = $this->get_setting();
1684         }
1685         for ($i = 0; $i < count($this->choices) - 1; $i++) {
1686             if (!isset($currentsetting[$i])) {
1687                 $currentsetting[$i] = 0;
1688             }
1689         }
1690         $return = '<div class="form-group">';
1691         for ($i = 0; $i < count($this->choices) - 1; $i++) {
1692             $return .='<select class="form-select" id="id_s_'.$this->name.$i.'" name="s_' . $this->name .'[]">';
1693             foreach ($this->choices as $key => $value) {
1694                 $return .= '<option value="' . $key . '"' . ($key == $currentsetting[$i] ? ' selected="selected"' : '') . '>' . $value . '</option>';
1695             }
1696             $return .= '</select>';
1697             if ($i !== count($this->choices) - 2) {
1698                 $return .= '<br />';
1699             }
1700         }
1701         $return .= '</div>';
1703         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1704     }
1707 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
1709     var $id;
1711     function admin_setting_sitesetcheckbox($name, $visiblename, $description, $defaultsetting) {
1713         $this->id = SITEID;
1714         parent::admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting);
1716     }
1718     function get_setting() {
1719         $site = get_site();
1720         return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1721     }
1723     function write_setting($data) {
1724         $record = new stdClass();
1725         $record->id = $this->id;
1726         $temp = $this->name;
1727         $record->$temp = ($data == '1' ? 1 : 0);
1728         $record->timemodified = time();
1729         return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1730     }
1734 class admin_setting_sitesettext extends admin_setting_configtext {
1736     var $id;
1738     function admin_setting_sitesettext($name, $visiblename, $description, $defaultsetting) {
1740         $this->id = SITEID;
1741         parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting);
1743     }
1745     function get_setting() {
1746         $site = get_site();
1747         return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1748     }
1750     function validate($data) {
1751         $cleaned = clean_param($data, PARAM_NOTAGS);
1752         if ($cleaned == '') {
1753             return false; // can not be empty
1754         }
1755         return ("$data" == "$cleaned"); // implicit conversion to string is needed to do exact comparison
1756     }
1758     function write_setting($data) {
1759         $data = trim($data);
1760         if (!$this->validate($data)) {
1761             return get_string('validateerror', 'admin') . $this->visiblename . '<br />';
1762         }
1764         $record = new stdClass();
1765         $record->id = $this->id;
1766         $record->{$this->name} = $data;
1767         $record->timemodified = time();
1768         return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1769     }
1773 class admin_setting_special_frontpagedesc extends admin_setting {
1775     var $id;
1777     function admin_setting_special_frontpagedesc() {
1778         $this->id = SITEID;
1779         $name = 'summary';
1780         $visiblename = get_string('frontpagedescription');
1781         $description = get_string('frontpagedescriptionhelp');
1782         parent::admin_setting($name, $visiblename, $description, '');
1783     }
1785     function output_html() {
1787         global $CFG;
1789         if ($this->get_setting() === NULL) {
1790             $currentsetting = $this->defaultsetting;
1791         } else {
1792             $currentsetting = $this->get_setting();
1793         }
1795         $CFG->adminusehtmleditor = can_use_html_editor();
1797         $return = print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, 's_' . $this->name, $currentsetting, 0, true);
1799         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1800     }
1802     function get_setting() {
1804         $site = get_site();
1805         return (isset($site->{$this->name}) ? $site->{$this->name} : NULL);
1807     }
1809     function write_setting($data) {
1811         $data = addslashes(clean_param($data, PARAM_CLEANHTML));
1813         $record = new stdClass();
1814         $record->id = $this->id;
1815         $temp = $this->name;
1816         $record->$temp = $data;
1817         $record->timemodified = time();
1819         return(update_record('course', $record) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1821     }
1826 class admin_setting_special_editorfontlist extends admin_setting {
1828     var $items;
1830     function admin_setting_special_editorfontlist() {
1831         global $CFG;
1832         $name = 'editorfontlist';
1833         $visiblename = get_string('editorfontlist', 'admin');
1834         $description = get_string('configeditorfontlist', 'admin');
1835         $defaults = array('k0' => 'Trebuchet',
1836                           'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
1837                           'k1' => 'Arial',
1838                           'v1' => 'arial,helvetica,sans-serif',
1839                           'k2' => 'Courier New',
1840                           'v2' => 'courier new,courier,monospace',
1841                           'k3' => 'Georgia',
1842                           'v3' => 'georgia,times new roman,times,serif',
1843                           'k4' => 'Tahoma',
1844                           'v4' => 'tahoma,arial,helvetica,sans-serif',
1845                           'k5' => 'Times New Roman',
1846                           'v5' => 'times new roman,times,serif',
1847                           'k6' => 'Verdana',
1848                           'v6' => 'verdana,arial,helvetica,sans-serif',
1849                           'k7' => 'Impact',
1850                           'v7' => 'impact',
1851                           'k8' => 'Wingdings',
1852                           'v8' => 'wingdings');
1853         parent::admin_setting($name, $visiblename, $description, $defaults);
1854     }
1856     function get_setting() {
1857         global $CFG;
1858         if (isset($CFG->editorfontlist)) {
1859             $i = 0;
1860             $currentsetting = array();
1861             $items = explode(';', $CFG->editorfontlist);
1862             foreach ($items as $item) {
1863               $item = explode(':', $item);
1864               $currentsetting['k' . $i] = $item[0];
1865               $currentsetting['v' . $i] = $item[1];
1866               $i++;
1867             }
1868             return $currentsetting;
1869         } else {
1870             return NULL;
1871         }
1872     }
1874     function write_setting($data) {
1876         // there miiight be an easier way to do this :)
1877         // if this is changed, make sure the $defaults array above is modified so that this
1878         // function processes it correctly
1880         $keys = array();
1881         $values = array();
1883         foreach ($data as $key => $value) {
1884             if (substr($key,0,1) == 'k') {
1885                 $keys[substr($key,1)] = $value;
1886             } elseif (substr($key,0,1) == 'v') {
1887                 $values[substr($key,1)] = $value;
1888             }
1889         }
1891         $result = '';
1892         for ($i = 0; $i < count($keys); $i++) {
1893             if (($keys[$i] !== '') && ($values[$i] !== '')) {
1894                 $result .= clean_param($keys[$i],PARAM_NOTAGS) . ':' . clean_param($values[$i], PARAM_NOTAGS) . ';';
1895             }
1896         }
1898         $result = substr($result, 0, -1); // trim the last semicolon
1900         return (set_config($this->name, $result) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
1901     }
1903     function output_html() {
1905         if ($this->get_setting() === NULL) {
1906             $currentsetting = $this->defaultsetting;
1907         } else {
1908             $currentsetting = $this->get_setting();
1909         }
1911         $return = '<div class="form-group">';
1912         for ($i = 0; $i < count($currentsetting) / 2; $i++) {
1913             $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="' . $currentsetting['k' . $i] . '" />';
1914             $return .= '&nbsp;&nbsp;';
1915             $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="' . $currentsetting['v' . $i] . '" /><br />';
1916         }
1917         $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . $i . ']" value="" />';
1918         $return .= '&nbsp;&nbsp;';
1919         $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . $i . ']" value="" /><br />';
1920         $return .= '<input type="text" class="form-text" name="s_editorfontlist[k' . ($i + 1) . ']" value="" />';
1921         $return .= '&nbsp;&nbsp;';
1922         $return .= '<input type="text" class="form-text" name="s_editorfontlist[v' . ($i + 1) . ']" value="" />';
1923         $return .= '</div>';
1925         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
1926     }
1930 class admin_setting_special_editordictionary extends admin_setting_configselect {
1932     function admin_setting_special_editordictionary() {
1933         $name = 'editordictionary';
1934         $visiblename = get_string('editordictionary','admin');
1935         $description = get_string('configeditordictionary', 'admin');
1936         $choices = $this->editor_get_dictionaries();
1937         if (! is_array($choices)) {
1938             $choices = array('');
1939         }
1941         parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
1942     }
1944     // function borrowed from the old moodle/admin/editor.php, slightly modified
1945     function editor_get_dictionaries () {
1946     /// Get all installed dictionaries in the system
1948         global $CFG;
1950 //        error_reporting(E_ALL); // for debug, final version shouldn't have this...
1951         clearstatcache();
1953         // If aspellpath isn't set don't even bother ;-)
1954         if (empty($CFG->aspellpath)) {
1955             return 'Empty aspell path!';
1956         }
1958         // Do we have access to popen function?
1959         if (!function_exists('popen')) {
1960             return 'Popen function disabled!';
1961         }
1963         $cmd          = $CFG->aspellpath;
1964         $output       = '';
1965         $dictionaries = array();
1966         $dicts        = array();
1968         if(!($handle = @popen(escapeshellarg($cmd) .' dump dicts', 'r'))) {
1969             return 'Couldn\'t create handle!';
1970         }
1972         while(!feof($handle)) {
1973             $output .= fread($handle, 1024);
1974         }
1975         @pclose($handle);
1977         $dictionaries = explode(chr(10), $output);
1979         // Get rid of possible empty values
1980         if (is_array($dictionaries)) {
1982             $cnt = count($dictionaries);
1984             for ($i = 0; $i < $cnt; $i++) {
1985                 if (!empty($dictionaries[$i])) {
1986                     $dicts[$dictionaries[$i]] = $dictionaries[$i];
1987                 }
1988             }
1989         }
1991         if (count($dicts) >= 1) {
1992             return $dicts;
1993         }
1995         return 'Error! Check your aspell installation!';
1996     }
2003 class admin_setting_special_editorhidebuttons extends admin_setting {
2005     var $name;
2006     var $visiblename;
2007     var $description;
2008     var $items;
2010     function admin_setting_special_editorhidebuttons() {
2011         $this->name = 'editorhidebuttons';
2012         $this->visiblename = get_string('editorhidebuttons', 'admin');
2013         $this->description = get_string('confeditorhidebuttons', 'admin');
2014         $this->defaultsetting = array();
2015         // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
2016         $this->items = array('fontname' => '',
2017                          'fontsize' => '',
2018                          'formatblock' => '',
2019                          'bold' => 'ed_format_bold.gif',
2020                          'italic' => 'ed_format_italic.gif',
2021                          'underline' => 'ed_format_underline.gif',
2022                          'strikethrough' => 'ed_format_strike.gif',
2023                          'subscript' => 'ed_format_sub.gif',
2024                          'superscript' => 'ed_format_sup.gif',
2025                          'copy' => 'ed_copy.gif',
2026                          'cut' => 'ed_cut.gif',
2027                          'paste' => 'ed_paste.gif',
2028                          'clean' => 'ed_wordclean.gif',
2029                          'undo' => 'ed_undo.gif',
2030                          'redo' => 'ed_redo.gif',
2031                          'justifyleft' => 'ed_align_left.gif',
2032                          'justifycenter' => 'ed_align_center.gif',
2033                          'justifyright' => 'ed_align_right.gif',
2034                          'justifyfull' => 'ed_align_justify.gif',
2035                          'lefttoright' => 'ed_left_to_right.gif',
2036                          'righttoleft' => 'ed_right_to_left.gif',
2037                          'insertorderedlist' => 'ed_list_num.gif',
2038                          'insertunorderedlist' => 'ed_list_bullet.gif',
2039                          'outdent' => 'ed_indent_less.gif',
2040                          'indent' => 'ed_indent_more.gif',
2041                          'forecolor' => 'ed_color_fg.gif',
2042                          'hilitecolor' => 'ed_color_bg.gif',
2043                          'inserthorizontalrule' => 'ed_hr.gif',
2044                          'createanchor' => 'ed_anchor.gif',
2045                          'createlink' => 'ed_link.gif',
2046                          'unlink' => 'ed_unlink.gif',
2047                          'insertimage' => 'ed_image.gif',
2048                          'inserttable' => 'insert_table.gif',
2049                          'insertsmile' => 'em.icon.smile.gif',
2050                          'insertchar' => 'icon_ins_char.gif',
2051                          'spellcheck' => 'spell-check.gif',
2052                          'htmlmode' => 'ed_html.gif',
2053                          'popupeditor' => 'fullscreen_maximize.gif',
2054                          'search_replace' => 'ed_replace.gif');
2055     }
2057     function get_setting() {
2058         global $CFG;
2059         return (isset($CFG->{$this->name}) ? explode(' ', $CFG->{$this->name}) : NULL);
2060     }
2062     function write_setting($data) {
2063         $result = array();
2064         if (empty($data)) { $data = array(); }
2065         foreach ($data as $key => $value) {
2066             if (!in_array($key, array_keys($this->items))) {
2067                 return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2068             }
2069             if ($value == '1') {
2070                 $result[] = $key;
2071             }
2072         }
2073         return (set_config($this->name, implode(' ',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2074     }
2076     function output_html() {
2078         global $CFG;
2080         // checkboxes with input name="$this->name[$key]" value="1"
2081         // we do 15 fields per column
2083         if ($this->get_setting() === NULL) {
2084             $currentsetting = $this->defaultsetting;
2085         } else {
2086             $currentsetting = $this->get_setting();
2087         }
2089         $return = '<div class="form-group">';
2090         $return .= '<table><tr><td valign="top" align="right">';
2092         $count = 0;
2094         foreach($this->items as $key => $value) {
2095             if ($count % 15 == 0 and $count != 0) {
2096                 $return .= '</td><td valign="top" align="right">';
2097             }
2099             $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;';
2100             $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;';
2101             $count++;
2102             if ($count % 15 != 0) {
2103                 $return .= '<br /><br />';
2104             }
2105         }
2107         $return .= '</td></tr>';
2108         $return .= '</table>';
2109         $return .= '</div>';
2111         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2112     }
2116 class admin_setting_backupselect extends admin_setting_configselect {
2118     function admin_setting_backupselect($name, $visiblename, $description, $default, $choices) {
2119         parent::admin_setting_configselect($name, $visiblename, $description, $default, $choices);
2120     }
2122     function get_setting() {
2123         $backup_config =  backup_get_config();
2124         return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2125     }
2127     function write_setting($data) {
2128          // check that what we got was in the original choices
2129          if (! in_array($data, array_keys($this->choices))) {
2130              return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2131          }
2133          return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2134     }
2138 class admin_setting_special_backupsaveto extends admin_setting_configtext {
2140     function admin_setting_special_backupsaveto() {
2141         $name = 'backup_sche_destination';
2142         $visiblename = get_string('saveto');
2143         $description = get_string('backupsavetohelp');
2144         parent::admin_setting_configtext($name, $visiblename, $description, '', PARAM_PATH);
2145     }
2147     function get_setting() {
2148         $backup_config =  backup_get_config();
2149         return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2150     }
2152     function write_setting($data) {
2153         $data = clean_param($data, PARAM_PATH);
2154         if (!empty($data) and (substr($data,-1) == '/' or substr($data,-1) == '\\')) {
2155             return get_string('pathslasherror') . '<br />';
2156         } else if (!empty($data) and !is_dir($data)) {
2157             return get_string('pathnotexists') . '<br />';
2158         }
2159         return (backup_set_config($this->name, $data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2160     }
2164 class admin_setting_backupcheckbox extends admin_setting_configcheckbox {
2166     function admin_setting_backupcheckbox($name, $visiblename, $description, $default) {
2167         parent::admin_setting_configcheckbox($name, $visiblename, $description, $default);
2168     }
2170     function write_setting($data) {
2171         if ($data == '1') {
2172             return (backup_set_config($this->name, 1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2173         } else {
2174             return (backup_set_config($this->name, 0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2175         }
2176     }
2178     function get_setting() {
2179         $backup_config =  backup_get_config();
2180         return (isset($backup_config->{$this->name}) ? $backup_config->{$this->name} : NULL);
2181     }
2185 class admin_setting_special_backuptime extends admin_setting_configtime {
2187     function admin_setting_special_backuptime() {
2188         $name = 'backup_sche_hour';
2189         $name2 = 'backup_sche_minute';
2190         $visiblename = get_string('executeat');
2191         $description = get_string('backupexecuteathelp');
2192         $default = array('h' => 0, 'm' => 0);
2193         parent::admin_setting_configtime($name, $name2, $visiblename, $description, $default);
2194     }
2196     function get_setting() {
2197         $backup_config =  backup_get_config();
2198         return (isset($backup_config->{$this->name}) && isset($backup_config->{$this->name}) ? array('h'=>$backup_config->{$this->name}, 'm'=>$backup_config->{$this->name2}) : NULL);
2199     }
2201     function write_setting($data) {
2202          // check that what we got was in the original choices
2203          if (!(in_array($data['h'], array_keys($this->choices)) && in_array($data['m'], array_keys($this->choices2)))) {
2204              return get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2205          }
2207          return (backup_set_config($this->name, $data['h']) && backup_set_config($this->name2, $data['m']) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2208     }
2212 class admin_setting_special_backupdays extends admin_setting {
2214     function admin_setting_special_backupdays() {
2215         $name = 'backup_sche_weekdays';
2216         $visiblename = get_string('schedule');
2217         $description = get_string('backupschedulehelp');
2218         $default = array('u' => 0, 'm' => 0, 't' => 0, 'w' => 0, 'r' => 0, 'f' => 0, 's' => 0);
2219         parent::admin_setting($name, $visiblename, $description, $default);
2220     }
2222     function get_setting() {
2223         $backup_config =  backup_get_config();
2224         if (isset($backup_config->{$this->name})) {
2225             $currentsetting = $backup_config->{$this->name};
2226             return array('u' => substr($currentsetting, 0, 1),
2227                          'm' => substr($currentsetting, 1, 1),
2228                          't' => substr($currentsetting, 2, 1),
2229                          'w' => substr($currentsetting, 3, 1),
2230                          'r' => substr($currentsetting, 4, 1),
2231                          'f' => substr($currentsetting, 5, 1),
2232                          's' => substr($currentsetting, 6, 1));
2233         } else {
2234             return NULL;
2235         }
2236     }
2238     function output_html() {
2240         if ($this->get_setting() === NULL) {
2241             $currentsetting = $this->defaultsetting;
2242         } else {
2243             $currentsetting = $this->get_setting();
2244         }
2246         // rewrite for simplicity
2247         $currentsetting = $currentsetting['u'] . $currentsetting['m'] . $currentsetting['t'] . $currentsetting['w'] .
2248                           $currentsetting['r'] . $currentsetting['f'] . $currentsetting['s'];
2250         $return = '<table><tr><td><div align="center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2251         get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2252         get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2253         get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2254         '<td><div 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>' .
2255         '<td><div 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>' .
2256         '<td><div 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>' .
2257         '<td><div 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>' .
2258         '<td><div 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>' .
2259         '<td><div 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>' .
2260         '<td><div 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>' .
2261         '</tr></table>';
2263         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2265     }
2267     // 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
2268     // admin_settingpage (note that admin_settingpage only calls write_setting with the data that matches $this->name... so if we have multiple form fields,
2269     // they MUST go into an array named $this->name, or else we won't receive them here
2270     function write_setting($data) {
2271         $week = 'umtwrfs';
2272         $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
2273         if (!empty($data)) {
2274             foreach($data as $key => $value) {
2275               if ($value == '1') {
2276                   $result[strpos($week, $key)] = 1;
2277                 }
2278             }
2279         }
2280         return (backup_set_config($this->name, implode('',$result)) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2281     }
2284 class admin_setting_special_debug extends admin_setting_configselect {
2286     function admin_setting_special_debug() {
2287         $name = 'debug';
2288         $visiblename = get_string('debug', 'admin');
2289         $description = get_string('configdebug', 'admin');
2290         $choices = array( DEBUG_NONE      => get_string('debugnone', 'admin'),
2291                           DEBUG_MINIMAL   => get_string('debugminimal', 'admin'),
2292                           DEBUG_NORMAL    => get_string('debugnormal', 'admin'),
2293                           DEBUG_ALL       => get_string('debugall', 'admin'),
2294                           DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin')
2295                         );
2296         parent::admin_setting_configselect($name, $visiblename, $description, '', $choices);
2297     }
2299     function get_setting() {
2300         global $CFG;
2301         if (isset($CFG->debug)) {
2302             return $CFG->debug;
2303         } else {
2304             return NULL;
2305         }
2306     }
2308     function write_setting($data) {
2309         return (set_config($this->name,$data) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2310     }
2315 class admin_setting_special_calendar_weekend extends admin_setting {
2317     function admin_setting_special_calendar_weekend() {
2318         $name = 'calendar_weekend';
2319         $visiblename = get_string('calendar_weekend', 'admin');
2320         $description = get_string('helpweekenddays', 'admin');
2321         $default = array('u' => 1, 'm' => 0, 't' => 0, 'w' => 0, 'r' => 0, 'f' => 0, 's' => 1);
2322         parent::admin_setting($name, $visiblename, $description, $default);
2323     }
2325     function get_setting() {
2326         global $CFG;
2327         if (isset($CFG->{$this->name})) {
2328             $currentsetting = decbin($CFG->{$this->name});
2329             $currentsetting = str_pad($currentsetting, 7, '0', STR_PAD_LEFT);
2330             return array('u' => substr($currentsetting, 0, 1),
2331                          'm' => substr($currentsetting, 1, 1),
2332                          't' => substr($currentsetting, 2, 1),
2333                          'w' => substr($currentsetting, 3, 1),
2334                          'r' => substr($currentsetting, 4, 1),
2335                          'f' => substr($currentsetting, 5, 1),
2336                          's' => substr($currentsetting, 6, 1));
2337         } else {
2338             return NULL;
2339         }
2340     }
2342     function write_setting($data) {
2343         $week = 'umtwrfs';
2344         $result = array(0 => 0, 1 => 0, 2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
2345         if (!empty($data)) {
2346             foreach($data as $key => $value) {
2347                 if ($value == '1') {
2348                     $result[strpos($week, $key)] = 1;
2349                 }
2350             }
2351         }
2352         return (set_config($this->name, bindec(implode('',$result))) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2353     }
2355     function output_html() {
2357         if ($this->get_setting() === NULL) {
2358             $currentsetting = $this->defaultsetting;
2359         } else {
2360             $currentsetting = $this->get_setting();
2361         }
2363         // rewrite for simplicity
2364         $currentsetting = $currentsetting['u'] . $currentsetting['m'] . $currentsetting['t'] . $currentsetting['w'] .
2365                           $currentsetting['r'] . $currentsetting['f'] . $currentsetting['s'];
2367         $return = '<table><tr><td><div align="center">&nbsp;&nbsp;' . get_string('sunday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2368         get_string('monday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('tuesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2369         get_string('wednesday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('thursday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' .
2370         get_string('friday', 'calendar') . '&nbsp;&nbsp;</div></td><td><div align="center">&nbsp;&nbsp;' . get_string('saturday', 'calendar') . '&nbsp;&nbsp;</div></td></tr><tr>' .
2371         '<td><div 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>' .
2372         '<td><div 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>' .
2373         '<td><div 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>' .
2374         '<td><div 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>' .
2375         '<td><div 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>' .
2376         '<td><div 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>' .
2377         '<td><div 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>' .
2378         '</tr></table>';
2380         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2382     }
2386 /*
2387  * this is used in config->appearance->gradeconfig
2388  */
2389 class admin_setting_special_gradebookroles extends admin_setting {
2391     function admin_setting_special_gradebookroles() {
2392         $name = 'gradebookroles';
2393         $visiblename = get_string('gradebookroles', 'admin');
2394         $description = get_string('configgradebookroles', 'admin');
2395         $default = array(5=>'1');    // The student role in a default install
2396         parent::admin_setting($name, $visiblename, $description, $default);
2397     }
2399     function get_setting() {
2400         global $CFG;
2401         if (!empty($CFG->{$this->name})) {
2402             $result = explode(',', $CFG->{$this->name});
2403             foreach ($result as $roleid) {
2404                 $array[$roleid] = 1;  
2405             }
2406             return $array;
2407         } else {
2408             return null;
2409         }
2410     }
2412     function write_setting($data) {
2413         if (!empty($data)) {
2414             $str = '';
2415             foreach ($data as $key => $value) {
2416                 if ($value) {
2417                     $str .= $key.',';
2418                 }
2419             }
2420             return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2421         } else {
2422             return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2423         }
2424     }
2426     function output_html() {
2428         if ($this->get_setting() === NULL) {
2429             $currentsetting = $this->defaultsetting;
2430         } else {
2431             $currentsetting = $this->get_setting();
2432         }
2433         // from to process which roles to display
2434         if ($roles = get_records('role')) {
2435             $return = '<div class="form-group">';
2436             $first = true;
2437             foreach ($roles as $roleid=>$role) {
2438                 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
2439                     $checked = ' checked="checked"';
2440                 } else {
2441                     $checked = '';
2442                 }
2443                 if ($first) {
2444                     $first = false;
2445                 } else {
2446                     $return .= '<br />';
2447                 }
2448                 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$roleid.']" value="1"'.$checked.' />&nbsp;'.$role->name;
2449             }
2450             $return .= '</div>';
2451         }
2453         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2455     }
2459 /*
2460  * this is used in config->appearance->coursemanager
2461  * (which roles to show on course decription page)
2462  */
2463 class admin_setting_special_coursemanager extends admin_setting {
2465     function admin_setting_special_coursemanager() {
2466         $name = 'coursemanager';
2467         $visiblename = get_string('coursemanager', 'admin');
2468         $description = get_string('configcoursemanager', 'admin');
2469         $default = array(3=>'1');    // The teahcer role in a default install
2470         parent::admin_setting($name, $visiblename, $description, $default);
2471     }
2473     function get_setting() {
2475         global $CFG;
2476         if (!empty($CFG->{$this->name})) {
2477             $result = explode(',', $CFG->{$this->name});
2478             foreach ($result as $roleid) {
2479                 $array[$roleid] = 1;  
2480             }
2481             return $array;
2482         } else {
2483             return null;
2484         }
2485     }
2487     function write_setting($data) {
2489         if (!empty($data)) {
2490             $str = '';
2491             foreach ($data as $key => $value) {
2492                 if ($value) {
2493                     $str .= $key.',';
2494                 }
2495             }
2496             return set_config($this->name, rtrim($str, ","))?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2497         } else {
2498             return set_config($this->name, '')?'':get_string('errorsetting', 'admin') . $this->visiblename . '<br />';
2499         }
2500     }
2502     function output_html() {
2504         if ($this->get_setting() === NULL) {
2505             $currentsetting = $this->defaultsetting;
2506         } else {
2507             $currentsetting = $this->get_setting();
2508         }
2509         // from to process which roles to display
2510         if ($roles = get_records('role')) {
2511             $return = '<div class="form-group">';
2512             $first = true;
2513             foreach ($roles as $roleid=>$role) {
2514                 if (is_array($currentsetting) && in_array($roleid, array_keys($currentsetting))) {
2515                     $checked = 'checked="checked"';
2516                 } else {
2517                     $checked = '';
2518                 }
2519                 if ($first) {
2520                     $first = false;
2521                 } else {
2522                     $return .= '<br />';
2523                 }
2524                 $return .= '<input type="checkbox" name="s_'.$this->name.'['.$roleid.']" value="1" '.$checked.' />&nbsp;'.$role->name;
2525             }
2526             $return .= '</div>';
2527         }
2528         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2529     }
2532 class admin_setting_special_perfdebug extends admin_setting_configcheckbox {
2534     function admin_setting_special_perfdebug() {
2535         $name = 'perfdebug';
2536         $visiblename = get_string('perfdebug', 'admin');
2537         $description = get_string('configperfdebug', 'admin');
2538         parent::admin_setting_configcheckbox($name, $visiblename, $description, '');
2539     }
2541     function write_setting($data) {
2543         if ($data == '1') {
2544             return (set_config($this->name,15) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2545         } else {
2546             return (set_config($this->name,7) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2547         }
2548     }
2550     function output_html() {
2552         if ($this->get_setting() === NULL) {
2553             $currentsetting = $this->defaultsetting;
2554         } else {
2555             $currentsetting = $this->get_setting();
2556         }
2558         $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 15 ? 'checked="checked"' : '') . ' />';
2559         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2560     }
2564 class admin_setting_special_debugdisplay extends admin_setting_configcheckbox {
2566     function admin_setting_special_debugdisplay() {
2567         $name = 'debugdisplay';
2568         $visiblename = get_string('debugdisplay', 'admin');
2569         $description = get_string('configdebugdisplay', 'admin');
2570         parent::admin_setting_configcheckbox($name, $visiblename, $description, '');
2571     }
2573     function write_setting($data) {
2575         if ($data == '1') {
2576             return (set_config($this->name,1) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2577         } else {
2578             return (set_config($this->name,0) ? '' : get_string('errorsetting', 'admin') . $this->visiblename . '<br />');
2579         }
2580     }
2582     function output_html() {
2584         if ($this->get_setting() === NULL) {
2585             $currentsetting = ini_get('display_error');
2586         } else {
2587             $currentsetting = $this->get_setting();
2588         }
2590         $return = '<input type="checkbox" class="form-checkbox" id="id_s_'.$this->name.'" name="s_'. $this->name .'" value="1" ' . ($currentsetting == 1 ? 'checked="checked"' : '') . ' />';
2591         return format_admin_setting($this->name, $this->visiblename, $return, $this->description);
2592     }
2597 // Code for a function that helps externalpages print proper headers and footers
2598 // N.B.: THIS FUNCTION HANDLES AUTHENTICATION
2599 function admin_externalpage_setup($section, $adminroot) {
2601     global $CFG, $PAGE, $USER;
2603     require_once($CFG->libdir . '/blocklib.php');
2604     require_once($CFG->dirroot . '/'.$CFG->admin.'/pagelib.php');
2606     page_map_class(PAGE_ADMIN, 'page_admin');
2608     $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
2610     $PAGE->init_extra($section); // hack alert!
2612     $root = $adminroot->locate($PAGE->section);
2614     if ($site = get_site()) {
2615         require_login();
2616     } else {
2617         redirect($CFG->wwwroot . '/'.$CFG->admin.'/index.php');
2618         die;
2619     }
2621     if (!is_a($root, 'admin_externalpage')) {
2622         error(get_string('sectionerror','admin'));
2623         die;
2624     }
2626     // this eliminates our need to authenticate on the actual pages
2627     if (!($root->check_access())) {
2628         error(get_string('accessdenied', 'admin'));
2629         die;
2630     }
2632     $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
2634     if (!isset($USER->adminediting)) {
2635         $USER->adminediting = false;
2636     }
2638     if ($PAGE->user_allowed_editing()) {
2639         if ($adminediting == 1) {
2640             $USER->adminediting = true;
2641         } elseif ($adminediting == 0) {
2642             $USER->adminediting = false;
2643         }
2644     }
2648 function admin_externalpage_print_header($adminroot) {
2650     global $CFG, $PAGE, $SITE;
2652     if (!empty($SITE->fullname)) {
2653         $pageblocks = blocks_setup($PAGE);
2655         $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
2656                                                blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
2657                                                BLOCK_L_MAX_WIDTH);
2658         $PAGE->print_header();
2659         echo '<table id="layout-table" summary=""><tr>';
2660         echo '<td style="width: ' . $preferred_width_left . 'px;" id="left-column">';
2661         blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
2662         echo '</td>';
2663         echo '<td id="middle-column">';
2664     } else {
2665         print_header();
2666     }
2669 function admin_externalpage_print_footer($adminroot) {
2671     global $CFG, $PAGE, $SITE;
2673     if (!empty($SITE->fullname)) {
2674         $pageblocks = blocks_setup($PAGE);
2675         $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
2676                                                 blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
2677                                                 BLOCK_R_MAX_WIDTH);
2678         echo '</td>';
2679         echo '<td style="width: ' . $preferred_width_right . 'px;" id="right-column">';
2680         blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
2681         echo '</td></tr></table>';
2682     }
2683     print_footer();
2686 function admin_get_root() {
2687     global $CFG;
2689     static $ADMIN;
2691     if (!isset($ADMIN)) {
2692         // start the admin tree!
2693         $ADMIN = new admin_category('root', get_string("administration"));
2694         // we process this file first to get categories up and running
2695         include($CFG->dirroot . '/'.$CFG->admin.'/settings/top.php');
2697         // now we process all other files in admin/settings to build the
2698         // admin tree
2699         foreach (glob($CFG->dirroot . '/'.$CFG->admin.'/settings/*.php') as $file) {
2700             if ($file != $CFG->dirroot . '/'.$CFG->admin.'/settings/top.php') {
2701                 include_once($file);
2702             }
2703         }
2704     }
2706     return $ADMIN;
2709 /// settings utiliti functions
2711 // n.b. this function unconditionally applies default settings
2712 function apply_default_settings(&$node) {
2714     global $CFG;
2716     if (is_a($node, 'admin_category')) {
2717         $entries = array_keys($node->children);
2718         foreach ($entries as $entry) {
2719             apply_default_settings($node->children[$entry]);
2720         }
2721         return;
2722     }
2724     if (is_a($node, 'admin_settingpage')) {
2725         foreach ($node->settings as $setting) {
2726                 $CFG->{$setting->name} = $setting->defaultsetting;
2727                 $setting->write_setting($setting->defaultsetting);
2728             unset($setting); // needed to prevent odd (imho) reference behaviour
2729                              // see http://www.php.net/manual/en/language.references.whatdo.php#AEN6399
2730         }
2731         return;
2732     }
2734     return;
2738 // n.b. this function unconditionally applies default settings
2739 function apply_default_exception_settings($defaults) {
2741     global $CFG;
2743     foreach($defaults as $key => $value) {
2744             $CFG->$key = $value;
2745             set_config($key, $value);
2746     }
2750 function format_admin_setting($name, $title='', $form='', $description='') {
2751     return "\n".
2752            '<div class="form-item" id="admin-'.$name.'">'."\n".
2753            '<label for="id_s_'.$name.'">'.$title."\n".
2754            '   <span class="form-shortname">'.$name.'</span>'."\n".
2755            '</label>'."\n".
2756            $form."\n".
2757            '<div class="description">'.$description.'</div>'."\n".
2758            '</div>'.
2759            "\n\n";
2762 /* 
2763  * Try to upgrade the given language pack (or current language)
2764  * If it doesn't work, fail silently and return false
2765  */
2766 function upgrade_language_pack($lang='') {
2767     global $CFG;
2769     if (empty($lang)) {
2770         $lang = current_language();
2771     }
2773     if ($lang == 'en_utf8') {
2774         return true;  // Nothing to do
2775     }
2777     notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
2779     @mkdir ($CFG->dataroot.'/temp/');    //make it in case it's a fresh install, it might not be there
2780     @mkdir ($CFG->dataroot.'/lang/');
2782     require_once($CFG->libdir.'/componentlib.class.php');
2784     if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
2785         $status = $cd->install(); //returns ERROR | UPTODATE | INSTALLED
2787         if ($status == INSTALLED) {
2788             debugging('Downloading successful: '.$lang);
2789             @unlink($CFG->dataroot.'/cache/languages');
2790             return true;
2791         }
2792     }
2794     return false;
2797 ?>