PageRenderTime 109ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/adminlib.php

https://bitbucket.org/ceu/moodle_demo
PHP | 5050 lines | 3499 code | 659 blank | 892 comment | 618 complexity | 0f1381dcda92bc8559e7775be9e04e68 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * adminlib.php - Contains functions that only administrators will ever need to use
  4. *
  5. * @author Martin Dougiamas and many others
  6. * @version $Id: adminlib.php,v 1.153.2.77 2011/08/26 16:22:55 moodlerobot Exp $
  7. * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  8. * @package moodlecore
  9. */
  10. define('INSECURE_DATAROOT_WARNING', 1);
  11. define('INSECURE_DATAROOT_ERROR', 2);
  12. function upgrade_main_savepoint($result, $version) {
  13. global $CFG;
  14. if ($result) {
  15. if ($CFG->version >= $version) {
  16. // something really wrong is going on in main upgrade script
  17. error("Upgrade savepoint: Can not upgrade main version from $CFG->version to $version.");
  18. }
  19. set_config('version', $version);
  20. } else {
  21. notify ("Upgrade savepoint: Error during main upgrade to version $version");
  22. }
  23. }
  24. function upgrade_mod_savepoint($result, $version, $type) {
  25. //TODO
  26. }
  27. function upgrade_plugin_savepoint($result, $version, $type, $dir) {
  28. //TODO
  29. }
  30. function upgrade_backup_savepoint($result, $version) {
  31. //TODO
  32. }
  33. function upgrade_blocks_savepoint($result, $version, $type) {
  34. //TODO
  35. }
  36. /**
  37. * Upgrade plugins
  38. *
  39. * @uses $db
  40. * @uses $CFG
  41. * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
  42. * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
  43. * @param string $return The url to prompt the user to continue to
  44. */
  45. function upgrade_plugins($type, $dir, $return) {
  46. global $CFG, $db;
  47. /// Let's know if the header has been printed, so the funcion is being called embedded in an outer page
  48. $embedded = defined('HEADER_PRINTED');
  49. $plugs = get_list_of_plugins($dir);
  50. $updated_plugins = false;
  51. $strpluginsetup = get_string('pluginsetup');
  52. foreach ($plugs as $plug) {
  53. $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
  54. unset($plugin);
  55. if (is_readable($fullplug .'/version.php')) {
  56. include_once($fullplug .'/version.php'); // defines $plugin with version etc
  57. } else {
  58. continue; // Nothing to do.
  59. }
  60. $oldupgrade = false;
  61. $newupgrade = false;
  62. if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) {
  63. include_once($fullplug . '/db/'. $CFG->dbtype . '.php'); // defines old upgrading function
  64. $oldupgrade = true;
  65. }
  66. if (is_readable($fullplug . '/db/upgrade.php')) {
  67. include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function
  68. $newupgrade = true;
  69. }
  70. if (!isset($plugin)) {
  71. continue;
  72. }
  73. if (!empty($plugin->requires)) {
  74. if ($plugin->requires > $CFG->version) {
  75. $info = new object();
  76. $info->pluginname = $plug;
  77. $info->pluginversion = $plugin->version;
  78. $info->currentmoodle = $CFG->version;
  79. $info->requiremoodle = $plugin->requires;
  80. if (!$updated_plugins && !$embedded) {
  81. print_header($strpluginsetup, $strpluginsetup,
  82. build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
  83. upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
  84. }
  85. upgrade_log_start();
  86. notify(get_string('pluginrequirementsnotmet', 'error', $info));
  87. $updated_plugins = true;
  88. continue;
  89. }
  90. }
  91. $plugin->name = $plug; // The name MUST match the directory
  92. $pluginversion = $type.'_'.$plug.'_version';
  93. if (!isset($CFG->$pluginversion)) {
  94. set_config($pluginversion, 0);
  95. }
  96. if ($CFG->$pluginversion == $plugin->version) {
  97. // do nothing
  98. } else if ($CFG->$pluginversion < $plugin->version) {
  99. if (!$updated_plugins && !$embedded) {
  100. print_header($strpluginsetup, $strpluginsetup,
  101. build_navigation(array(array('name' => $strpluginsetup, 'link' => null, 'type' => 'misc'))), '',
  102. upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
  103. }
  104. $updated_plugins = true;
  105. upgrade_log_start();
  106. print_heading($dir.'/'. $plugin->name .' plugin needs upgrading');
  107. $db->debug = true;
  108. @set_time_limit(0); // To allow slow databases to complete the long SQL
  109. if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
  110. /// Both old .sql files and new install.xml are supported
  111. /// but we priorize install.xml (XMLDB) if present
  112. $status = false;
  113. if (file_exists($fullplug . '/db/install.xml')) {
  114. $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method
  115. } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
  116. $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method
  117. } else {
  118. $status = true;
  119. }
  120. $db->debug = false;
  121. /// Continue with the instalation, roles and other stuff
  122. if ($status) {
  123. /// OK so far, now update the plugins record
  124. set_config($pluginversion, $plugin->version);
  125. /// Install capabilities
  126. if (!update_capabilities($type.'/'.$plug)) {
  127. error('Could not set up the capabilities for '.$plugin->name.'!');
  128. }
  129. /// Install events
  130. events_update_definition($type.'/'.$plug);
  131. /// Run local install function if there is one
  132. if (is_readable($fullplug .'/lib.php')) {
  133. include_once($fullplug .'/lib.php');
  134. $installfunction = $plugin->name.'_install';
  135. if (function_exists($installfunction)) {
  136. if (! $installfunction() ) {
  137. notify('Encountered a problem running install function for '.$plugin->name.'!');
  138. }
  139. }
  140. }
  141. notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
  142. } else {
  143. notify('Installing '. $plugin->name .' FAILED!');
  144. }
  145. } else { // Upgrade existing install
  146. /// Run de old and new upgrade functions for the module
  147. $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade';
  148. $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade';
  149. /// First, the old function if exists
  150. $oldupgrade_status = true;
  151. if ($oldupgrade && function_exists($oldupgrade_function)) {
  152. $db->debug = true;
  153. $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion);
  154. } else if ($oldupgrade) {
  155. notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
  156. $fullplug . '/db/' . $CFG->dbtype . '.php');
  157. }
  158. /// Then, the new function if exists and the old one was ok
  159. $newupgrade_status = true;
  160. if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
  161. $db->debug = true;
  162. $newupgrade_status = $newupgrade_function($CFG->$pluginversion);
  163. } else if ($newupgrade) {
  164. notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
  165. $fullplug . '/db/upgrade.php');
  166. }
  167. $db->debug=false;
  168. /// Now analyze upgrade results
  169. if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
  170. // OK so far, now update the plugins record
  171. set_config($pluginversion, $plugin->version);
  172. if (!update_capabilities($type.'/'.$plug)) {
  173. error('Could not update '.$plugin->name.' capabilities!');
  174. }
  175. events_update_definition($type.'/'.$plug);
  176. notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
  177. } else {
  178. notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
  179. }
  180. }
  181. echo '<hr />';
  182. } else {
  183. upgrade_log_start();
  184. error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
  185. }
  186. }
  187. upgrade_log_finish();
  188. if ($updated_plugins && !$embedded) {
  189. print_continue($return);
  190. print_footer('none');
  191. die;
  192. }
  193. }
  194. /**
  195. * Find and check all modules and load them up or upgrade them if necessary
  196. *
  197. * @uses $db
  198. * @uses $CFG
  199. * @param string $return The url to prompt the user to continue to
  200. * @todo Finish documenting this function
  201. */
  202. function upgrade_activity_modules($return) {
  203. global $CFG, $db;
  204. if (!$mods = get_list_of_plugins('mod') ) {
  205. error('No modules installed!');
  206. }
  207. $updated_modules = false;
  208. $strmodulesetup = get_string('modulesetup');
  209. foreach ($mods as $mod) {
  210. if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
  211. continue;
  212. }
  213. $fullmod = $CFG->dirroot .'/mod/'. $mod;
  214. unset($module);
  215. if ( is_readable($fullmod .'/version.php')) {
  216. include_once($fullmod .'/version.php'); // defines $module with version etc
  217. } else {
  218. notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
  219. continue;
  220. }
  221. $oldupgrade = false;
  222. $newupgrade = false;
  223. if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) {
  224. include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function
  225. $oldupgrade = true;
  226. }
  227. if ( is_readable($fullmod . '/db/upgrade.php')) {
  228. include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function
  229. $newupgrade = true;
  230. }
  231. if (!isset($module)) {
  232. continue;
  233. }
  234. if (!empty($module->requires)) {
  235. if ($module->requires > $CFG->version) {
  236. $info = new object();
  237. $info->modulename = $mod;
  238. $info->moduleversion = $module->version;
  239. $info->currentmoodle = $CFG->version;
  240. $info->requiremoodle = $module->requires;
  241. if (!$updated_modules) {
  242. print_header($strmodulesetup, $strmodulesetup,
  243. build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
  244. upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
  245. }
  246. upgrade_log_start();
  247. notify(get_string('modulerequirementsnotmet', 'error', $info));
  248. $updated_modules = true;
  249. continue;
  250. }
  251. }
  252. $module->name = $mod; // The name MUST match the directory
  253. include_once($fullmod.'/lib.php'); // defines upgrading and/or installing functions
  254. if ($currmodule = get_record('modules', 'name', $module->name)) {
  255. if ($currmodule->version == $module->version) {
  256. // do nothing
  257. } else if ($currmodule->version < $module->version) {
  258. /// If versions say that we need to upgrade but no upgrade files are available, notify and continue
  259. if (!$oldupgrade && !$newupgrade) {
  260. notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' .
  261. $fullmod . '/db/upgrade.php were not readable');
  262. continue;
  263. }
  264. if (!$updated_modules) {
  265. print_header($strmodulesetup, $strmodulesetup,
  266. build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
  267. upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
  268. }
  269. upgrade_log_start();
  270. print_heading($module->name .' module needs upgrading');
  271. /// Run de old and new upgrade functions for the module
  272. $oldupgrade_function = $module->name . '_upgrade';
  273. $newupgrade_function = 'xmldb_' . $module->name . '_upgrade';
  274. /// First, the old function if exists
  275. $oldupgrade_status = true;
  276. if ($oldupgrade && function_exists($oldupgrade_function)) {
  277. $db->debug = true;
  278. $oldupgrade_status = $oldupgrade_function($currmodule->version, $module);
  279. if (!$oldupgrade_status) {
  280. notify ('Upgrade function ' . $oldupgrade_function .
  281. ' did not complete successfully.');
  282. }
  283. } else if ($oldupgrade) {
  284. notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' .
  285. $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php');
  286. }
  287. /// Then, the new function if exists and the old one was ok
  288. $newupgrade_status = true;
  289. if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) {
  290. $db->debug = true;
  291. $newupgrade_status = $newupgrade_function($currmodule->version, $module);
  292. } else if ($newupgrade && $oldupgrade_status) {
  293. notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' .
  294. $mod . ': ' . $fullmod . '/db/upgrade.php');
  295. }
  296. $db->debug=false;
  297. /// Now analyze upgrade results
  298. if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed
  299. // OK so far, now update the modules record
  300. $module->id = $currmodule->id;
  301. if (! update_record('modules', $module)) {
  302. error('Could not update '. $module->name .' record in modules table!');
  303. }
  304. remove_dir($CFG->dataroot . '/cache', true); // flush cache
  305. notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
  306. echo '<hr />';
  307. } else {
  308. notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
  309. }
  310. /// Update the capabilities table?
  311. if (!update_capabilities('mod/'.$module->name)) {
  312. error('Could not update '.$module->name.' capabilities!');
  313. }
  314. events_update_definition('mod/'.$module->name);
  315. $updated_modules = true;
  316. } else {
  317. upgrade_log_start();
  318. error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
  319. }
  320. } else { // module not installed yet, so install it
  321. if (!$updated_modules) {
  322. print_header($strmodulesetup, $strmodulesetup,
  323. build_navigation(array(array('name' => $strmodulesetup, 'link' => null, 'type' => 'misc'))), '',
  324. upgrade_get_javascript(), false, '&nbsp;', '&nbsp;');
  325. }
  326. upgrade_log_start();
  327. print_heading($module->name);
  328. $updated_modules = true;
  329. $db->debug = true;
  330. @set_time_limit(0); // To allow slow databases to complete the long SQL
  331. /// Both old .sql files and new install.xml are supported
  332. /// but we priorize install.xml (XMLDB) if present
  333. if (file_exists($fullmod . '/db/install.xml')) {
  334. $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method
  335. } else {
  336. $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method
  337. }
  338. $db->debug = false;
  339. /// Continue with the installation, roles and other stuff
  340. if ($status) {
  341. if ($module->id = insert_record('modules', $module)) {
  342. /// Capabilities
  343. if (!update_capabilities('mod/'.$module->name)) {
  344. error('Could not set up the capabilities for '.$module->name.'!');
  345. }
  346. /// Events
  347. events_update_definition('mod/'.$module->name);
  348. /// Run local install function if there is one
  349. $installfunction = $module->name.'_install';
  350. if (function_exists($installfunction)) {
  351. if (! $installfunction() ) {
  352. notify('Encountered a problem running install function for '.$module->name.'!');
  353. }
  354. }
  355. notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
  356. echo '<hr />';
  357. } else {
  358. error($module->name .' module could not be added to the module list!');
  359. }
  360. } else {
  361. error($module->name .' tables could NOT be set up successfully!');
  362. }
  363. }
  364. /// Check submodules of this module if necessary
  365. $submoduleupgrade = $module->name.'_upgrade_submodules';
  366. if (function_exists($submoduleupgrade)) {
  367. $submoduleupgrade();
  368. }
  369. /// Run any defaults or final code that is necessary for this module
  370. if ( is_readable($fullmod .'/defaults.php')) {
  371. // Insert default values for any important configuration variables
  372. unset($defaults);
  373. include($fullmod .'/defaults.php'); // include here means execute, not library include
  374. if (!empty($defaults)) {
  375. foreach ($defaults as $name => $value) {
  376. if (!isset($CFG->$name)) {
  377. set_config($name, $value);
  378. }
  379. }
  380. }
  381. }
  382. }
  383. upgrade_log_finish(); // finish logging if started
  384. if ($updated_modules) {
  385. print_continue($return);
  386. print_footer('none');
  387. die;
  388. }
  389. }
  390. /**
  391. * Try to obtain or release the cron lock.
  392. *
  393. * @param string $name name of lock
  394. * @param int $until timestamp when this lock considered stale, null means remove lock unconditionaly
  395. * @param bool $ignorecurrent ignore current lock state, usually entend previous lock
  396. * @return bool true if lock obtained
  397. */
  398. function set_cron_lock($name, $until, $ignorecurrent=false) {
  399. if (empty($name)) {
  400. debugging("Tried to get a cron lock for a null fieldname");
  401. return false;
  402. }
  403. // remove lock by force == remove from config table
  404. if (is_null($until)) {
  405. set_config($name, null);
  406. return true;
  407. }
  408. if (!$ignorecurrent) {
  409. // read value from db - other processes might have changed it
  410. $value = get_field('config', 'value', 'name', $name);
  411. if ($value and $value > time()) {
  412. //lock active
  413. return false;
  414. }
  415. }
  416. set_config($name, $until);
  417. return true;
  418. }
  419. function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
  420. static $thisbarid;
  421. static $starttime;
  422. static $lasttime;
  423. if ($total < 2) { // No need to show anything
  424. return;
  425. }
  426. // Are we done?
  427. if ($done >= $total) {
  428. $done = $total;
  429. if (!empty($thisbarid)) {
  430. $donetext .= ' ('.$done.'/'.$total.') '.get_string('success');
  431. print_progress_redraw($thisbarid, $done, $total, 500, $donetext);
  432. $thisbarid = $starttime = $lasttime = NULL;
  433. }
  434. return;
  435. }
  436. if (empty($starttime)) {
  437. $starttime = $lasttime = time();
  438. $lasttime = $starttime - $updatetime;
  439. $thisbarid = uniqid();
  440. echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
  441. echo '<div id="bar'.$thisbarid.'" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
  442. echo '<div id="slider'.$thisbarid.'" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
  443. echo '</div>';
  444. echo '<div id="text'.$thisbarid.'" align="center" style="width:500px;"></div>';
  445. echo '</td></tr></table>';
  446. echo '</div>';
  447. }
  448. $now = time();
  449. if ($done && (($now - $lasttime) >= $updatetime)) {
  450. $elapsedtime = $now - $starttime;
  451. $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
  452. $percentage = round((float)$done / (float)$total, 2);
  453. $width = (int)(500 * $percentage);
  454. if ($projectedtime > 10) {
  455. $projectedtext = ' Ending: '.format_time($projectedtime);
  456. } else {
  457. $projectedtext = '';
  458. }
  459. $donetext .= ' ('.$done.'/'.$total.') '.$projectedtext;
  460. print_progress_redraw($thisbarid, $done, $total, $width, $donetext);
  461. $lasttime = $now;
  462. }
  463. }
  464. // Don't call this function directly, it's called from print_progress.
  465. function print_progress_redraw($thisbarid, $done, $total, $width, $donetext='') {
  466. if (empty($thisbarid)) {
  467. return;
  468. }
  469. echo '<script>';
  470. echo 'document.getElementById("text'.$thisbarid.'").innerHTML = "'.addslashes($donetext).'";'."\n";
  471. echo 'document.getElementById("slider'.$thisbarid.'").style.width = \''.$width.'px\';'."\n";
  472. echo '</script>';
  473. }
  474. function upgrade_get_javascript() {
  475. global $CFG;
  476. if (!empty($_SESSION['installautopilot'])) {
  477. $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = true;</script>'."\n";
  478. } else {
  479. $linktoscrolltoerrors = '<script type="text/javascript">var installautopilot = false;</script>'."\n";
  480. }
  481. $linktoscrolltoerrors .= '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>';
  482. return $linktoscrolltoerrors;
  483. }
  484. function create_admin_user() {
  485. global $CFG, $USER;
  486. if (empty($CFG->rolesactive)) { // No admin user yet.
  487. $user = new object();
  488. $user->auth = 'manual';
  489. $user->firstname = get_string('admin');
  490. $user->lastname = get_string('user');
  491. $user->username = 'admin';
  492. $user->password = hash_internal_user_password('admin');
  493. $user->email = 'root@localhost';
  494. $user->confirmed = 1;
  495. $user->mnethostid = $CFG->mnet_localhost_id;
  496. $user->lang = $CFG->lang;
  497. $user->maildisplay = 1;
  498. $user->timemodified = time();
  499. if (!$user->id = insert_record('user', $user)) {
  500. error('SERIOUS ERROR: Could not create admin user record !!!');
  501. }
  502. if (!$user = get_record('user', 'id', $user->id)) { // Double check.
  503. error('User ID was incorrect (can\'t find it)');
  504. }
  505. // Assign the default admin roles to the new user.
  506. if (!$adminroles = get_roles_with_capability('moodle/legacy:admin', CAP_ALLOW)) {
  507. error('No admin role could be found');
  508. }
  509. $sitecontext = get_context_instance(CONTEXT_SYSTEM);
  510. foreach ($adminroles as $adminrole) {
  511. role_assign($adminrole->id, $user->id, 0, $sitecontext->id);
  512. }
  513. set_config('rolesactive', 1);
  514. // Log the user in.
  515. $USER = get_complete_user_data('username', 'admin');
  516. $USER->newadminuser = 1;
  517. load_all_capabilities();
  518. redirect("$CFG->wwwroot/user/editadvanced.php?id=$user->id"); // Edit thyself
  519. } else {
  520. error('Can not create admin!');
  521. }
  522. }
  523. ////////////////////////////////////////////////
  524. /// upgrade logging functions
  525. ////////////////////////////////////////////////
  526. $upgradeloghandle = false;
  527. $upgradelogbuffer = '';
  528. // I did not find out how to use static variable in callback function,
  529. // the problem was that I could not flush the static buffer :-(
  530. global $upgradeloghandle, $upgradelogbuffer;
  531. /**
  532. * Check if upgrade is already running.
  533. *
  534. * If anything goes wrong due to missing call to upgrade_log_finish()
  535. * just restart the browser.
  536. *
  537. * @param string warning message indicating upgrade is already running
  538. * @param int page reload timeout
  539. */
  540. function upgrade_check_running($message, $timeout) {
  541. if (!empty($_SESSION['upgraderunning'])) {
  542. print_header();
  543. redirect(me(), $message, $timeout);
  544. }
  545. }
  546. /**
  547. * Start logging of output into file (if not disabled) and
  548. * prevent aborting and concurrent execution of upgrade script.
  549. *
  550. * Please note that you can not write into session variables after calling this function!
  551. *
  552. * This function may be called repeatedly.
  553. */
  554. function upgrade_log_start() {
  555. global $CFG, $upgradeloghandle;
  556. if (!empty($_SESSION['upgraderunning'])) {
  557. return; // logging already started
  558. }
  559. @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
  560. $_SESSION['upgraderunning'] = 1; // set upgrade indicator
  561. if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted
  562. session_write_close(); // from now on user can reload page - will be displayed warning
  563. }
  564. make_upload_directory('upgradelogs');
  565. ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
  566. register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging
  567. }
  568. /**
  569. * Terminate logging of output, flush all data, allow script aborting
  570. * and reopen session for writing. Function error() does terminate the logging too.
  571. *
  572. * Please make sure that each upgrade_log_start() is properly terminated by
  573. * this function or error().
  574. *
  575. * This function may be called repeatedly.
  576. */
  577. function upgrade_log_finish() {
  578. global $CFG, $upgradeloghandle, $upgradelogbuffer;
  579. if (empty($_SESSION['upgraderunning'])) {
  580. return; // logging already terminated
  581. }
  582. @ob_end_flush();
  583. if ($upgradelogbuffer !== '') {
  584. @fwrite($upgradeloghandle, $upgradelogbuffer);
  585. $upgradelogbuffer = '';
  586. }
  587. if ($upgradeloghandle and ($upgradeloghandle !== 'error')) {
  588. @fclose($upgradeloghandle);
  589. $upgradeloghandle = false;
  590. }
  591. if (empty($CFG->dbsessions)) {
  592. @session_start(); // ignore header errors, we only need to reopen session
  593. }
  594. $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
  595. if (connection_aborted()) {
  596. die;
  597. }
  598. @ignore_user_abort(false);
  599. }
  600. /**
  601. * Callback function for logging into files. Not more than one file is created per minute,
  602. * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
  603. *
  604. * This function must not output any characters or throw warnigns and errors!
  605. */
  606. function upgrade_log_callback($string) {
  607. global $CFG, $upgradeloghandle, $upgradelogbuffer;
  608. if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
  609. if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
  610. $upgradelogbuffer .= $string;
  611. if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer
  612. @fwrite($upgradeloghandle, $upgradelogbuffer);
  613. $upgradelogbuffer = '';
  614. }
  615. } else {
  616. $upgradeloghandle = 'error';
  617. }
  618. }
  619. return $string;
  620. }
  621. /**
  622. * Test if and critical warnings are present
  623. * @return bool
  624. */
  625. function admin_critical_warnings_present() {
  626. global $SESSION;
  627. if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) {
  628. return 0;
  629. }
  630. if (!isset($SESSION->admin_critical_warning)) {
  631. $SESSION->admin_critical_warning = 0;
  632. if (ini_get_bool('register_globals')) {
  633. $SESSION->admin_critical_warning = 1;
  634. } else if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) {
  635. $SESSION->admin_critical_warning = 1;
  636. }
  637. }
  638. return $SESSION->admin_critical_warning;
  639. }
  640. /**
  641. * Detects if float support at least 10 deciman digits
  642. * and also if float-->string conversion works as expected.
  643. * @return bool true if problem found
  644. */
  645. function is_float_problem() {
  646. $num1 = 2009010200.01;
  647. $num2 = 2009010200.02;
  648. return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1);
  649. }
  650. /**
  651. * Try to verify that dataroot is not accessible from web.
  652. * It is not 100% correct but might help to reduce number of vulnerable sites.
  653. *
  654. * Protection from httpd.conf and .htaccess is not detected properly.
  655. * @param bool $fetchtest try to test public access by fetching file
  656. * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING migth be problematic
  657. */
  658. function is_dataroot_insecure($fetchtest=false) {
  659. global $CFG;
  660. $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
  661. $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
  662. $rp = strrev(trim($rp, '/'));
  663. $rp = explode('/', $rp);
  664. foreach($rp as $r) {
  665. if (strpos($siteroot, '/'.$r.'/') === 0) {
  666. $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
  667. } else {
  668. break; // probably alias root
  669. }
  670. }
  671. $siteroot = strrev($siteroot);
  672. $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
  673. if (strpos($dataroot, $siteroot) !== 0) {
  674. return false;
  675. }
  676. if (!$fetchtest) {
  677. return INSECURE_DATAROOT_WARNING;
  678. }
  679. // now try all methods to fetch a test file using http protocol
  680. $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/'));
  681. preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches);
  682. $httpdocroot = $matches[1];
  683. $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot));
  684. if (make_upload_directory('diag', false) === false) {
  685. return INSECURE_DATAROOT_WARNING;
  686. }
  687. $testfile = $CFG->dataroot.'/diag/public.txt';
  688. if (!file_exists($testfile)) {
  689. file_put_contents($testfile, 'test file, do not delete');
  690. }
  691. $teststr = trim(file_get_contents($testfile));
  692. if (empty($teststr)) {
  693. // hmm, strange
  694. return INSECURE_DATAROOT_WARNING;
  695. }
  696. $testurl = $datarooturl.'/diag/public.txt';
  697. if (extension_loaded('curl') and
  698. !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and
  699. !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and
  700. ($ch = @curl_init($testurl)) !== false) {
  701. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  702. curl_setopt($ch, CURLOPT_HEADER, false);
  703. $data = curl_exec($ch);
  704. if (!curl_errno($ch)) {
  705. $data = trim($data);
  706. if ($data === $teststr) {
  707. curl_close($ch);
  708. return INSECURE_DATAROOT_ERROR;
  709. }
  710. }
  711. curl_close($ch);
  712. }
  713. if ($data = @file_get_contents($testurl)) {
  714. $data = trim($data);
  715. if ($data === $teststr) {
  716. return INSECURE_DATAROOT_ERROR;
  717. }
  718. }
  719. preg_match('|https?://([^/]+)|i', $testurl, $matches);
  720. $sitename = $matches[1];
  721. $error = 0;
  722. if ($fp = @fsockopen($sitename, 80, $error)) {
  723. preg_match('|https?://[^/]+(.*)|i', $testurl, $matches);
  724. $localurl = $matches[1];
  725. $out = "GET $localurl HTTP/1.1\r\n";
  726. $out .= "Host: $sitename\r\n";
  727. $out .= "Connection: Close\r\n\r\n";
  728. fwrite($fp, $out);
  729. $data = '';
  730. $incoming = false;
  731. while (!feof($fp)) {
  732. if ($incoming) {
  733. $data .= fgets($fp, 1024);
  734. } else if (@fgets($fp, 1024) === "\r\n") {
  735. $incoming = true;
  736. }
  737. }
  738. fclose($fp);
  739. $data = trim($data);
  740. if ($data === $teststr) {
  741. return INSECURE_DATAROOT_ERROR;
  742. }
  743. }
  744. return INSECURE_DATAROOT_WARNING;
  745. }
  746. /// =============================================================================================================
  747. /// administration tree classes and functions
  748. // n.b. documentation is still in progress for this code
  749. /// INTRODUCTION
  750. /// This file performs the following tasks:
  751. /// -it defines the necessary objects and interfaces to build the Moodle
  752. /// admin hierarchy
  753. /// -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
  754. /// and admin_externalpage_print_footer() functions used on admin pages
  755. /// ADMIN_SETTING OBJECTS
  756. /// Moodle settings are represented by objects that inherit from the admin_setting
  757. /// class. These objects encapsulate how to read a setting, how to write a new value
  758. /// to a setting, and how to appropriately display the HTML to modify the setting.
  759. /// ADMIN_SETTINGPAGE OBJECTS
  760. /// The admin_setting objects are then grouped into admin_settingpages. The latter
  761. /// appear in the Moodle admin tree block. All interaction with admin_settingpage
  762. /// objects is handled by the admin/settings.php file.
  763. /// ADMIN_EXTERNALPAGE OBJECTS
  764. /// There are some settings in Moodle that are too complex to (efficiently) handle
  765. /// with admin_settingpages. (Consider, for example, user management and displaying
  766. /// lists of users.) In this case, we use the admin_externalpage object. This object
  767. /// places a link to an external PHP file in the admin tree block.
  768. /// If you're using an admin_externalpage object for some settings, you can take
  769. /// advantage of the admin_externalpage_* functions. For example, suppose you wanted
  770. /// to add a foo.php file into admin. First off, you add the following line to
  771. /// admin/settings/first.php (at the end of the file) or to some other file in
  772. /// admin/settings:
  773. /// $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
  774. /// $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
  775. /// Next, in foo.php, your file structure would resemble the following:
  776. /// require_once('.../config.php');
  777. /// require_once($CFG->libdir.'/adminlib.php');
  778. /// admin_externalpage_setup('foo');
  779. /// // functionality like processing form submissions goes here
  780. /// admin_externalpage_print_header();
  781. /// // your HTML goes here
  782. /// admin_externalpage_print_footer();
  783. /// The admin_externalpage_setup() function call ensures the user is logged in,
  784. /// and makes sure that they have the proper role permission to access the page.
  785. /// The admin_externalpage_print_header() function prints the header (it figures
  786. /// out what category and subcategories the page is classified under) and ensures
  787. /// that you're using the admin pagelib (which provides the admin tree block and
  788. /// the admin bookmarks block).
  789. /// The admin_externalpage_print_footer() function properly closes the tables
  790. /// opened up by the admin_externalpage_print_header() function and prints the
  791. /// standard Moodle footer.
  792. /// ADMIN_CATEGORY OBJECTS
  793. /// Above and beyond all this, we have admin_category objects. These objects
  794. /// appear as folders in the admin tree block. They contain admin_settingpage's,
  795. /// admin_externalpage's, and other admin_category's.
  796. /// OTHER NOTES
  797. /// admin_settingpage's, admin_externalpage's, and admin_category's all inherit
  798. /// from part_of_admin_tree (a pseudointerface). This interface insists that
  799. /// a class has a check_access method for access permissions, a locate method
  800. /// used to find a specific node in the admin tree and find parent path.
  801. /// admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
  802. /// interface ensures that the class implements a recursive add function which
  803. /// accepts a part_of_admin_tree object and searches for the proper place to
  804. /// put it. parentable_part_of_admin_tree implies part_of_admin_tree.
  805. /// Please note that the $this->name field of any part_of_admin_tree must be
  806. /// UNIQUE throughout the ENTIRE admin tree.
  807. /// The $this->name field of an admin_setting object (which is *not* part_of_
  808. /// admin_tree) must be unique on the respective admin_settingpage where it is
  809. /// used.
  810. /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
  811. /**
  812. * Pseudointerface for anything appearing in the admin tree
  813. *
  814. * The pseudointerface that is implemented by anything that appears in the admin tree
  815. * block. It forces inheriting classes to define a method for checking user permissions
  816. * and methods for finding something in the admin tree.
  817. *
  818. * @author Vincenzo K. Marcovecchio
  819. * @package admin
  820. */
  821. class part_of_admin_tree {
  822. /**
  823. * Finds a named part_of_admin_tree.
  824. *
  825. * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
  826. * and not parentable_part_of_admin_tree, then this function should only check if
  827. * $this->name matches $name. If it does, it should return a reference to $this,
  828. * otherwise, it should return a reference to NULL.
  829. *
  830. * If a class inherits parentable_part_of_admin_tree, this method should be called
  831. * recursively on all child objects (assuming, of course, the parent object's name
  832. * doesn't match the search criterion).
  833. *
  834. * @param string $name The internal name of the part_of_admin_tree we're searching for.
  835. * @return mixed An object reference or a NULL reference.
  836. */
  837. function &locate($name) {
  838. trigger_error('Admin class does not implement method <strong>locate()</strong>', E_USER_WARNING);
  839. return;
  840. }
  841. /**
  842. * Removes named part_of_admin_tree.
  843. *
  844. * @param string $name The internal name of the part_of_admin_tree we want to remove.
  845. * @return bool success.
  846. */
  847. function prune($name) {
  848. trigger_error('Admin class does not implement method <strong>prune()</strong>', E_USER_WARNING);
  849. return;
  850. }
  851. /**
  852. * Search using query
  853. * @param strin query
  854. * @return mixed array-object structure of found settings and pages
  855. */
  856. function search($query) {
  857. trigger_error('Admin class does not implement method <strong>search()</strong>', E_USER_WARNING);
  858. return;
  859. }
  860. /**
  861. * Verifies current user's access to this part_of_admin_tree.
  862. *
  863. * Used to check if the current user has access to this part of the admin tree or
  864. * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
  865. * then this method is usually just a call to has_capability() in the site context.
  866. *
  867. * If a class inherits parentable_part_of_admin_tree, this method should return the
  868. * logical OR of the return of check_access() on all child objects.
  869. *
  870. * @return bool True if the user has access, false if she doesn't.
  871. */
  872. function check_access() {
  873. trigger_error('Admin class does not implement method <strong>check_access()</strong>', E_USER_WARNING);
  874. return;
  875. }
  876. /**
  877. * Mostly usefull for removing of some parts of the tree in admin tree block.
  878. *
  879. * @return True is hidden from normal list view
  880. */
  881. function is_hidden() {
  882. trigger_error('Admin class does not implement method <strong>is_hidden()</strong>', E_USER_WARNING);
  883. return;
  884. }
  885. }
  886. /**
  887. * Pseudointerface implemented by any part_of_admin_tree that has children.
  888. *
  889. * The pseudointerface implemented by any part_of_admin_tree that can be a parent
  890. * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
  891. * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
  892. * include an add method for adding other part_of_admin_tree objects as children.
  893. *
  894. * @author Vincenzo K. Marcovecchio
  895. * @package admin
  896. */
  897. class parentable_part_of_admin_tree extends part_of_admin_tree {
  898. /**
  899. * Adds a part_of_admin_tree object to the admin tree.
  900. *
  901. * Used to add a part_of_admin_tree object to this object or a child of this
  902. * object. $something should only be added if $destinationname matches
  903. * $this->name. If it doesn't, add should be called on child objects that are
  904. * also parentable_part_of_admin_tree's.
  905. *
  906. * @param string $destinationname The internal name of the new parent for $something.
  907. * @param part_of_admin_tree &$something The object to be added.
  908. * @return bool True on success, false on failure.
  909. */
  910. function add($destinationname, $something) {
  911. trigger_error('Admin class does not implement method <strong>add()</strong>', E_USER_WARNING);
  912. return;
  913. }
  914. }
  915. /**
  916. * The object used to represent folders (a.k.a. categories) in the admin tree block.
  917. *
  918. * Each admin_category object contains a number of part_of_admin_tree objects.
  919. *
  920. * @author Vincenzo K. Marcovecchio
  921. * @package admin
  922. */
  923. class admin_category extends parentable_part_of_admin_tree {
  924. /**
  925. * @var mixed An array of part_of_admin_tree objects that are this object's children
  926. */
  927. var $children;
  928. /**
  929. * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
  930. */
  931. var $name;
  932. /**
  933. * @var string The displayed name for this category. Usually obtained through get_string()
  934. */
  935. var $visiblename;
  936. /**
  937. * @var bool Should this category be hidden in admin tree block?
  938. */
  939. var $hidden;
  940. /**
  941. * paths
  942. */
  943. var $path;
  944. var $visiblepath;
  945. /**
  946. * Constructor for an empty admin category
  947. *
  948. * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
  949. * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
  950. * @param bool $hidden hide category in admin tree block
  951. */
  952. function admin_category($name, $visiblename, $hidden=false) {
  953. $this->children = array();
  954. $this->name = $name;
  955. $this->visiblename = $visiblename;
  956. $this->hidden = $hidden;
  957. }
  958. /**
  959. * Returns a reference to the part_of_admin_tree object with internal name $name.
  960. *
  961. * @param string $name The internal name of the object we want.
  962. * @param bool $findpath initialize path and visiblepath arrays
  963. * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
  964. */
  965. function &locate($name, $findpath=false) {
  966. if ($this->name == $name) {
  967. if ($findpath) {
  968. $this->visiblepath[] = $this->visiblename;
  969. $this->path[] = $this->name;
  970. }
  971. return $this;
  972. }
  973. $return = NULL;
  974. foreach($this->children as $childid=>$unused) {
  975. if ($return =& $this->children[$childid]->locate($name, $findpath)) {
  976. break;
  977. }
  978. }
  979. if (!is_null($return) and $findpath) {
  980. $return->visiblepath[] = $this->visiblename;
  981. $return->path[] = $this->name;
  982. }
  983. return $return;
  984. }
  985. /**
  986. * Search using query
  987. * @param strin query
  988. * @return mixed array-object structure of found settings and pages
  989. */
  990. function search($query) {
  991. $result = array();
  992. foreach ($this->children as $child) {
  993. $subsearch = $child->search($query);
  994. if (!is_array($subsearch)) {
  995. debugging('Incorrect search result from '.$child->name);
  996. continue;
  997. }
  998. $result = array_merge($result, $subsearch);
  999. }
  1000. return $result;
  1001. }
  1002. /**
  1003. * Removes part_of_admin_tree object with internal name $name.
  1004. *
  1005. * @param string $name The internal name of the object we want to remove.
  1006. * @return bool success
  1007. */
  1008. function prune($name) {
  1009. if ($this->name == $name) {
  1010. return false; //can not remove itself
  1011. }
  1012. foreach($this->children as $precedence => $child) {
  1013. if ($child->name == $name) {
  1014. // found it!
  1015. unset($this->children[$precedence]);
  1016. return true;
  1017. }
  1018. if ($this->children[$precedence]->prune($name)) {
  1019. return true;
  1020. }
  1021. }
  1022. return false;
  1023. }
  1024. /**
  1025. * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
  1026. *
  1027. * @param string $destinationame The internal name of the immediate parent that we want for $something.
  1028. * @param mixed $something A part_of_admin_tree or setting instanceto be added.
  1029. * @return bool True if successfully added, false if $something can not be added.
  1030. */
  1031. function add($parentname, $something) {
  1032. $parent =& $this->locate($parentname);
  1033. if (is_null($parent)) {
  1034. debugging('parent does not exist!');
  1035. return false;
  1036. }
  1037. if (is_a($something, 'part_of_admin_tree')) {
  1038. if (!is_a($parent, 'parentable_part_of_admin_tree')) {
  1039. debugging('error - parts of tree can be inserted only into parentable parts');
  1040. return false;
  1041. }
  1042. $parent->children[] = $something;
  1043. return true;
  1044. } else {
  1045. debugging('error - can not add this element');
  1046. return false;
  1047. }
  1048. }
  1049. /**
  1050. * Checks if the user has access to anything in this category.
  1051. *
  1052. * @return bool True if the user has access to atleast one child in this category, false otherwise.
  1053. */
  1054. function check_access() {
  1055. foreach ($this->children as $child) {
  1056. if ($child->check_access()) {
  1057. return true;
  1058. }
  1059. }
  1060. return false;
  1061. }
  1062. /**
  1063. * Is this category hidden in admin tree block?
  1064. *
  1065. * @return bool True if hidden
  1066. */
  1067. function is_hidden() {
  1068. return $this->hidden;
  1069. }
  1070. }
  1071. class admin_root extends admin_category {
  1072. /**
  1073. * list of errors
  1074. */
  1075. var $errors;
  1076. /**
  1077. * search query
  1078. */
  1079. var $search;
  1080. /**
  1081. * full tree flag - true means all settings required, false onlypages required
  1082. */
  1083. var $fulltree;
  1084. function admin_root() {
  1085. parent::admin_category('root', get_string('administration'), false);
  1086. $this->errors = array();
  1087. $this->search = '';
  1088. $this->fulltree = true;
  1089. }
  1090. }
  1091. /**
  1092. * Links external PHP pages into the admin tree.
  1093. *
  1094. * See detailed usage example at the top of this document (adminlib.php)
  1095. *
  1096. * @author Vincenzo K. Marcovecchio
  1097. * @package admin
  1098. */
  1099. class admin_externalpage extends part_of_admin_tree {
  1100. /**
  1101. * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
  1102. */
  1103. var $name;
  1104. /**
  1105. * @var string The displayed name for this external page. Usually obtained through get_string().
  1106. */
  1107. var $visiblename;
  1108. /**
  1109. * @var string The external URL that we should link to when someone requests this external page.
  1110. */
  1111. var $url;
  1112. /**
  1113. * @var string The role capability/permission a user must have to access this external page.
  1114. */
  1115. var $req_capability;
  1116. /**
  1117. * @var object The context in which capability/permission should be checked, default is site context.
  1118. */
  1119. var $context;
  1120. /**
  1121. * @var bool hidden in admin tree block.
  1122. */
  1123. var $hidden;
  1124. /**
  1125. * visible path
  1126. */
  1127. var $path;
  1128. var $visiblepath;
  1129. /**
  1130. * Constructor for adding an external page into the admin tree.
  1131. *
  1132. * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
  1133. * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
  1134. * @param string $url The external URL that we should link to when someone requests this external page.
  1135. * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
  1136. * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
  1137. * @param context $context The context the page relates to. Not sure what happens
  1138. * if you specify something other than system or front page. Defaults to system.
  1139. */
  1140. function admin_externalpage($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
  1141. $this->name = $name;
  1142. $this->visiblename = $visiblename;
  1143. $this->url = $url;
  1144. if (is_array($req_capability)) {
  1145. $this->req_capability = $req_capability;
  1146. } else {
  1147. $this->req_capability = array($req_capability);
  1148. }
  1149. $this->hidden = $hidden;
  1150. $this->context = $context;
  1151. }
  1152. /**
  1153. * Returns a reference to the part_of_admin_tree object with internal name $name.
  1154. *
  1155. * @param string $name The internal name of the object we want.
  1156. * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
  1157. */
  1158. function &locate($name, $findpath=false) {
  1159. if ($this->name == $name) {
  1160. if ($findpath) {
  1161. $this->visiblepath = array($this->visiblename);
  1162. $this->path = array($this->name);
  1163. }
  1164. return $this;
  1165. } else {
  1166. $return = NULL;
  1167. return $return;
  1168. }
  1169. }
  1170. function prune($name) {
  1171. return false;
  1172. }
  1173. /**
  1174. * Search using query
  1175. * @param strin query
  1176. * @return mixed array-object structure of found settings and pages
  1177. */
  1178. function search($query) {
  1179. $textlib = textlib_get_instance();
  1180. $found = false;
  1181. if (strpos(strtolower($this->name), $query) !== false) {
  1182. $found = true;
  1183. } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
  1184. $found = true;
  1185. }
  1186. if ($found) {
  1187. $result = new object();
  1188. $result->page = $this;
  1189. $result->settings = array();
  1190. return array($this->name => $result);
  1191. } else {
  1192. return array();
  1193. }
  1194. }
  1195. /**
  1196. * Determines if the current user has access to this external page based on $this->req_capability.
  1197. * @return bool True if user has access, false otherwise.
  1198. */
  1199. function check_access() {
  1200. if (!get_site()) {
  1201. return true; // no access check before site is fully set up
  1202. }
  1203. $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
  1204. foreach($this->req_capability as $cap) {
  1205. if (is_valid_capability($cap) and has_capability($cap, $context)) {
  1206. return true;
  1207. }
  1208. }
  1209. return false;
  1210. }
  1211. /**
  1212. * Is this external page hidden in admin tree block?
  1213. *
  1214. * @return bool True if hidden
  1215. */
  1216. function is_hidden() {
  1217. return $this->hidden;
  1218. }
  1219. }
  1220. /**
  1221. * Used to group a number of admin_setting objects into a page and add them to the admin tree.
  1222. *
  1223. * @author Vincenzo K. Marcovecchio
  1224. * @package admin
  1225. */
  1226. class admin_settingpage extends part_of_admin_tree {
  1227. /**
  1228. * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
  1229. */
  1230. var $name;
  1231. /**
  1232. * @var string The displayed name for this external page. Usually obtained through get_string().
  1233. */
  1234. var $visiblename;
  1235. /**
  1236. * @var mixed An array of admin_setting objects that are part of this setting page.
  1237. */
  1238. var $settings;
  1239. /**
  1240. * @var string The role capability/permission a user must have to access this external page.
  1241. */
  1242. var $req_capability;
  1243. /**
  1244. * @var object The context in which capability/permission should be checked, default is site context.
  1245. */
  1246. var $context;
  1247. /**
  1248. * @var bool hidden in admin tree block.
  1249. */
  1250. var $hidden;
  1251. /**
  1252. * paths
  1253. */
  1254. var $path;
  1255. var $visiblepath;
  1256. // see admin_externalpage
  1257. function admin_settingpage($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
  1258. $this->settings = new object();
  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 = $hidden;
  1267. $this->context = $context;
  1268. }
  1269. // see admin_category
  1270. function &locate($name, $findpath=false) {
  1271. if ($this->name == $name) {
  1272. if ($findpath) {
  1273. $this->visiblepath = array($this->visiblename);
  1274. $this->path = array($this->name);
  1275. }
  1276. return $this;
  1277. } else {
  1278. $return = NULL;
  1279. return $return;
  1280. }
  1281. }
  1282. function search($query) {
  1283. $found = array();
  1284. foreach ($this->settings as $setting) {
  1285. if ($setting->is_related($query)) {
  1286. $found[] = $setting;
  1287. }
  1288. }
  1289. if ($found) {
  1290. $result = new object();
  1291. $result->page = $this;
  1292. $result->settings = $found;
  1293. return array($this->name => $result);
  1294. }
  1295. $textlib = textlib_get_instance();
  1296. $found = false;
  1297. if (strpos(strtolower($this->name), $query) !== false) {
  1298. $found = true;
  1299. } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
  1300. $found = true;
  1301. }
  1302. if ($found) {
  1303. $result = new object();
  1304. $result->page = $this;
  1305. $result->settings = array();
  1306. return array($this->name => $result);
  1307. } else {
  1308. return array();
  1309. }
  1310. }
  1311. function prune($name) {
  1312. return false;
  1313. }
  1314. /**
  1315. * 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
  1316. * n.b. each admin_setting in an admin_settingpage must have a unique internal name
  1317. * @param object $setting is the admin_setting object you want to add
  1318. * @return true if successful, false if not
  1319. */
  1320. function add($setting) {
  1321. if (!is_a($setting, 'admin_setting')) {
  1322. debugging('error - not a setting instance');
  1323. return false;
  1324. }
  1325. $this->settings->{$setting->name} = $setting;
  1326. return true;
  1327. }
  1328. // see admin_externalpage
  1329. function check_access() {
  1330. if (!get_site()) {
  1331. return true; // no access check before site is fully set up
  1332. }
  1333. $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
  1334. foreach($this->req_capability as $cap) {
  1335. if (is_valid_capability($cap) and has_capability($cap, $context)) {
  1336. return true;
  1337. }
  1338. }
  1339. return false;
  1340. }
  1341. /**
  1342. * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
  1343. * returns a string of the html
  1344. */
  1345. function output_html() {
  1346. $adminroot =& admin_get_root();
  1347. $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
  1348. foreach($this->settings as $setting) {
  1349. $fullname = $setting->get_full_name();
  1350. if (array_key_exists($fullname, $adminroot->errors)) {
  1351. $data = $adminroot->errors[$fullname]->data;
  1352. } else {
  1353. $data = $setting->get_setting();
  1354. if (is_null($data)) {
  1355. $data = $setting->get_defaultsetting();
  1356. }
  1357. }
  1358. $return .= $setting->output_html($data);
  1359. }
  1360. $return .= '</fieldset>';
  1361. return $return;
  1362. }
  1363. /**
  1364. * Is this settigns page hidden in admin tree block?
  1365. *
  1366. * @return bool True if hidden
  1367. */
  1368. function is_hidden() {
  1369. return $this->hidden;
  1370. }
  1371. }
  1372. /**
  1373. * Admin settings class. Only exists on setting pages.
  1374. * Read & write happens at this level; no authentication.
  1375. */
  1376. class admin_setting {
  1377. var $name;
  1378. var $visiblename;
  1379. var $description;
  1380. var $defaultsetting;
  1381. var $updatedcallback;
  1382. var $plugin; // null means main config table
  1383. /**
  1384. * Constructor
  1385. * @param $name string unique ascii name
  1386. * @param $visiblename string localised name
  1387. * @param strin $description localised long description
  1388. * @param mixed $defaultsetting string or array depending on implementation
  1389. */
  1390. function admin_setting($name, $visiblename, $description, $defaultsetting) {
  1391. $this->parse_setting_name($name);
  1392. $this->visiblename = $visiblename;
  1393. $this->description = $description;
  1394. $this->defaultsetting = $defaultsetting;
  1395. }
  1396. /**
  1397. * Set up $this->name and possibly $this->plugin based on whether $name looks
  1398. * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking
  1399. * on the names, that is, output a developer debug warning if the name
  1400. * contains anything other than [a-zA-Z0-9_]+.
  1401. *
  1402. * @param string $name the setting name passed in to the constructor.
  1403. */
  1404. function parse_setting_name($name) {
  1405. $bits = explode('/', $name);
  1406. if (count($bits) > 2) {
  1407. print_error('invalidadminsettingname', '', '', $name);
  1408. }
  1409. $this->name = array_pop($bits);
  1410. if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) {
  1411. print_error('invalidadminsettingname', '', '', $name);
  1412. }
  1413. if (!empty($bits)) {
  1414. $this->plugin = array_pop($bits);
  1415. if ($this->plugin === 'moodle') {
  1416. $this->plugin = null;
  1417. } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) {
  1418. print_error('invalidadminsettingname', '', '', $name);
  1419. }
  1420. }
  1421. }
  1422. function get_full_name() {
  1423. return 's_'.$this->plugin.'_'.$this->name;
  1424. }
  1425. function get_id() {
  1426. return 'id_s_'.$this->plugin.'_'.$this->name;
  1427. }
  1428. function config_read($name) {
  1429. global $CFG;
  1430. if ($this->plugin === 'backup') {
  1431. require_once($CFG->dirroot.'/backup/lib.php');
  1432. $backupconfig = backup_get_config();
  1433. if (isset($backupconfig->$name)) {
  1434. return $backupconfig->$name;
  1435. } else {
  1436. return NULL;
  1437. }
  1438. } else if (!empty($this->plugin)) {
  1439. $value = get_config($this->plugin, $name);
  1440. return $value === false ? NULL : $value;
  1441. } else {
  1442. if (isset($CFG->$name)) {
  1443. return $CFG->$name;
  1444. } else {
  1445. return NULL;
  1446. }
  1447. }
  1448. }
  1449. function config_write($name, $value) {
  1450. global $CFG;
  1451. if ($this->plugin === 'backup') {
  1452. require_once($CFG->dirroot.'/backup/lib.php');
  1453. return (boolean)backup_set_config($name, $value);
  1454. } else {
  1455. return (boolean)set_config($name, $value, $this->plugin);
  1456. }
  1457. }
  1458. /**
  1459. * Returns current value of this setting
  1460. * @return mixed array or string depending on instance, NULL means not set yet
  1461. */
  1462. function get_setting() {
  1463. // has to be overridden
  1464. return NULL;
  1465. }
  1466. /**
  1467. * Returns default setting if exists
  1468. * @return mixed array or string depending on instance; NULL means no default, user must supply
  1469. */
  1470. function get_defaultsetting() {
  1471. return $this->defaultsetting;
  1472. }
  1473. /**
  1474. * Store new setting
  1475. * @param mixed string or array, must not be NULL
  1476. * @return '' if ok, string error message otherwise
  1477. */
  1478. function write_setting($data) {
  1479. // should be overridden
  1480. return '';
  1481. }
  1482. /**
  1483. * Return part of form with setting
  1484. * @param mixed data array or string depending on setting
  1485. * @return string
  1486. */
  1487. function output_html($data, $query='') {
  1488. // should be overridden
  1489. return;
  1490. }
  1491. /**
  1492. * function called if setting updated - cleanup, cache reset, etc.
  1493. */
  1494. function set_updatedcallback($functionname) {
  1495. $this->updatedcallback = $functionname;
  1496. }
  1497. /**
  1498. * Is setting related to query text - used when searching
  1499. * @param string $query
  1500. * @return bool
  1501. */
  1502. function is_related($query) {
  1503. if (strpos(strtolower($this->name), $query) !== false) {
  1504. return true;
  1505. }
  1506. $textlib = textlib_get_instance();
  1507. if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
  1508. return true;
  1509. }
  1510. if (strpos($textlib->strtolower($this->description), $query) !== false) {
  1511. return true;
  1512. }
  1513. $current = $this->get_setting();
  1514. if (!is_null($current)) {
  1515. if (is_string($current)) {
  1516. if (strpos($textlib->strtolower($current), $query) !== false) {
  1517. return true;
  1518. }
  1519. }
  1520. }
  1521. $default = $this->get_defaultsetting();
  1522. if (!is_null($default)) {
  1523. if (is_string($default)) {
  1524. if (strpos($textlib->strtolower($default), $query) !== false) {
  1525. return true;
  1526. }
  1527. }
  1528. }
  1529. return false;
  1530. }
  1531. }
  1532. /**
  1533. * No setting - just heading and text.
  1534. */
  1535. class admin_setting_heading extends admin_setting {
  1536. /**
  1537. * not a setting, just text
  1538. * @param string $name of setting
  1539. * @param string $heading heading
  1540. * @param string $information text in box
  1541. */
  1542. function admin_setting_heading($name, $heading, $information) {
  1543. parent::admin_setting($name, $heading, $information, '');
  1544. }
  1545. function get_setting() {
  1546. return true;
  1547. }
  1548. function get_defaultsetting() {
  1549. return true;
  1550. }
  1551. function write_setting($data) {
  1552. // do not write any setting
  1553. return '';
  1554. }
  1555. function output_html($data, $query='') {
  1556. $return = '';
  1557. if ($this->visiblename != '') {
  1558. $return .= print_heading('<a name="'.$this->name.'">'.highlightfast($query, $this->visiblename).'</a>', '', 3, 'main', true);
  1559. }
  1560. if ($this->description != '') {
  1561. $return .= print_box(highlight($query, $this->description), 'generalbox formsettingheading', '', true);
  1562. }
  1563. return $return;
  1564. }
  1565. }
  1566. /**
  1567. * The most flexibly setting, user is typing text
  1568. */
  1569. class admin_setting_configtext extends admin_setting {
  1570. var $paramtype;
  1571. var $size;
  1572. /**
  1573. * config text contructor
  1574. * @param string $name of setting
  1575. * @param string $visiblename localised
  1576. * @param string $description long localised info
  1577. * @param string $defaultsetting
  1578. * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
  1579. * @param int $size default field size
  1580. */
  1581. function admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
  1582. $this->paramtype = $paramtype;
  1583. if (!is_null($size)) {
  1584. $this->size = $size;
  1585. } else {
  1586. $this->size = ($paramtype == PARAM_INT) ? 5 : 30;
  1587. }
  1588. parent::admin_setting($name, $visiblename, $description, $defaultsetting);
  1589. }
  1590. function get_setting() {
  1591. return $this->config_read($this->name);
  1592. }
  1593. function write_setting($data) {
  1594. if ($this->paramtype === PARAM_INT and $data === '') {
  1595. // do not complain if '' used instead of 0
  1596. $data = 0;
  1597. }
  1598. // $data is a string
  1599. $validated = $this->validate($data);
  1600. if ($validated !== true) {
  1601. return $validated;
  1602. }
  1603. return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
  1604. }
  1605. /**
  1606. * Validate data before storage
  1607. * @param string data
  1608. * @return mixed true if ok string if error found
  1609. */
  1610. function validate($data) {
  1611. if (is_string($this->paramtype)) {
  1612. if (preg_match($this->paramtype, $data)) {
  1613. return true;
  1614. } else {
  1615. return get_string('validateerror', 'admin');
  1616. }
  1617. } else if ($this->paramtype === PARAM_RAW) {
  1618. return true;
  1619. } else {
  1620. $cleaned = stripslashes(clean_param(addslashes($data), $this->paramtype));
  1621. if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
  1622. return true;
  1623. } else {
  1624. return get_string('validateerror', 'admin');
  1625. }
  1626. }
  1627. }
  1628. function output_html($data, $query='') {
  1629. $default = $this->get_defaultsetting();
  1630. return format_admin_setting($this, $this->visiblename,
  1631. '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>',
  1632. $this->description, true, '', $default, $query);
  1633. }
  1634. }
  1635. /**
  1636. * General text area without html editor.
  1637. */
  1638. class admin_setting_configtextarea extends admin_setting_configtext {
  1639. var $rows;
  1640. var $cols;
  1641. function admin_setting_configtextarea($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
  1642. $this->rows = $rows;
  1643. $this->cols = $cols;
  1644. parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
  1645. }
  1646. function output_html($data, $query='') {
  1647. $default = $this->get_defaultsetting();
  1648. $defaultinfo = $default;
  1649. if (!is_null($default) and $default !== '') {
  1650. $defaultinfo = "\n".$default;
  1651. }
  1652. return format_admin_setting($this, $this->visiblename,
  1653. '<div class="form-textarea" ><textarea rows="'.$this->rows.'" cols="'.$this->cols.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'">'.s($data).'</textarea></div>',
  1654. $this->description, true, '', $defaultinfo, $query);
  1655. }
  1656. }
  1657. /**
  1658. * General text area with html editor.
  1659. */
  1660. class admin_setting_confightmltextarea extends admin_setting_configtext {
  1661. function admin_setting_confightmltextarea($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW) {
  1662. parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, $paramtype);
  1663. }
  1664. function output_html($data, $query='') {
  1665. global $CFG;
  1666. $CFG->adminusehtmleditor = can_use_html_editor();
  1667. $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true).'</div>';
  1668. return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
  1669. }
  1670. }
  1671. /**
  1672. * Password field, allows unmasking of password
  1673. */
  1674. class admin_setting_configpasswordunmask extends admin_setting_configtext {
  1675. /**
  1676. * Constructor
  1677. * @param string $name of setting
  1678. * @param string $visiblename localised
  1679. * @param string $description long localised info
  1680. * @param string $defaultsetting default password
  1681. */
  1682. function admin_setting_configpasswordunmask($name, $visiblename, $description, $defaultsetting) {
  1683. parent::admin_setting_configtext($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
  1684. }
  1685. function output_html($data, $query='') {
  1686. $id = $this->get_id();
  1687. $unmask = get_string('unmaskpassword', 'form');
  1688. $unmaskjs = '<script type="text/javascript">
  1689. //<![CDATA[
  1690. document.write(\'<span class="unmask"><input id="'.$id.'unmask" value="1" type="checkbox" onclick="unmaskPassword(\\\''.$id.'\\\')"/><label for="'.$id.'unmask">'.addslashes_js($unmask).'<\/label><\/span>\');
  1691. document.getElementById("'.$this->get_id().'").setAttribute("autocomplete", "off");
  1692. //]]>
  1693. </script>';
  1694. return format_admin_setting($this, $this->visiblename,
  1695. '<div class="form-password"><input type="password" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$unmaskjs.'</div>',
  1696. $this->description, true, '', NULL, $query);
  1697. }
  1698. }
  1699. /**
  1700. * Path to directory
  1701. */
  1702. class admin_setting_configfile extends admin_setting_configtext {
  1703. /**
  1704. * Constructor
  1705. * @param string $name of setting
  1706. * @param string $visiblename localised
  1707. * @param string $description long localised info
  1708. * @param string $defaultdirectory default directory location
  1709. */
  1710. function admin_setting_configfile($name, $visiblename, $description, $defaultdirectory) {
  1711. parent::admin_setting_configtext($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
  1712. }
  1713. function output_html($data, $query='') {
  1714. $default = $this->get_defaultsetting();
  1715. if ($data) {
  1716. if (file_exists($data)) {
  1717. $executable = '<span class="pathok">&#x2714;</span>';
  1718. } else {
  1719. $executable = '<span class="patherror">&#x2718;</span>';
  1720. }
  1721. } else {
  1722. $executable = '';
  1723. }
  1724. return format_admin_setting($this, $this->visiblename,
  1725. '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
  1726. $this->description, true, '', $default, $query);
  1727. }
  1728. }
  1729. /**
  1730. * Path to executable file
  1731. */
  1732. class admin_setting_configexecutable extends admin_setting_configfile {
  1733. function output_html($data, $query='') {
  1734. $default = $this->get_defaultsetting();
  1735. if ($data) {
  1736. if (file_exists($data) and is_executable($data)) {
  1737. $executable = '<span class="pathok">&#x2714;</span>';
  1738. } else {
  1739. $executable = '<span class="patherror">&#x2718;</span>';
  1740. }
  1741. } else {
  1742. $executable = '';
  1743. }
  1744. return format_admin_setting($this, $this->visiblename,
  1745. '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
  1746. $this->description, true, '', $default, $query);
  1747. }
  1748. }
  1749. /**
  1750. * Path to directory
  1751. */
  1752. class admin_setting_configdirectory extends admin_setting_configfile {
  1753. function output_html($data, $query='') {
  1754. $default = $this->get_defaultsetting();
  1755. if ($data) {
  1756. if (file_exists($data) and is_dir($data)) {
  1757. $executable = '<span class="pathok">&#x2714;</span>';
  1758. } else {
  1759. $executable = '<span class="patherror">&#x2718;</span>';
  1760. }
  1761. } else {
  1762. $executable = '';
  1763. }
  1764. return format_admin_setting($this, $this->visiblename,
  1765. '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
  1766. $this->description, true, '', $default, $query);
  1767. }
  1768. }
  1769. /**
  1770. * Checkbox
  1771. */
  1772. class admin_setting_configcheckbox extends admin_setting {
  1773. var $yes;
  1774. var $no;
  1775. /**
  1776. * Constructor
  1777. * @param string $name of setting
  1778. * @param string $visiblename localised
  1779. * @param string $description long localised info
  1780. * @param string $defaultsetting
  1781. * @param string $yes value used when checked
  1782. * @param string $no value used when not checked
  1783. */
  1784. function admin_setting_configcheckbox($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
  1785. parent::admin_setting($name, $visiblename, $description, $defaultsetting);
  1786. $this->yes = (string)$yes;
  1787. $this->no = (string)$no;
  1788. }
  1789. function get_setting() {
  1790. return $this->config_read($this->name);
  1791. }
  1792. function write_setting($data) {
  1793. if ((string)$data === $this->yes) { // convert to strings before comparison
  1794. $data = $this->yes;
  1795. } else {
  1796. $data = $this->no;
  1797. }
  1798. return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
  1799. }
  1800. function output_html($data, $query='') {
  1801. $default = $this->get_defaultsetting();
  1802. if (!is_null($default)) {
  1803. if ((string)$default === $this->yes) {
  1804. $defaultinfo = get_string('checkboxyes', 'admin');
  1805. } else {
  1806. $defaultinfo = get_string('checkboxno', 'admin');
  1807. }
  1808. } else {
  1809. $defaultinfo = NULL;
  1810. }
  1811. if ((string)$data === $this->yes) { // convert to strings before comparison
  1812. $checked = 'checked="checked"';
  1813. } else {
  1814. $checked = '';
  1815. }
  1816. return format_admin_setting($this, $this->visiblename,
  1817. '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
  1818. .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
  1819. $this->description, true, '', $defaultinfo, $query);
  1820. }
  1821. }
  1822. /**
  1823. * Multiple checkboxes, each represents different value, stored in csv format
  1824. */
  1825. class admin_setting_configmulticheckbox extends admin_setting {
  1826. var $choices;
  1827. /**
  1828. * Constructor
  1829. * @param string $name of setting
  1830. * @param string $visiblename localised
  1831. * @param string $description long localised info
  1832. * @param array $defaultsetting array of selected
  1833. * @param array $choices array of $value=>$label for each checkbox
  1834. */
  1835. function admin_setting_configmulticheckbox($name, $visiblename, $description, $defaultsetting, $choices) {
  1836. $this->choices = $choices;
  1837. parent::admin_setting($name, $visiblename, $description, $defaultsetting);
  1838. }
  1839. /**
  1840. * This function may be used in ancestors for lazy loading of choices
  1841. * @return true if loaded, false if error
  1842. */
  1843. function load_choices() {
  1844. /*
  1845. if (is_array($this->choices)) {
  1846. return true;
  1847. }
  1848. .... load choices here
  1849. */
  1850. return true;
  1851. }
  1852. /**
  1853. * Is setting related to query text - used when searching
  1854. * @param string $query
  1855. * @return bool
  1856. */
  1857. function is_related($query) {
  1858. if (!$this->load_choices() or empty($this->choices)) {
  1859. return false;
  1860. }
  1861. if (parent::is_related($query)) {
  1862. return true;
  1863. }
  1864. $textlib = textlib_get_instance();
  1865. foreach ($this->choices as $desc) {
  1866. if (strpos($textlib->strtolower($desc), $query) !== false) {
  1867. return true;
  1868. }
  1869. }
  1870. return false;
  1871. }
  1872. function get_setting() {
  1873. $result = $this->config_read($this->name);
  1874. if (is_null($result)) {
  1875. return NULL;
  1876. }
  1877. if ($result === '') {
  1878. return array();
  1879. }
  1880. return explode(',', $result);
  1881. }
  1882. function write_setting($data) {
  1883. if (!is_array($data)) {
  1884. return ''; // ignore it
  1885. }
  1886. if (!$this->load_choices() or empty($this->choices)) {
  1887. return '';
  1888. }
  1889. unset($data['xxxxx']);
  1890. $result = array();
  1891. foreach ($data as $key => $value) {
  1892. if ($value and array_key_exists($key, $this->choices)) {
  1893. $result[] = $key;
  1894. }
  1895. }
  1896. return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
  1897. }
  1898. function output_html($data, $query='') {
  1899. if (!$this->load_choices() or empty($this->choices)) {
  1900. return '';
  1901. }
  1902. $default = $this->get_defaultsetting();
  1903. if (is_null($default)) {
  1904. $default = array();
  1905. }
  1906. if (is_null($data)) {
  1907. foreach ($default as $key=>$value) {
  1908. if ($value) {
  1909. $current[] = $value;
  1910. }
  1911. }
  1912. }
  1913. $options = array();
  1914. $defaults = array();
  1915. foreach($this->choices as $key=>$description) {
  1916. if (in_array($key, $data)) {
  1917. $checked = 'checked="checked"';
  1918. } else {
  1919. $checked = '';
  1920. }
  1921. if (!empty($default[$key])) {
  1922. $defaults[] = $description;
  1923. }
  1924. $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
  1925. .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
  1926. }
  1927. if (is_null($default)) {
  1928. $defaultinfo = NULL;
  1929. } else if (!empty($defaults)) {
  1930. $defaultinfo = implode(', ', $defaults);
  1931. } else {
  1932. $defaultinfo = get_string('none');
  1933. }
  1934. $return = '<div class="form-multicheckbox">';
  1935. $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
  1936. if ($options) {
  1937. $return .= '<ul>';
  1938. foreach ($options as $option) {
  1939. $return .= '<li>'.$option.'</li>';
  1940. }
  1941. $return .= '</ul>';
  1942. }
  1943. $return .= '</div>';
  1944. return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
  1945. }
  1946. }
  1947. /**
  1948. * Multiple checkboxes 2, value stored as string 00101011
  1949. */
  1950. class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
  1951. function get_setting() {
  1952. $result = $this->config_read($this->name);
  1953. if (is_null($result)) {
  1954. return NULL;
  1955. }
  1956. if (!$this->load_choices()) {
  1957. return NULL;
  1958. }
  1959. $result = str_pad($result, count($this->choices), '0');
  1960. $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
  1961. $setting = array();
  1962. foreach ($this->choices as $key=>$unused) {
  1963. $value = array_shift($result);
  1964. if ($value) {
  1965. $setting[] = $key;
  1966. }
  1967. }
  1968. return $setting;
  1969. }
  1970. function write_setting($data) {
  1971. if (!is_array($data)) {
  1972. return ''; // ignore it
  1973. }
  1974. if (!$this->load_choices() or empty($this->choices)) {
  1975. return '';
  1976. }
  1977. $result = '';
  1978. foreach ($this->choices as $key=>$unused) {
  1979. if (!empty($data[$key])) {
  1980. $result .= '1';
  1981. } else {
  1982. $result .= '0';
  1983. }
  1984. }
  1985. return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
  1986. }
  1987. }
  1988. /**
  1989. * Select one value from list
  1990. */
  1991. class admin_setting_configselect extends admin_setting {
  1992. var $choices;
  1993. /**
  1994. * Constructor
  1995. * @param string $name of setting
  1996. * @param string $visiblename localised
  1997. * @param string $description long localised info
  1998. * @param string $defaultsetting
  1999. * @param array $choices array of $value=>$label for each selection
  2000. */
  2001. function admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices) {
  2002. $this->choices = $choices;
  2003. parent::admin_setting($name, $visiblename, $description, $defaultsetting);
  2004. }
  2005. /**
  2006. * This function may be used in ancestors for lazy loading of choices
  2007. * @return true if loaded, false if error
  2008. */
  2009. function load_choices() {
  2010. /*
  2011. if (is_array($this->choices)) {
  2012. return true;
  2013. }
  2014. .... load choices here
  2015. */
  2016. return true;
  2017. }
  2018. function is_related($query) {
  2019. if (parent::is_related($query)) {
  2020. return true;
  2021. }
  2022. if (!$this->load_choices()) {
  2023. return false;
  2024. }
  2025. $textlib = textlib_get_instance();
  2026. foreach ($this->choices as $key=>$value) {
  2027. if (strpos($textlib->strtolower($key), $query) !== false) {
  2028. return true;
  2029. }
  2030. if (strpos($textlib->strtolower($value), $query) !== false) {
  2031. return true;
  2032. }
  2033. }
  2034. return false;
  2035. }
  2036. function get_setting() {
  2037. return $this->config_read($this->name);
  2038. }
  2039. function write_setting($data) {
  2040. if (!$this->load_choices() or empty($this->choices)) {
  2041. return '';
  2042. }
  2043. if (!array_key_exists($data, $this->choices)) {
  2044. return ''; // ignore it
  2045. }
  2046. return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
  2047. }
  2048. function output_html($data, $query='') {
  2049. if (!$this->load_choices() or empty($this->choices)) {
  2050. return '';
  2051. }
  2052. $default = $this->get_defaultsetting();
  2053. if (!is_null($default) and array_key_exists($default, $this->choices)) {
  2054. $defaultinfo = $this->choices[$default];
  2055. } else {
  2056. $defaultinfo = NULL;
  2057. }
  2058. $current = $this->get_setting();
  2059. $warning = '';
  2060. if (is_null($current)) {
  2061. //first run
  2062. } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
  2063. // no warning
  2064. } else if (!array_key_exists($current, $this->choices)) {
  2065. $warning = get_string('warningcurrentsetting', 'admin', s($current));
  2066. if (!is_null($default) and $data==$current) {
  2067. $data = $default; // use default instead of first value when showing the form
  2068. }
  2069. }
  2070. $return = '<div class="form-select defaultsnext"><select id="'.$this->get_id().'" name="'.$this->get_full_name().'">';
  2071. foreach ($this->choices as $key => $value) {
  2072. // the string cast is needed because key may be integer - 0 is equal to most strings!
  2073. $return .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
  2074. }
  2075. $return .= '</select></div>';
  2076. return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
  2077. }
  2078. }
  2079. /**
  2080. * Select multiple items from list
  2081. */
  2082. class admin_setting_configmultiselect extends admin_setting_configselect {
  2083. /**
  2084. * Constructor
  2085. * @param string $name of setting
  2086. * @param string $visiblename localised
  2087. * @param string $description long localised info
  2088. * @param array $defaultsetting array of selected items
  2089. * @param array $choices array of $value=>$label for each list item
  2090. */
  2091. function admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, $choices) {
  2092. parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, $choices);
  2093. }
  2094. function get_setting() {
  2095. $result = $this->config_read($this->name);
  2096. if (is_null($result)) {
  2097. return NULL;
  2098. }
  2099. if ($result === '') {
  2100. return array();
  2101. }
  2102. return explode(',', $result);
  2103. }
  2104. function write_setting($data) {
  2105. if (!is_array($data)) {
  2106. return ''; //ignore it
  2107. }
  2108. if (!$this->load_choices() or empty($this->choices)) {
  2109. return '';
  2110. }
  2111. unset($data['xxxxx']);
  2112. $save = array();
  2113. foreach ($data as $value) {
  2114. if (!array_key_exists($value, $this->choices)) {
  2115. continue; // ignore it
  2116. }
  2117. $save[] = $value;
  2118. }
  2119. return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
  2120. }
  2121. /**
  2122. * Is setting related to query text - used when searching
  2123. * @param string $query
  2124. * @return bool
  2125. */
  2126. function is_related($query) {
  2127. if (!$this->load_choices() or empty($this->choices)) {
  2128. return false;
  2129. }
  2130. if (parent::is_related($query)) {
  2131. return true;
  2132. }
  2133. $textlib = textlib_get_instance();
  2134. foreach ($this->choices as $desc) {
  2135. if (strpos($textlib->strtolower($desc), $query) !== false) {
  2136. return true;
  2137. }
  2138. }
  2139. return false;
  2140. }
  2141. function output_html($data, $query='') {
  2142. if (!$this->load_choices() or empty($this->choices)) {
  2143. return '';
  2144. }
  2145. $choices = $this->choices;
  2146. $default = $this->get_defaultsetting();
  2147. if (is_null($default)) {
  2148. $default = array();
  2149. }
  2150. if (is_null($data)) {
  2151. $data = array();
  2152. }
  2153. $defaults = array();
  2154. $size = min(10, count($this->choices));
  2155. $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
  2156. $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="'.$size.'" multiple="multiple">';
  2157. foreach ($this->choices as $key => $description) {
  2158. if (in_array($key, $data)) {
  2159. $selected = 'selected="selected"';
  2160. } else {
  2161. $selected = '';
  2162. }
  2163. if (in_array($key, $default)) {
  2164. $defaults[] = $description;
  2165. }
  2166. $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
  2167. }
  2168. if (is_null($default)) {
  2169. $defaultinfo = NULL;
  2170. } if (!empty($defaults)) {
  2171. $defaultinfo = implode(', ', $defaults);
  2172. } else {
  2173. $defaultinfo = get_string('none');
  2174. }
  2175. $return .= '</select></div>';
  2176. return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
  2177. }
  2178. }
  2179. /**
  2180. * Time selector
  2181. * this is a liiitle bit messy. we're using two selects, but we're returning
  2182. * them as an array named after $name (so we only use $name2 internally for the setting)
  2183. */
  2184. class admin_setting_configtime extends admin_setting {
  2185. var $name2;
  2186. /**
  2187. * Constructor
  2188. * @param string $hoursname setting for hours
  2189. * @param string $minutesname setting for hours
  2190. * @param string $visiblename localised
  2191. * @param string $description long localised info
  2192. * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
  2193. */
  2194. function admin_setting_configtime($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
  2195. $this->name2 = $minutesname;
  2196. parent::admin_setting($hoursname, $visiblename, $description, $defaultsetting);
  2197. }
  2198. function get_setting() {
  2199. $result1 = $this->config_read($this->name);
  2200. $result2 = $this->config_read($this->name2);
  2201. if (is_null($result1) or is_null($result2)) {
  2202. return NULL;
  2203. }
  2204. return array('h' => $result1, 'm' => $result2);
  2205. }
  2206. function write_setting($data) {
  2207. if (!is_array($data)) {
  2208. return '';
  2209. }
  2210. $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
  2211. return ($result ? '' : get_string('errorsetting', 'admin'));
  2212. }
  2213. function output_html($data, $query='') {
  2214. $default = $this->get_defaultsetting();
  2215. if (is_array($default)) {
  2216. $defaultinfo = $default['h'].':'.$default['m'];
  2217. } else {
  2218. $defaultinfo = NULL;
  2219. }
  2220. $return = '<div class="form-time defaultsnext">'.
  2221. '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
  2222. for ($i = 0; $i < 24; $i++) {
  2223. $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
  2224. }
  2225. $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
  2226. for ($i = 0; $i < 60; $i += 5) {
  2227. $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
  2228. }
  2229. $return .= '</select></div>';
  2230. return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
  2231. }
  2232. }
  2233. /**
  2234. * An admin setting for selecting one or more users, who have a particular capability
  2235. * in the system context. Warning, make sure the list will never be too long. There is
  2236. * no paging or searching of this list.
  2237. *
  2238. * To correctly get a list of users from this config setting, you need to call the
  2239. * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php.
  2240. */
  2241. class admin_setting_users_with_capability extends admin_setting_configmultiselect {
  2242. var $capability;
  2243. /**
  2244. * Constructor.
  2245. *
  2246. * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
  2247. * @param string $visiblename localised name
  2248. * @param string $description localised long description
  2249. * @param array $defaultsetting array of usernames
  2250. * @param string $capability string capability name.
  2251. */
  2252. function admin_setting_users_with_capability($name, $visiblename, $description, $defaultsetting, $capability) {
  2253. $this->capability = $capability;
  2254. parent::admin_setting_configmultiselect($name, $visiblename, $description, $defaultsetting, NULL);
  2255. }
  2256. function load_choices() {
  2257. if (is_array($this->choices)) {
  2258. return true;
  2259. }
  2260. $users = get_users_by_capability(get_context_instance(CONTEXT_SYSTEM),
  2261. $this->capability, 'u.id,u.username,u.firstname,u.lastname', 'u.lastname,u.firstname');
  2262. $this->choices = array(
  2263. '$@NONE@$' => get_string('nobody'),
  2264. '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)),
  2265. );
  2266. if (is_array($users)) {
  2267. foreach ($users as $user) {
  2268. $this->choices[$user->username] = fullname($user);
  2269. }
  2270. }
  2271. return true;
  2272. }
  2273. function get_defaultsetting() {
  2274. $this->load_choices();
  2275. if (empty($this->defaultsetting)) {
  2276. return array('$@NONE@$');
  2277. } else if (array_key_exists($this->defaultsetting, $this->choices)) {
  2278. return $this->defaultsetting;
  2279. } else {
  2280. return '';
  2281. }
  2282. }
  2283. function get_setting() {
  2284. $result = parent::get_setting();
  2285. if (empty($result)) {
  2286. $result = array('$@NONE@$');
  2287. }
  2288. return $result;
  2289. }
  2290. function write_setting($data) {
  2291. // If all is selected, remove any explicit options.
  2292. if (in_array('$@ALL@$', $data)) {
  2293. $data = array('$@ALL@$');
  2294. }
  2295. // None never needs to be writted to the DB.
  2296. if (in_array('$@NONE@$', $data)) {
  2297. unset($data[array_search('$@NONE@$', $data)]);
  2298. }
  2299. return parent::write_setting($data);
  2300. }
  2301. }
  2302. /**
  2303. * Special checkbox for calendar - resets SESSION vars.
  2304. */
  2305. class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
  2306. function admin_setting_special_adminseesall() {
  2307. parent::admin_setting_configcheckbox('calendar_adminseesall', get_string('adminseesall', 'admin'),
  2308. get_string('helpadminseesall', 'admin'), '0');
  2309. }
  2310. function write_setting($data) {
  2311. global $SESSION;
  2312. unset($SESSION->cal_courses_shown);
  2313. return parent::write_setting($data);
  2314. }
  2315. }
  2316. /**
  2317. * Special select for settings that are altered in setup.php and can not be altered on the fly
  2318. */
  2319. class admin_setting_special_selectsetup extends admin_setting_configselect {
  2320. function get_setting() {
  2321. // read directly from db!
  2322. return get_config(NULL, $this->name);
  2323. }
  2324. function write_setting($data) {
  2325. global $CFG;
  2326. // do not change active CFG setting!
  2327. $current = $CFG->{$this->name};
  2328. $result = parent::write_setting($data);
  2329. $CFG->{$this->name} = $current;
  2330. return $result;
  2331. }
  2332. }
  2333. /**
  2334. * Special select for frontpage - stores data in course table
  2335. */
  2336. class admin_setting_sitesetselect extends admin_setting_configselect {
  2337. function get_setting() {
  2338. $site = get_site();
  2339. return $site->{$this->name};
  2340. }
  2341. function write_setting($data) {
  2342. global $SITE;
  2343. if (!in_array($data, array_keys($this->choices))) {
  2344. return get_string('errorsetting', 'admin');
  2345. }
  2346. $record = new stdClass();
  2347. $record->id = SITEID;
  2348. $temp = $this->name;
  2349. $record->$temp = $data;
  2350. $record->timemodified = time();
  2351. // update $SITE
  2352. $SITE->{$this->name} = $data;
  2353. return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
  2354. }
  2355. }
  2356. /**
  2357. * Special select - lists on the frontpage - hacky
  2358. */
  2359. class admin_setting_courselist_frontpage extends admin_setting {
  2360. var $choices;
  2361. function admin_setting_courselist_frontpage($loggedin) {
  2362. global $CFG;
  2363. require_once($CFG->dirroot.'/course/lib.php');
  2364. $name = 'frontpage'.($loggedin ? 'loggedin' : '');
  2365. $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
  2366. $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
  2367. $defaults = array(FRONTPAGECOURSELIST);
  2368. parent::admin_setting($name, $visiblename, $description, $defaults);
  2369. }
  2370. function load_choices() {
  2371. if (is_array($this->choices)) {
  2372. return true;
  2373. }
  2374. $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
  2375. FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
  2376. FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
  2377. FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
  2378. 'none' => get_string('none'));
  2379. if ($this->name == 'frontpage' and count_records('course') > FRONTPAGECOURSELIMIT) {
  2380. unset($this->choices[FRONTPAGECOURSELIST]);
  2381. }
  2382. return true;
  2383. }
  2384. function get_setting() {
  2385. $result = $this->config_read($this->name);
  2386. if (is_null($result)) {
  2387. return NULL;
  2388. }
  2389. if ($result === '') {
  2390. return array();
  2391. }
  2392. return explode(',', $result);
  2393. }
  2394. function write_setting($data) {
  2395. if (!is_array($data)) {
  2396. return '';
  2397. }
  2398. $this->load_choices();
  2399. $save = array();
  2400. foreach($data as $datum) {
  2401. if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
  2402. continue;
  2403. }
  2404. $save[$datum] = $datum; // no duplicates
  2405. }
  2406. return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
  2407. }
  2408. function output_html($data, $query='') {
  2409. $this->load_choices();
  2410. $currentsetting = array();
  2411. foreach ($data as $key) {
  2412. if ($key != 'none' and array_key_exists($key, $this->choices)) {
  2413. $currentsetting[] = $key; // already selected first
  2414. }
  2415. }
  2416. $return = '<div class="form-group">';
  2417. for ($i = 0; $i < count($this->choices) - 1; $i++) {
  2418. if (!array_key_exists($i, $currentsetting)) {
  2419. $currentsetting[$i] = 'none'; //none
  2420. }
  2421. $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
  2422. foreach ($this->choices as $key => $value) {
  2423. $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
  2424. }
  2425. $return .= '</select>';
  2426. if ($i !== count($this->choices) - 2) {
  2427. $return .= '<br />';
  2428. }
  2429. }
  2430. $return .= '</div>';
  2431. return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
  2432. }
  2433. }
  2434. /**
  2435. * Special checkbox for frontpage - stores data in course table
  2436. */
  2437. class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
  2438. function get_setting() {
  2439. $site = get_site();
  2440. return $site->{$this->name};
  2441. }
  2442. function write_setting($data) {
  2443. global $SITE;
  2444. $record = new object();
  2445. $record->id = SITEID;
  2446. $record->{$this->name} = ($data == '1' ? 1 : 0);
  2447. $record->timemodified = time();
  2448. // update $SITE
  2449. $SITE->{$this->name} = $data;
  2450. return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
  2451. }
  2452. }
  2453. /**
  2454. * Special text for frontpage - stores data in course table.
  2455. * Empty string means not set here. Manual setting is required.
  2456. */
  2457. class admin_setting_sitesettext extends admin_setting_configtext {
  2458. function get_setting() {
  2459. $site = get_site();
  2460. return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
  2461. }
  2462. function validate($data) {
  2463. $cleaned = stripslashes(clean_param(addslashes($data), PARAM_MULTILANG));
  2464. if ($cleaned === '') {
  2465. return get_string('required');
  2466. }
  2467. if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
  2468. return true;
  2469. } else {
  2470. return get_string('validateerror', 'admin');
  2471. }
  2472. }
  2473. function write_setting($data) {
  2474. global $SITE;
  2475. $data = trim($data);
  2476. $validated = $this->validate($data);
  2477. if ($validated !== true) {
  2478. return $validated;
  2479. }
  2480. $record = new object();
  2481. $record->id = SITEID;
  2482. $record->{$this->name} = addslashes($data);
  2483. $record->timemodified = time();
  2484. // update $SITE
  2485. $SITE->{$this->name} = $data;
  2486. return (update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
  2487. }
  2488. }
  2489. /**
  2490. * Special text editor for site description.
  2491. */
  2492. class admin_setting_special_frontpagedesc extends admin_setting {
  2493. function admin_setting_special_frontpagedesc() {
  2494. parent::admin_setting('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
  2495. }
  2496. function get_setting() {
  2497. $site = get_site();
  2498. return $site->{$this->name};
  2499. }
  2500. function write_setting($data) {
  2501. global $SITE;
  2502. $record = new object();
  2503. $record->id = SITEID;
  2504. $record->{$this->name} = addslashes($data);
  2505. $record->timemodified = time();
  2506. $SITE->{$this->name} = $data;
  2507. return (update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
  2508. }
  2509. function output_html($data, $query='') {
  2510. global $CFG;
  2511. $CFG->adminusehtmleditor = can_use_html_editor();
  2512. $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true).'</div>';
  2513. return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
  2514. }
  2515. }
  2516. class admin_setting_special_editorfontlist extends admin_setting {
  2517. var $items;
  2518. function admin_setting_special_editorfontlist() {
  2519. global $CFG;
  2520. $name = 'editorfontlist';
  2521. $visiblename = get_string('editorfontlist', 'admin');
  2522. $description = get_string('configeditorfontlist', 'admin');
  2523. $defaults = array('k0' => 'Trebuchet',
  2524. 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
  2525. 'k1' => 'Arial',
  2526. 'v1' => 'arial,helvetica,sans-serif',
  2527. 'k2' => 'Courier New',
  2528. 'v2' => 'courier new,courier,monospace',
  2529. 'k3' => 'Georgia',
  2530. 'v3' => 'georgia,times new roman,times,serif',
  2531. 'k4' => 'Tahoma',
  2532. 'v4' => 'tahoma,arial,helvetica,sans-serif',
  2533. 'k5' => 'Times New Roman',
  2534. 'v5' => 'times new roman,times,serif',
  2535. 'k6' => 'Verdana',
  2536. 'v6' => 'verdana,arial,helvetica,sans-serif',
  2537. 'k7' => 'Impact',
  2538. 'v7' => 'impact',
  2539. 'k8' => 'Wingdings',
  2540. 'v8' => 'wingdings');
  2541. parent::admin_setting($name, $visiblename, $description, $defaults);
  2542. }
  2543. function get_setting() {
  2544. global $CFG;
  2545. $result = $this->config_read($this->name);
  2546. if (is_null($result)) {
  2547. return NULL;
  2548. }
  2549. $i = 0;
  2550. $currentsetting = array();
  2551. $items = explode(';', $result);
  2552. foreach ($items as $item) {
  2553. $item = explode(':', $item);
  2554. $currentsetting['k'.$i] = $item[0];
  2555. $currentsetting['v'.$i] = $item[1];
  2556. $i++;
  2557. }
  2558. return $currentsetting;
  2559. }
  2560. function write_setting($data) {
  2561. // there miiight be an easier way to do this :)
  2562. // if this is changed, make sure the $defaults array above is modified so that this
  2563. // function processes it correctly
  2564. $keys = array();
  2565. $values = array();
  2566. foreach ($data as $key => $value) {
  2567. if (substr($key,0,1) == 'k') {
  2568. $keys[substr($key,1)] = $value;
  2569. } elseif (substr($key,0,1) == 'v') {
  2570. $values[substr($key,1)] = $value;
  2571. }
  2572. }
  2573. $result = array();
  2574. for ($i = 0; $i < count($keys); $i++) {
  2575. if (($keys[$i] !== '') && ($values[$i] !== '')) {
  2576. $result[] = clean_param($keys[$i],PARAM_NOTAGS).':'.clean_param($values[$i], PARAM_NOTAGS);
  2577. }
  2578. }
  2579. return ($this->config_write($this->name, implode(';', $result)) ? '' : get_string('errorsetting', 'admin'));
  2580. }
  2581. function output_html($data, $query='') {
  2582. $fullname = $this->get_full_name();
  2583. $return = '<div class="form-group">';
  2584. for ($i = 0; $i < count($data) / 2; $i++) {
  2585. $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
  2586. $return .= '&nbsp;&nbsp;';
  2587. $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
  2588. }
  2589. $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
  2590. $return .= '&nbsp;&nbsp;';
  2591. $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
  2592. $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
  2593. $return .= '&nbsp;&nbsp;';
  2594. $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
  2595. $return .= '</div>';
  2596. return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
  2597. }
  2598. }
  2599. class admin_setting_emoticons extends admin_setting {
  2600. var $items;
  2601. function admin_setting_emoticons() {
  2602. global $CFG;
  2603. $name = 'emoticons';
  2604. $visiblename = get_string('emoticons', 'admin');
  2605. $description = get_string('configemoticons', 'admin');
  2606. $defaults = array('k0' => ':-)',
  2607. 'v0' => 'smiley',
  2608. 'k1' => ':)',
  2609. 'v1' => 'smiley',
  2610. 'k2' => ':-D',
  2611. 'v2' => 'biggrin',
  2612. 'k3' => ';-)',
  2613. 'v3' => 'wink',
  2614. 'k4' => ':-/',
  2615. 'v4' => 'mixed',
  2616. 'k5' => 'V-.',
  2617. 'v5' => 'thoughtful',
  2618. 'k6' => ':-P',
  2619. 'v6' => 'tongueout',
  2620. 'k7' => 'B-)',
  2621. 'v7' => 'cool',
  2622. 'k8' => '^-)',
  2623. 'v8' => 'approve',
  2624. 'k9' => '8-)',
  2625. 'v9' => 'wideeyes',
  2626. 'k10' => ':o)',
  2627. 'v10' => 'clown',
  2628. 'k11' => ':-(',
  2629. 'v11' => 'sad',
  2630. 'k12' => ':(',
  2631. 'v12' => 'sad',
  2632. 'k13' => '8-.',
  2633. 'v13' => 'shy',
  2634. 'k14' => ':-I',
  2635. 'v14' => 'blush',
  2636. 'k15' => ':-X',
  2637. 'v15' => 'kiss',
  2638. 'k16' => '8-o',
  2639. 'v16' => 'surprise',
  2640. 'k17' => 'P-|',
  2641. 'v17' => 'blackeye',
  2642. 'k18' => '8-[',
  2643. 'v18' => 'angry',
  2644. 'k19' => 'xx-P',
  2645. 'v19' => 'dead',
  2646. 'k20' => '|-.',
  2647. 'v20' => 'sleepy',
  2648. 'k21' => '}-]',
  2649. 'v21' => 'evil',
  2650. 'k22' => '(h)',
  2651. 'v22' => 'heart',
  2652. 'k23' => '(heart)',
  2653. 'v23' => 'heart',
  2654. 'k24' => '(y)',
  2655. 'v24' => 'yes',
  2656. 'k25' => '(n)',
  2657. 'v25' => 'no',
  2658. 'k26' => '(martin)',
  2659. 'v26' => 'martin',
  2660. 'k27' => '( )',
  2661. 'v27' => 'egg');
  2662. parent::admin_setting($name, $visiblename, $description, $defaults);
  2663. }
  2664. function get_setting() {
  2665. global $CFG;
  2666. $result = $this->config_read($this->name);
  2667. if (is_null($result)) {
  2668. return NULL;
  2669. }
  2670. $i = 0;
  2671. $currentsetting = array();
  2672. $items = explode('{;}', $result);
  2673. foreach ($items as $item) {
  2674. $item = explode('{:}', $item);
  2675. $currentsetting['k'.$i] = $item[0];
  2676. $currentsetting['v'.$i] = $item[1];
  2677. $i++;
  2678. }
  2679. return $currentsetting;
  2680. }
  2681. function write_setting($data) {
  2682. // there miiight be an easier way to do this :)
  2683. // if this is changed, make sure the $defaults array above is modified so that this
  2684. // function processes it correctly
  2685. $keys = array();
  2686. $values = array();
  2687. foreach ($data as $key => $value) {
  2688. if (substr($key,0,1) == 'k') {
  2689. $keys[substr($key,1)] = $value;
  2690. } elseif (substr($key,0,1) == 'v') {
  2691. $values[substr($key,1)] = $value;
  2692. }
  2693. }
  2694. $result = array();
  2695. for ($i = 0; $i < count($keys); $i++) {
  2696. if (($keys[$i] !== '') && ($values[$i] !== '')) {
  2697. $result[] = clean_param($keys[$i],PARAM_NOTAGS).'{:}'.clean_param($values[$i], PARAM_NOTAGS);
  2698. }
  2699. }
  2700. return ($this->config_write($this->name, implode('{;}', $result)) ? '' : get_string('errorsetting', 'admin').$this->visiblename.'<br />');
  2701. }
  2702. function output_html($data, $query='') {
  2703. $fullname = $this->get_full_name();
  2704. $return = '<div class="form-group">';
  2705. for ($i = 0; $i < count($data) / 2; $i++) {
  2706. $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
  2707. $return .= '&nbsp;&nbsp;';
  2708. $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
  2709. }
  2710. $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
  2711. $return .= '&nbsp;&nbsp;';
  2712. $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
  2713. $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
  2714. $return .= '&nbsp;&nbsp;';
  2715. $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
  2716. $return .= '</div>';
  2717. return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
  2718. }
  2719. }
  2720. /**
  2721. * Setting for spellchecker language selection.
  2722. */
  2723. class admin_setting_special_editordictionary extends admin_setting_configselect {
  2724. function admin_setting_special_editordictionary() {
  2725. $name = 'editordictionary';
  2726. $visiblename = get_string('editordictionary','admin');
  2727. $description = get_string('configeditordictionary', 'admin');
  2728. parent::admin_setting_configselect($name, $visiblename, $description, '', NULL);
  2729. }
  2730. function load_choices() {
  2731. // function borrowed from the old moodle/admin/editor.php, slightly modified
  2732. // Get all installed dictionaries in the system
  2733. if (is_array($this->choices)) {
  2734. return true;
  2735. }
  2736. $this->choices = array();
  2737. global $CFG;
  2738. clearstatcache();
  2739. // If aspellpath isn't set don't even bother ;-)
  2740. if (empty($CFG->aspellpath)) {
  2741. $this->choices['error'] = 'Empty aspell path!';
  2742. return true;
  2743. }
  2744. // Do we have access to popen function?
  2745. if (!function_exists('popen')) {
  2746. $this->choices['error'] = 'Popen function disabled!';
  2747. return true;
  2748. }
  2749. $cmd = $CFG->aspellpath;
  2750. $output = '';
  2751. $dictionaries = array();
  2752. if(!($handle = @popen(escapeshellarg($cmd).' dump dicts', 'r'))) {
  2753. $this->choices['error'] = 'Couldn\'t create handle!';
  2754. }
  2755. while(!feof($handle)) {
  2756. $output .= fread($handle, 1024);
  2757. }
  2758. @pclose($handle);
  2759. $dictionaries = explode(chr(10), $output);
  2760. foreach ($dictionaries as $dict) {
  2761. if (empty($dict)) {
  2762. continue;
  2763. }
  2764. $this->choices[$dict] = $dict;
  2765. }
  2766. if (empty($this->choices)) {
  2767. $this->choices['error'] = 'Error! Check your aspell installation!';
  2768. }
  2769. return true;
  2770. }
  2771. }
  2772. class admin_setting_special_editorhidebuttons extends admin_setting {
  2773. var $items;
  2774. function admin_setting_special_editorhidebuttons() {
  2775. parent::admin_setting('editorhidebuttons', get_string('editorhidebuttons', 'admin'),
  2776. get_string('confeditorhidebuttons', 'admin'), array());
  2777. // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
  2778. $this->items = array('fontname' => '',
  2779. 'fontsize' => '',
  2780. 'formatblock' => '',
  2781. 'bold' => 'ed_format_bold.gif',
  2782. 'italic' => 'ed_format_italic.gif',
  2783. 'underline' => 'ed_format_underline.gif',
  2784. 'strikethrough' => 'ed_format_strike.gif',
  2785. 'subscript' => 'ed_format_sub.gif',
  2786. 'superscript' => 'ed_format_sup.gif',
  2787. 'copy' => 'ed_copy.gif',
  2788. 'cut' => 'ed_cut.gif',
  2789. 'paste' => 'ed_paste.gif',
  2790. 'clean' => 'ed_wordclean.gif',
  2791. 'undo' => 'ed_undo.gif',
  2792. 'redo' => 'ed_redo.gif',
  2793. 'justifyleft' => 'ed_align_left.gif',
  2794. 'justifycenter' => 'ed_align_center.gif',
  2795. 'justifyright' => 'ed_align_right.gif',
  2796. 'justifyfull' => 'ed_align_justify.gif',
  2797. 'lefttoright' => 'ed_left_to_right.gif',
  2798. 'righttoleft' => 'ed_right_to_left.gif',
  2799. 'insertorderedlist' => 'ed_list_num.gif',
  2800. 'insertunorderedlist' => 'ed_list_bullet.gif',
  2801. 'outdent' => 'ed_indent_less.gif',
  2802. 'indent' => 'ed_indent_more.gif',
  2803. 'forecolor' => 'ed_color_fg.gif',
  2804. 'hilitecolor' => 'ed_color_bg.gif',
  2805. 'inserthorizontalrule' => 'ed_hr.gif',
  2806. 'createanchor' => 'ed_anchor.gif',
  2807. 'createlink' => 'ed_link.gif',
  2808. 'unlink' => 'ed_unlink.gif',
  2809. 'insertimage' => 'ed_image.gif',
  2810. 'inserttable' => 'insert_table.gif',
  2811. 'insertsmile' => 'em.icon.smile.gif',
  2812. 'insertchar' => 'icon_ins_char.gif',
  2813. 'spellcheck' => 'spell-check.gif',
  2814. 'htmlmode' => 'ed_html.gif',
  2815. 'popupeditor' => 'fullscreen_maximize.gif',
  2816. 'search_replace' => 'ed_replace.gif');
  2817. }
  2818. function get_setting() {
  2819. $result = $this->config_read($this->name);
  2820. if (is_null($result)) {
  2821. return NULL;
  2822. }
  2823. if ($result === '') {
  2824. return array();
  2825. }
  2826. return explode(' ', $result);
  2827. }
  2828. function write_setting($data) {
  2829. if (!is_array($data)) {
  2830. return ''; // ignore it
  2831. }
  2832. unset($data['xxxxx']);
  2833. $result = array();
  2834. foreach ($data as $key => $value) {
  2835. if (!isset($this->items[$key])) {
  2836. return get_string('errorsetting', 'admin');
  2837. }
  2838. if ($value == '1') {
  2839. $result[] = $key;
  2840. }
  2841. }
  2842. return ($this->config_write($this->name, implode(' ', $result)) ? '' : get_string('errorsetting', 'admin'));
  2843. }
  2844. function output_html($data, $query='') {
  2845. global $CFG;
  2846. // checkboxes with input name="$this->name[$key]" value="1"
  2847. // we do 15 fields per column
  2848. $return = '<div class="form-group">';
  2849. $return .= '<table><tr><td valign="top" align="right">';
  2850. $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
  2851. $count = 0;
  2852. foreach($this->items as $key => $value) {
  2853. if ($count % 15 == 0 and $count != 0) {
  2854. $return .= '</td><td valign="top" align="right">';
  2855. }
  2856. $return .= '<label for="'.$this->get_id().$key.'">';
  2857. $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;';
  2858. $return .= '<input type="checkbox" class="form-checkbox" value="1" id="'.$this->get_id().$key.'" name="'.$this->get_full_name().'['.$key.']"'.(in_array($key,$data) ? ' checked="checked"' : '').' />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
  2859. $return .= '</label>';
  2860. $count++;
  2861. if ($count % 15 != 0) {
  2862. $return .= '<br /><br />';
  2863. }
  2864. }
  2865. $return .= '</td></tr>';
  2866. $return .= '</table>';
  2867. $return .= '</div>';
  2868. return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
  2869. }
  2870. }
  2871. /**
  2872. * Special setting for limiting of the list of available languages.
  2873. */
  2874. class admin_setting_langlist extends admin_setting_configtext {
  2875. function admin_setting_langlist() {
  2876. parent::admin_setting_configtext('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
  2877. }
  2878. function write_setting($data) {
  2879. $return = parent::write_setting($data);
  2880. get_list_of_languages(true);//refresh the list
  2881. return $return;
  2882. }
  2883. }
  2884. /**
  2885. * Course category selection
  2886. */
  2887. class admin_settings_coursecat_select extends admin_setting_configselect {
  2888. function admin_settings_coursecat_select($name, $visiblename, $description, $defaultsetting) {
  2889. parent::admin_setting_configselect($name, $visiblename, $description, $defaultsetting, NULL);
  2890. }
  2891. function load_choices() {
  2892. global $CFG;
  2893. require_once($CFG->dirroot.'/course/lib.php');
  2894. if (is_array($this->choices)) {
  2895. return true;
  2896. }
  2897. $this->choices = make_categories_options();
  2898. return true;
  2899. }
  2900. }
  2901. class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
  2902. function admin_setting_special_backupdays() {
  2903. parent::admin_setting_configmulticheckbox2('backup_sche_weekdays', get_string('schedule'), get_string('backupschedulehelp'), array(), NULL);
  2904. $this->plugin = 'backup';
  2905. }
  2906. function load_choices() {
  2907. if (is_array($this->choices)) {
  2908. return true;
  2909. }
  2910. $this->choices = array();
  2911. $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
  2912. foreach ($days as $day) {
  2913. $this->choices[$day] = get_string($day, 'calendar');
  2914. }
  2915. return true;
  2916. }
  2917. }
  2918. /**
  2919. * Special debug setting
  2920. */
  2921. class admin_setting_special_debug extends admin_setting_configselect {
  2922. function admin_setting_special_debug() {
  2923. parent::admin_setting_configselect('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
  2924. }
  2925. function load_choices() {
  2926. if (is_array($this->choices)) {
  2927. return true;
  2928. }
  2929. $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
  2930. DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
  2931. DEBUG_NORMAL => get_string('debugnormal', 'admin'),
  2932. DEBUG_ALL => get_string('debugall', 'admin'),
  2933. DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
  2934. return true;
  2935. }
  2936. }
  2937. class admin_setting_special_calendar_weekend extends admin_setting {
  2938. function admin_setting_special_calendar_weekend() {
  2939. $name = 'calendar_weekend';
  2940. $visiblename = get_string('calendar_weekend', 'admin');
  2941. $description = get_string('helpweekenddays', 'admin');
  2942. $default = array ('0', '6'); // Saturdays and Sundays
  2943. parent::admin_setting($name, $visiblename, $description, $default);
  2944. }
  2945. function get_setting() {
  2946. $result = $this->config_read($this->name);
  2947. if (is_null($result)) {
  2948. return NULL;
  2949. }
  2950. if ($result === '') {
  2951. return array();
  2952. }
  2953. $settings = array();
  2954. for ($i=0; $i<7; $i++) {
  2955. if ($result & (1 << $i)) {
  2956. $settings[] = $i;
  2957. }
  2958. }
  2959. return $settings;
  2960. }
  2961. function write_setting($data) {
  2962. if (!is_array($data)) {
  2963. return '';
  2964. }
  2965. unset($data['xxxxx']);
  2966. $result = 0;
  2967. foreach($data as $index) {
  2968. $result |= 1 << $index;
  2969. }
  2970. return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
  2971. }
  2972. function output_html($data, $query='') {
  2973. // The order matters very much because of the implied numeric keys
  2974. $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
  2975. $return = '<table><thead><tr>';
  2976. $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
  2977. foreach($days as $index => $day) {
  2978. $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>';
  2979. }
  2980. $return .= '</tr></thead><tbody><tr>';
  2981. foreach($days as $index => $day) {
  2982. $return .= '<td><input type="checkbox" class="form-checkbox" id="'.$this->get_id().$index.'" name="'.$this->get_full_name().'[]" value="'.$index.'" '.(in_array("$index", $data) ? 'checked="checked"' : '').' /></td>';
  2983. }
  2984. $return .= '</tr></tbody></table>';
  2985. return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
  2986. }
  2987. }
  2988. /**
  2989. * Graded roles in gradebook
  2990. */
  2991. class admin_setting_special_gradebookroles extends admin_setting_configmulticheckbox {
  2992. function admin_setting_special_gradebookroles() {
  2993. parent::admin_setting_configmulticheckbox('gradebookroles', get_string('gradebookroles', 'admin'),
  2994. get_string('configgradebookroles', 'admin'), NULL, NULL);
  2995. }
  2996. function load_choices() {
  2997. global $CFG;
  2998. if (empty($CFG->rolesactive)) {
  2999. return false;
  3000. }
  3001. if (is_array($this->choices)) {
  3002. return true;
  3003. }
  3004. if ($roles = get_records('role')) {
  3005. $this->choices = array();
  3006. foreach($roles as $role) {
  3007. $this->choices[$role->id] = format_string($role->name);
  3008. }
  3009. return true;
  3010. } else {
  3011. return false;
  3012. }
  3013. }
  3014. function get_defaultsetting() {
  3015. global $CFG;
  3016. if (empty($CFG->rolesactive)) {
  3017. return NULL;
  3018. }
  3019. $result = array();
  3020. if ($studentroles = get_roles_with_capability('moodle/legacy:student', CAP_ALLOW)) {
  3021. foreach ($studentroles as $studentrole) {
  3022. $result[$studentrole->id] = '1';
  3023. }
  3024. }
  3025. return $result;
  3026. }
  3027. }
  3028. class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
  3029. function write_setting($data) {
  3030. global $CFG;
  3031. $oldvalue = $this->config_read($this->name);
  3032. $return = parent::write_setting($data);
  3033. $newvalue = $this->config_read($this->name);
  3034. if ($oldvalue !== $newvalue) {
  3035. // force full regrading
  3036. set_field('grade_items', 'needsupdate', 1, 'needsupdate', 0);
  3037. }
  3038. return $return;
  3039. }
  3040. }
  3041. /**
  3042. * Which roles to show on course decription page
  3043. */
  3044. class admin_setting_special_coursemanager extends admin_setting_configmulticheckbox {
  3045. function admin_setting_special_coursemanager() {
  3046. parent::admin_setting_configmulticheckbox('coursemanager', get_string('coursemanager', 'admin'),
  3047. get_string('configcoursemanager', 'admin'), NULL, NULL);
  3048. }
  3049. function load_choices() {
  3050. if (is_array($this->choices)) {
  3051. return true;
  3052. }
  3053. if ($roles = get_records('role','','','sortorder')) {
  3054. $this->choices = array();
  3055. foreach($roles as $role) {
  3056. $this->choices[$role->id] = format_string($role->name);
  3057. }
  3058. return true;
  3059. }
  3060. return false;
  3061. }
  3062. function get_defaultsetting() {
  3063. global $CFG;
  3064. if (empty($CFG->rolesactive)) {
  3065. return NULL;
  3066. }
  3067. $result = array();
  3068. if ($teacherroles = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW)) {
  3069. foreach ($teacherroles as $teacherrole) {
  3070. $result[$teacherrole->id] = '1';
  3071. }
  3072. }
  3073. return $result;
  3074. }
  3075. }
  3076. class admin_setting_special_gradelimiting extends admin_setting_configcheckbox {
  3077. function admin_setting_special_gradelimiting() {
  3078. parent::admin_setting_configcheckbox('unlimitedgrades', get_string('unlimitedgrades', 'grades'),
  3079. get_string('configunlimitedgrades', 'grades'), '0', '1', '0');
  3080. }
  3081. function regrade_all() {
  3082. global $CFG;
  3083. require_once("$CFG->libdir/gradelib.php");
  3084. grade_force_site_regrading();
  3085. }
  3086. function write_setting($data) {
  3087. $previous = $this->get_setting();
  3088. if ($previous === null) {
  3089. if ($data) {
  3090. $this->regrade_all();
  3091. }
  3092. } else {
  3093. if ($data != $previous) {
  3094. $this->regrade_all();
  3095. }
  3096. }
  3097. return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
  3098. }
  3099. }
  3100. /**
  3101. * Primary grade export plugin - has state tracking.
  3102. */
  3103. class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
  3104. function admin_setting_special_gradeexport() {
  3105. parent::admin_setting_configmulticheckbox('gradeexport', get_string('gradeexport', 'admin'),
  3106. get_string('configgradeexport', 'admin'), array(), NULL);
  3107. }
  3108. function load_choices() {
  3109. if (is_array($this->choices)) {
  3110. return true;
  3111. }
  3112. $this->choices = array();
  3113. if ($plugins = get_list_of_plugins('grade/export')) {
  3114. foreach($plugins as $plugin) {
  3115. $this->choices[$plugin] = get_string('modulename', 'gradeexport_'.$plugin);
  3116. }
  3117. }
  3118. return true;
  3119. }
  3120. }
  3121. /**
  3122. * Grade category settings
  3123. */
  3124. class admin_setting_gradecat_combo extends admin_setting {
  3125. var $choices;
  3126. function admin_setting_gradecat_combo($name, $visiblename, $description, $defaultsetting, $choices) {
  3127. $this->choices = $choices;
  3128. parent::admin_setting($name, $visiblename, $description, $defaultsetting);
  3129. }
  3130. function get_setting() {
  3131. global $CFG;
  3132. $value = $this->config_read($this->name);
  3133. $flag = $this->config_read($this->name.'_flag');
  3134. if (is_null($value) or is_null($flag)) {
  3135. return NULL;
  3136. }
  3137. $flag = (int)$flag;
  3138. $forced = (boolean)(1 & $flag); // first bit
  3139. $adv = (boolean)(2 & $flag); // second bit
  3140. return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
  3141. }
  3142. function write_setting($data) {
  3143. global $CFG;
  3144. $value = $data['value'];
  3145. $forced = empty($data['forced']) ? 0 : 1;
  3146. $adv = empty($data['adv']) ? 0 : 2;
  3147. $flag = ($forced | $adv); //bitwise or
  3148. if (!in_array($value, array_keys($this->choices))) {
  3149. return 'Error setting ';
  3150. }
  3151. $oldvalue = $this->config_read($this->name);
  3152. $oldflag = (int)$this->config_read($this->name.'_flag');
  3153. $oldforced = (1 & $oldflag); // first bit
  3154. $result1 = $this->config_write($this->name, $value);
  3155. $result2 = $this->config_write($this->name.'_flag', $flag);
  3156. // force regrade if needed
  3157. if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
  3158. require_once($CFG->libdir.'/gradelib.php');
  3159. grade_category::updated_forced_settings();
  3160. }
  3161. if ($result1 and $result2) {
  3162. return '';
  3163. } else {
  3164. return get_string('errorsetting', 'admin');
  3165. }
  3166. }
  3167. function output_html($data, $query='') {
  3168. $value = $data['value'];
  3169. $forced = !empty($data['forced']);
  3170. $adv = !empty($data['adv']);
  3171. $default = $this->get_defaultsetting();
  3172. if (!is_null($default)) {
  3173. $defaultinfo = array();
  3174. if (isset($this->choices[$default['value']])) {
  3175. $defaultinfo[] = $this->choices[$default['value']];
  3176. }
  3177. if (!empty($default['forced'])) {
  3178. $defaultinfo[] = get_string('force');
  3179. }
  3180. if (!empty($default['adv'])) {
  3181. $defaultinfo[] = get_string('advanced');
  3182. }
  3183. $defaultinfo = implode(', ', $defaultinfo);
  3184. } else {
  3185. $defaultinfo = NULL;
  3186. }
  3187. $return = '<div class="form-group">';
  3188. $return .= '<select class="form-select" id="'.$this->get_id().'" name="'.$this->get_full_name().'[value]">';
  3189. foreach ($this->choices as $key => $val) {
  3190. // the string cast is needed because key may be integer - 0 is equal to most strings!
  3191. $return .= '<option value="'.$key.'"'.((string)$key==$value ? ' selected="selected"' : '').'>'.$val.'</option>';
  3192. }
  3193. $return .= '</select>';
  3194. $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'force" name="'.$this->get_full_name().'[forced]" value="1" '.($forced ? 'checked="checked"' : '').' />'
  3195. .'<label for="'.$this->get_id().'force">'.get_string('force').'</label>';
  3196. $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'adv" name="'.$this->get_full_name().'[adv]" value="1" '.($adv ? 'checked="checked"' : '').' />'
  3197. .'<label for="'.$this->get_id().'adv">'.get_string('advanced').'</label>';
  3198. $return .= '</div>';
  3199. return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
  3200. }
  3201. }
  3202. /**
  3203. * Selection of grade report in user profiles
  3204. */
  3205. class admin_setting_grade_profilereport extends admin_setting_configselect {
  3206. function admin_setting_grade_profilereport() {
  3207. parent::admin_setting_configselect('grade_profilereport', get_string('profilereport', 'grades'), get_string('configprofilereport', 'grades'), 'user', null);
  3208. }
  3209. function load_choices() {
  3210. if (is_array($this->choices)) {
  3211. return true;
  3212. }
  3213. $this->choices = array();
  3214. global $CFG;
  3215. require_once($CFG->libdir.'/gradelib.php');
  3216. foreach (get_list_of_plugins('grade/report') as $plugin) {
  3217. if (file_exists($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php')) {
  3218. require_once($CFG->dirroot.'/grade/report/'.$plugin.'/lib.php');
  3219. $functionname = 'grade_report_'.$plugin.'_profilereport';
  3220. if (function_exists($functionname)) {
  3221. $this->choices[$plugin] = get_string('modulename', 'gradereport_'.$plugin, NULL, $CFG->dirroot.'/grade/report/'.$plugin.'/lang/');
  3222. }
  3223. }
  3224. }
  3225. return true;
  3226. }
  3227. }
  3228. /**
  3229. * Special class for register auth selection
  3230. */
  3231. class admin_setting_special_registerauth extends admin_setting_configselect {
  3232. function admin_setting_special_registerauth() {
  3233. parent::admin_setting_configselect('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null);
  3234. }
  3235. function get_defaultsettings() {
  3236. $this->load_choices();
  3237. if (array_key_exists($this->defaultsetting, $this->choices)) {
  3238. return $this->defaultsetting;
  3239. } else {
  3240. return '';
  3241. }
  3242. }
  3243. function load_choices() {
  3244. global $CFG;
  3245. if (is_array($this->choices)) {
  3246. return true;
  3247. }
  3248. $this->choices = array();
  3249. $this->choices[''] = get_string('disable');
  3250. $authsenabled = get_enabled_auth_plugins(true);
  3251. foreach ($authsenabled as $auth) {
  3252. $authplugin = get_auth_plugin($auth);
  3253. if (!$authplugin->can_signup()) {
  3254. continue;
  3255. }
  3256. // Get the auth title (from core or own auth lang files)
  3257. $authtitle = $authplugin->get_title();
  3258. $this->choices[$auth] = $authtitle;
  3259. }
  3260. return true;
  3261. }
  3262. }
  3263. /**
  3264. * Module manage page
  3265. */
  3266. class admin_page_managemods extends admin_externalpage {
  3267. function admin_page_managemods() {
  3268. global $CFG;
  3269. parent::admin_externalpage('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
  3270. }
  3271. function search($query) {
  3272. if ($result = parent::search($query)) {
  3273. return $result;
  3274. }
  3275. $found = false;
  3276. if ($modules = get_records('modules')) {
  3277. $textlib = textlib_get_instance();
  3278. foreach ($modules as $module) {
  3279. if (strpos($module->name, $query) !== false) {
  3280. $found = true;
  3281. break;
  3282. }
  3283. $strmodulename = get_string('modulename', $module->name);
  3284. if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
  3285. $found = true;
  3286. break;
  3287. }
  3288. }
  3289. }
  3290. if ($found) {
  3291. $result = new object();
  3292. $result->page = $this;
  3293. $result->settings = array();
  3294. return array($this->name => $result);
  3295. } else {
  3296. return array();
  3297. }
  3298. }
  3299. }
  3300. /**
  3301. * Enrolment manage page
  3302. */
  3303. class admin_enrolment_page extends admin_externalpage {
  3304. function admin_enrolment_page() {
  3305. global $CFG;
  3306. parent::admin_externalpage('enrolment', get_string('enrolments'), $CFG->wwwroot . '/'.$CFG->admin.'/enrol.php');
  3307. }
  3308. function search($query) {
  3309. if ($result = parent::search($query)) {
  3310. return $result;
  3311. }
  3312. $found = false;
  3313. if ($modules = get_list_of_plugins('enrol')) {
  3314. $textlib = textlib_get_instance();
  3315. foreach ($modules as $plugin) {
  3316. if (strpos($plugin, $query) !== false) {
  3317. $found = true;
  3318. break;
  3319. }
  3320. $strmodulename = get_string('enrolname', "enrol_$plugin");
  3321. if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
  3322. $found = true;
  3323. break;
  3324. }
  3325. }
  3326. }
  3327. //ugly harcoded hacks
  3328. if (strpos('sendcoursewelcomemessage', $query) !== false) {
  3329. $found = true;
  3330. } else if (strpos($textlib->strtolower(get_string('sendcoursewelcomemessage', 'admin')), $query) !== false) {
  3331. $found = true;
  3332. } else if (strpos($textlib->strtolower(get_string('configsendcoursewelcomemessage', 'admin')), $query) !== false) {
  3333. $found = true;
  3334. } else if (strpos($textlib->strtolower(get_string('configenrolmentplugins', 'admin')), $query) !== false) {
  3335. $found = true;
  3336. }
  3337. if ($found) {
  3338. $result = new object();
  3339. $result->page = $this;
  3340. $result->settings = array();
  3341. return array($this->name => $result);
  3342. } else {
  3343. return array();
  3344. }
  3345. }
  3346. }
  3347. /**
  3348. * Blocks manage page
  3349. */
  3350. class admin_page_manageblocks extends admin_externalpage {
  3351. function admin_page_manageblocks() {
  3352. global $CFG;
  3353. parent::admin_externalpage('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
  3354. }
  3355. function search($query) {
  3356. global $CFG;
  3357. if ($result = parent::search($query)) {
  3358. return $result;
  3359. }
  3360. $found = false;
  3361. if (!empty($CFG->blocks_version) and $blocks = get_records('block')) {
  3362. $textlib = textlib_get_instance();
  3363. foreach ($blocks as $block) {
  3364. if (strpos($block->name, $query) !== false) {
  3365. $found = true;
  3366. break;
  3367. }
  3368. $strblockname = get_string('blockname', 'block_'.$block->name);
  3369. if (strpos($textlib->strtolower($strblockname), $query) !== false) {
  3370. $found = true;
  3371. break;
  3372. }
  3373. }
  3374. }
  3375. if ($found) {
  3376. $result = new object();
  3377. $result->page = $this;
  3378. $result->settings = array();
  3379. return array($this->name => $result);
  3380. } else {
  3381. return array();
  3382. }
  3383. }
  3384. }
  3385. /**
  3386. * Special class for authentication administration.
  3387. */
  3388. class admin_setting_manageauths extends admin_setting {
  3389. function admin_setting_manageauths() {
  3390. parent::admin_setting('authsui', get_string('authsettings', 'admin'), '', '');
  3391. }
  3392. function get_setting() {
  3393. return true;
  3394. }
  3395. function get_defaultsetting() {
  3396. return true;
  3397. }
  3398. function write_setting($data) {
  3399. // do not write any setting
  3400. return '';
  3401. }
  3402. function is_related($query) {
  3403. if (parent::is_related($query)) {
  3404. return true;
  3405. }
  3406. $textlib = textlib_get_instance();
  3407. $authsavailable = get_list_of_plugins('auth');
  3408. foreach ($authsavailable as $auth) {
  3409. if (strpos($auth, $query) !== false) {
  3410. return true;
  3411. }
  3412. $authplugin = get_auth_plugin($auth);
  3413. $authtitle = $authplugin->get_title();
  3414. if (strpos($textlib->strtolower($authtitle), $query) !== false) {
  3415. return true;
  3416. }
  3417. }
  3418. return false;
  3419. }
  3420. function output_html($data, $query='') {
  3421. global $CFG;
  3422. // display strings
  3423. $txt = get_strings(array('authenticationplugins', 'users', 'administration',
  3424. 'settings', 'edit', 'name', 'enable', 'disable',
  3425. 'up', 'down', 'none'));
  3426. $txt->updown = "$txt->up/$txt->down";
  3427. $authsavailable = get_list_of_plugins('auth');
  3428. get_enabled_auth_plugins(true); // fix the list of enabled auths
  3429. if (empty($CFG->auth)) {
  3430. $authsenabled = array();
  3431. } else {
  3432. $authsenabled = explode(',', $CFG->auth);
  3433. }
  3434. // construct the display array, with enabled auth plugins at the top, in order
  3435. $displayauths = array();
  3436. $registrationauths = array();
  3437. $registrationauths[''] = $txt->disable;
  3438. foreach ($authsenabled as $auth) {
  3439. $authplugin = get_auth_plugin($auth);
  3440. /// Get the auth title (from core or own auth lang files)
  3441. $authtitle = $authplugin->get_title();
  3442. /// Apply titles
  3443. $displayauths[$auth] = $authtitle;
  3444. if ($authplugin->can_signup()) {
  3445. $registrationauths[$auth] = $authtitle;
  3446. }
  3447. }
  3448. foreach ($authsavailable as $auth) {
  3449. if (array_key_exists($auth, $displayauths)) {
  3450. continue; //already in the list
  3451. }
  3452. $authplugin = get_auth_plugin($auth);
  3453. /// Get the auth title (from core or own auth lang files)
  3454. $authtitle = $authplugin->get_title();
  3455. /// Apply titles
  3456. $displayauths[$auth] = $authtitle;
  3457. if ($authplugin->can_signup()) {
  3458. $registrationauths[$auth] = $authtitle;
  3459. }
  3460. }
  3461. $return = print_heading(get_string('actauthhdr', 'auth'), '', 3, 'main', true);
  3462. $return .= print_box_start('generalbox authsui', '', true);
  3463. $table = new object();
  3464. $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings);
  3465. $table->align = array('left', 'center', 'center', 'center');
  3466. $table->width = '90%';
  3467. $table->data = array();
  3468. //add always enabled plugins first
  3469. $displayname = "<span>".$displayauths['manual']."</span>";
  3470. $settings = "<a href=\"auth_config.php?auth=manual\">{$txt->settings}</a>";
  3471. //$settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
  3472. $table->data[] = array($displayname, '', '', $settings);
  3473. $displayname = "<span>".$displayauths['nologin']."</span>";
  3474. $settings = "<a href=\"auth_config.php?auth=nologin\">{$txt->settings}</a>";
  3475. $table->data[] = array($displayname, '', '', $settings);
  3476. // iterate through auth plugins and add to the display table
  3477. $updowncount = 1;
  3478. $authcount = count($authsenabled);
  3479. $url = "auth.php?sesskey=" . sesskey();
  3480. foreach ($displayauths as $auth => $name) {
  3481. if ($auth == 'manual' or $auth == 'nologin') {
  3482. continue;
  3483. }
  3484. // hide/show link
  3485. if (in_array($auth, $authsenabled)) {
  3486. $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
  3487. $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"disable\" /></a>";
  3488. // $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\"><input type=\"checkbox\" checked /></a>";
  3489. $enabled = true;
  3490. $displayname = "<span>$name</span>";
  3491. }
  3492. else {
  3493. $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
  3494. $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"enable\" /></a>";
  3495. // $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\"><input type=\"checkbox\" /></a>";
  3496. $enabled = false;
  3497. $displayname = "<span class=\"dimmed_text\">$name</span>";
  3498. }
  3499. // up/down link (only if auth is enabled)
  3500. $updown = '';
  3501. if ($enabled) {
  3502. if ($updowncount > 1) {
  3503. $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
  3504. $updown .= "<img src=\"{$CFG->pixpath}/t/up.gif\" alt=\"up\" /></a>&nbsp;";
  3505. }
  3506. else {
  3507. $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
  3508. }
  3509. if ($updowncount < $authcount) {
  3510. $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
  3511. $updown .= "<img src=\"{$CFG->pixpath}/t/down.gif\" alt=\"down\" /></a>";
  3512. }
  3513. else {
  3514. $updown .= "<img src=\"{$CFG->pixpath}/spacer.gif\" class=\"icon\" alt=\"\" />";
  3515. }
  3516. ++ $updowncount;
  3517. }
  3518. // settings link
  3519. if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
  3520. $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
  3521. } else {
  3522. $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
  3523. }
  3524. // add a row to the table
  3525. $table->data[] =array($displayname, $hideshow, $updown, $settings);
  3526. }
  3527. $return .= print_table($table, true);
  3528. $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
  3529. $return .= print_box_end(true);
  3530. return highlight($query, $return);
  3531. }
  3532. }
  3533. /**
  3534. * Special class for filter administration.
  3535. */
  3536. class admin_setting_managefilters extends admin_setting {
  3537. function admin_setting_managefilters() {
  3538. parent::admin_setting('filtersui', get_string('filtersettings', 'admin'), '', '');
  3539. }
  3540. function get_setting() {
  3541. return true;
  3542. }
  3543. function get_defaultsetting() {
  3544. return true;
  3545. }
  3546. function write_setting($data) {
  3547. // do not write any setting
  3548. return '';
  3549. }
  3550. function is_related($query) {
  3551. if (parent::is_related($query)) {
  3552. return true;
  3553. }
  3554. $textlib = textlib_get_instance();
  3555. $filterlocations = array('mod','filter');
  3556. foreach ($filterlocations as $filterlocation) {
  3557. $plugins = get_list_of_plugins($filterlocation);
  3558. foreach ($plugins as $plugin) {
  3559. if (strpos($plugin, $query) !== false) {
  3560. return true;
  3561. }
  3562. $name = get_string('filtername', $plugin);
  3563. if (strpos($textlib->strtolower($name), $query) !== false) {
  3564. return true;
  3565. }
  3566. }
  3567. }
  3568. return false;
  3569. }
  3570. function output_html($data, $query='') {
  3571. global $CFG;
  3572. $strname = get_string('name');
  3573. $strhide = get_string('disable');
  3574. $strshow = get_string('enable');
  3575. $strhideshow = "$strhide/$strshow";
  3576. $strsettings = get_string('settings');
  3577. $strup = get_string('up');
  3578. $strdown = get_string('down');
  3579. $strupdown = "$strup/$strdown";
  3580. // get a list of possible filters (and translate name if possible)
  3581. // note filters can be in the dedicated filters area OR in their
  3582. // associated modules
  3583. $installedfilters = array();
  3584. $filtersettings_new = array();
  3585. $filtersettings_old = array();
  3586. $filterlocations = array('mod','filter');
  3587. foreach ($filterlocations as $filterlocation) {
  3588. $plugins = get_list_of_plugins($filterlocation);
  3589. foreach ($plugins as $plugin) {
  3590. $pluginpath = "$CFG->dirroot/$filterlocation/$plugin/filter.php";
  3591. $settingspath_new = "$CFG->dirroot/$filterlocation/$plugin/filtersettings.php";
  3592. $settingspath_old = "$CFG->dirroot/$filterlocation/$plugin/filterconfig.html";
  3593. if (is_readable($pluginpath)) {
  3594. $name = trim(get_string("filtername", $plugin));
  3595. if (empty($name) or ($name == '[[filtername]]')) {
  3596. $textlib = textlib_get_instance();
  3597. $name = $textlib->strtotitle($plugin);
  3598. }
  3599. $installedfilters["$filterlocation/$plugin"] = $name;
  3600. if (is_readable($settingspath_new)) {
  3601. $filtersettings_new[] = "$filterlocation/$plugin";
  3602. } else if (is_readable($settingspath_old)) {
  3603. $filtersettings_old[] = "$filterlocation/$plugin";
  3604. }
  3605. }
  3606. }
  3607. }
  3608. // get all the currently selected filters
  3609. if (!empty($CFG->textfilters)) {
  3610. $oldactivefilters = explode(',', $CFG->textfilters);
  3611. $oldactivefilters = array_unique($oldactivefilters);
  3612. } else {
  3613. $oldactivefilters = array();
  3614. }
  3615. // take this opportunity to clean up filters
  3616. $activefilters = array();
  3617. foreach ($oldactivefilters as $oldactivefilter) {
  3618. if (!empty($oldactivefilter) and array_key_exists($oldactivefilter, $installedfilters)) {
  3619. $activefilters[] = $oldactivefilter;
  3620. }
  3621. }
  3622. // construct the display array with installed filters
  3623. // at the top in the right order
  3624. $displayfilters = array();
  3625. foreach ($activefilters as $activefilter) {
  3626. $name = $installedfilters[$activefilter];
  3627. $displayfilters[$activefilter] = $name;
  3628. }
  3629. foreach ($installedfilters as $key => $filter) {
  3630. if (!array_key_exists($key, $displayfilters)) {
  3631. $displayfilters[$key] = $filter;
  3632. }
  3633. }
  3634. $return = print_heading(get_string('actfilterhdr', 'filters'), '', 3, 'main', true);
  3635. $return .= print_box_start('generalbox filtersui', '', true);
  3636. $table = new object();
  3637. $table->head = array($strname, $strhideshow, $strupdown, $strsettings);
  3638. $table->align = array('left', 'center', 'center', 'center');
  3639. $table->width = '90%';
  3640. $table->data = array();
  3641. $filtersurl = "$CFG->wwwroot/$CFG->admin/filters.php?sesskey=".sesskey();
  3642. $imgurl = "$CFG->pixpath/t";
  3643. // iterate through filters adding to display table
  3644. $updowncount = 1;
  3645. $activefilterscount = count($activefilters);
  3646. foreach ($displayfilters as $path => $name) {
  3647. $upath = urlencode($path);
  3648. // get hide/show link
  3649. if (in_array($path, $activefilters)) {
  3650. $hideshow = "<a href=\"$filtersurl&amp;action=hide&amp;filterpath=$upath\">";
  3651. $hideshow .= "<img src=\"{$CFG->pixpath}/i/hide.gif\" class=\"icon\" alt=\"$strhide\" /></a>";
  3652. $hidden = false;
  3653. $displayname = "<span>$name</span>";
  3654. }
  3655. else {
  3656. $hideshow = "<a href=\"$filtersurl&amp;action=show&amp;filterpath=$upath\">";
  3657. $hideshow .= "<img src=\"{$CFG->pixpath}/i/show.gif\" class=\"icon\" alt=\"$strshow\" /></a>";
  3658. $hidden = true;
  3659. $displayname = "<span class=\"dimmed_text\">$name</span>";
  3660. }
  3661. // get up/down link (only if not hidden)
  3662. $updown = '';
  3663. if (!$hidden) {
  3664. if ($updowncount>1) {
  3665. $updown .= "<a href=\"$filtersurl&amp;action=up&amp;filterpath=$upath\">";
  3666. $updown .= "<img src=\"$imgurl/up.gif\" alt=\"$strup\" /></a>&nbsp;";
  3667. }
  3668. else {
  3669. $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />&nbsp;";
  3670. }
  3671. if ($updowncount<$activefilterscount) {
  3672. $updown .= "<a href=\"$filtersurl&amp;action=down&amp;filterpath=$upath\">";
  3673. $updown .= "<img src=\"$imgurl/down.gif\" alt=\"$strdown\" /></a>";
  3674. }
  3675. else {
  3676. $updown .= "<img src=\"$CFG->pixpath/spacer.gif\" class=\"icon\" alt=\"\" />";
  3677. }
  3678. ++$updowncount;
  3679. }
  3680. // settings link (if defined)
  3681. $settings = '';
  3682. if (in_array($path, $filtersettings_new)) {
  3683. $settings = "<a href=\"settings.php?section=filtersetting".str_replace('/', '',$path)."\">$strsettings</a>";
  3684. } else if (in_array($path, $filtersettings_old)) {
  3685. $settings = "<a href=\"filter.php?filter=".urlencode($path)."\">$strsettings</a>";
  3686. }
  3687. // write data into the table object
  3688. $table->data[] = array($displayname, $hideshow, $updown, $settings);
  3689. }
  3690. $return .= print_table($table, true);
  3691. $return .= get_string('tablenosave', 'filters');
  3692. $return .= print_box_end(true);
  3693. return highlight($query, $return);
  3694. }
  3695. }
  3696. /**
  3697. * Initialise admin page - this function does require login and permission
  3698. * checks specified in page definition.
  3699. * This function must be called on each admin page before other code.
  3700. * @param string $section name of page
  3701. * @param string $extrabutton extra HTML that is added after the blocks editing on/off button.
  3702. * @param string $extraurlparams an array paramname => paramvalue, or parameters that need to be
  3703. * added to the turn blocks editing on/off form, so this page reloads correctly.
  3704. * @param string $actualurl if the actual page being viewed is not the normal one for this
  3705. * page (e.g. admin/roles/allowassin.php, instead of admin/roles/manage.php, you can pass the alternate URL here.
  3706. */
  3707. function admin_externalpage_setup($section, $extrabutton='', $extraurlparams=array(), $actualurl='') {
  3708. global $CFG, $PAGE, $USER;
  3709. require_once($CFG->libdir.'/blocklib.php');
  3710. require_once($CFG->dirroot.'/'.$CFG->admin.'/pagelib.php');
  3711. if ($site = get_site()) {
  3712. require_login();
  3713. } else {
  3714. redirect($CFG->wwwroot.'/'.$CFG->admin.'/index.php');
  3715. die;
  3716. }
  3717. $adminroot =& admin_get_root(false, false); // settings not required for external pages
  3718. $extpage =& $adminroot->locate($section);
  3719. if (empty($extpage) or !is_a($extpage, 'admin_externalpage')) {
  3720. print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
  3721. die;
  3722. }
  3723. // this eliminates our need to authenticate on the actual pages
  3724. if (!($extpage->check_access())) {
  3725. print_error('accessdenied', 'admin');
  3726. die;
  3727. }
  3728. page_map_class(PAGE_ADMIN, 'page_admin');
  3729. $PAGE = page_create_object(PAGE_ADMIN, 0); // there must be any constant id number
  3730. $PAGE->init_extra($section); // hack alert!
  3731. $PAGE->set_extra_button($extrabutton);
  3732. $PAGE->set_extra_url_params($extraurlparams, $actualurl);
  3733. $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
  3734. if (!isset($USER->adminediting)) {
  3735. $USER->adminediting = false;
  3736. }
  3737. if ($PAGE->user_allowed_editing()) {
  3738. if ($adminediting == 1) {
  3739. $USER->adminediting = true;
  3740. } elseif ($adminediting == 0) {
  3741. $USER->adminediting = false;
  3742. }
  3743. }
  3744. }
  3745. /**
  3746. * Print header for admin page
  3747. * @param string $focus focus element
  3748. */
  3749. function admin_externalpage_print_header($focus='') {
  3750. if (!is_string($focus)) {
  3751. $focus = ''; // BC compatibility, there used to be adminroot parameter
  3752. }
  3753. global $CFG, $PAGE, $SITE, $THEME;
  3754. define('ADMIN_EXT_HEADER_PRINTED', 'true');
  3755. if (!empty($SITE->fullname)) {
  3756. $pageblocks = blocks_setup($PAGE);
  3757. $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
  3758. blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
  3759. BLOCK_L_MAX_WIDTH);
  3760. $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
  3761. blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
  3762. BLOCK_R_MAX_WIDTH);
  3763. $PAGE->print_header('', $focus);
  3764. echo '<table id="layout-table" summary=""><tr>';
  3765. $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
  3766. foreach ($lt as $column) {
  3767. $lt1[] = $column;
  3768. if ($column == 'middle') break;
  3769. }
  3770. foreach ($lt1 as $column) {
  3771. switch ($column) {
  3772. case 'left':
  3773. echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
  3774. print_container_start();
  3775. blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
  3776. print_container_end();
  3777. echo '</td>';
  3778. break;
  3779. case 'middle':
  3780. echo '<td id="middle-column">';
  3781. print_container_start(true);
  3782. $THEME->open_header_containers++; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
  3783. break;
  3784. case 'right':
  3785. if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
  3786. echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
  3787. print_container_start();
  3788. blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
  3789. print_container_end();
  3790. echo '</td>';
  3791. }
  3792. break;
  3793. }
  3794. }
  3795. } else {
  3796. print_header();
  3797. }
  3798. }
  3799. /**
  3800. * Print footer on admin page - please use normal print_footer() instead
  3801. */
  3802. function admin_externalpage_print_footer() {
  3803. global $CFG, $PAGE, $SITE, $THEME;
  3804. define('ADMIN_EXT_FOOTER_PRINTED', 'true');
  3805. if (!empty($SITE->fullname)) {
  3806. $pageblocks = blocks_setup($PAGE);
  3807. $preferred_width_left = bounded_number(BLOCK_L_MIN_WIDTH,
  3808. blocks_preferred_width($pageblocks[BLOCK_POS_LEFT]),
  3809. BLOCK_L_MAX_WIDTH);
  3810. $preferred_width_right = bounded_number(BLOCK_R_MIN_WIDTH,
  3811. blocks_preferred_width($pageblocks[BLOCK_POS_RIGHT]),
  3812. BLOCK_R_MAX_WIDTH);
  3813. $lt = (empty($THEME->layouttable)) ? array('left', 'middle', 'right') : $THEME->layouttable;
  3814. foreach ($lt as $column) {
  3815. if ($column != 'middle') {
  3816. array_shift($lt);
  3817. } else if ($column == 'middle') {
  3818. break;
  3819. }
  3820. }
  3821. foreach ($lt as $column) {
  3822. switch ($column) {
  3823. case 'left':
  3824. echo '<td style="width: '.$preferred_width_left.'px;" id="left-column">';
  3825. print_container_start();
  3826. blocks_print_group($PAGE, $pageblocks, BLOCK_POS_LEFT);
  3827. print_container_end();
  3828. echo '</td>';
  3829. break;
  3830. case 'middle':
  3831. print_container_end();
  3832. $THEME->open_header_containers--; // this is hacky workaround for the error()/notice() autoclosing problems on admin pages
  3833. echo '</td>';
  3834. break;
  3835. case 'right':
  3836. if (blocks_have_content($pageblocks, BLOCK_POS_RIGHT)) {
  3837. echo '<td style="width: '.$preferred_width_right.'px;" id="right-column">';
  3838. print_container_start();
  3839. blocks_print_group($PAGE, $pageblocks, BLOCK_POS_RIGHT);
  3840. print_container_end();
  3841. echo '</td>';
  3842. }
  3843. break;
  3844. }
  3845. }
  3846. echo '</tr></table>';
  3847. }
  3848. print_footer();
  3849. }
  3850. /**
  3851. * Returns the reference to admin tree root
  3852. * @return reference
  3853. */
  3854. function &admin_get_root($reload=false, $requirefulltree=true) {
  3855. global $CFG;
  3856. static $ADMIN = NULL;
  3857. if (!is_null($ADMIN)) {
  3858. $olderrors = $ADMIN->errors;
  3859. $oldsearch = $ADMIN->search;
  3860. $oldfulltree = $ADMIN->fulltree;
  3861. } else {
  3862. $olderrors = array();
  3863. $oldsearch = '';
  3864. $oldfulltree = false;
  3865. }
  3866. if ($reload or ($requirefulltree and !$oldfulltree)) {
  3867. $ADMIN = NULL;
  3868. }
  3869. if (is_null($ADMIN)) {
  3870. // start the admin tree!
  3871. $ADMIN = new admin_root();
  3872. // array of error messages and search query
  3873. $ADMIN->errors = $olderrors;
  3874. $ADMIN->search = $oldsearch;
  3875. if ($requirefulltree) {
  3876. $ADMIN->fulltree = true;
  3877. } else {
  3878. $ADMIN->fulltree = $oldfulltree;
  3879. }
  3880. // we process this file first to create categories first and in correct order
  3881. require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
  3882. // now we process all other files in admin/settings to build the admin tree
  3883. foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
  3884. if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
  3885. continue;
  3886. }
  3887. if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') {
  3888. // plugins are loaded last - they may insert pages anywhere
  3889. continue;
  3890. }
  3891. include($file);
  3892. }
  3893. include($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php');
  3894. if (file_exists($CFG->dirroot.'/local/settings.php')) {
  3895. include($CFG->dirroot.'/local/settings.php');
  3896. }
  3897. }
  3898. return $ADMIN;
  3899. }
  3900. /// settings utility functions
  3901. /**
  3902. * This function applies default settings.
  3903. * @param object $node, NULL means complete tree
  3904. * @param bool $uncoditional if true overrides all values with defaults
  3905. * @return void
  3906. */
  3907. function admin_apply_default_settings($node=NULL, $unconditional=true) {
  3908. global $CFG;
  3909. if (is_null($node)) {
  3910. $node =& admin_get_root();
  3911. }
  3912. if (is_a($node, 'admin_category')) {
  3913. $entries = array_keys($node->children);
  3914. foreach ($entries as $entry) {
  3915. admin_apply_default_settings($node->children[$entry], $unconditional);
  3916. }
  3917. } else if (is_a($node, 'admin_settingpage')) {
  3918. foreach ($node->settings as $setting) {
  3919. if (!$unconditional and !is_null($setting->get_setting())) {
  3920. //do not override existing defaults
  3921. continue;
  3922. }
  3923. $defaultsetting = $setting->get_defaultsetting();
  3924. if (is_null($defaultsetting)) {
  3925. // no value yet - default maybe applied after admin user creation or in upgradesettings
  3926. continue;
  3927. }
  3928. $setting->write_setting($defaultsetting);
  3929. }
  3930. }
  3931. }
  3932. /**
  3933. * Store changed settings, this function updates the errors variable in $ADMIN
  3934. * @param object $formdata from form (without magic quotes)
  3935. * @return int number of changed settings
  3936. */
  3937. function admin_write_settings($formdata) {
  3938. global $CFG, $SITE, $COURSE;
  3939. $olddbsessions = !empty($CFG->dbsessions);
  3940. $formdata = (array)stripslashes_recursive($formdata);
  3941. $data = array();
  3942. foreach ($formdata as $fullname=>$value) {
  3943. if (strpos($fullname, 's_') !== 0) {
  3944. continue; // not a config value
  3945. }
  3946. $data[$fullname] = $value;
  3947. }
  3948. $adminroot =& admin_get_root();
  3949. $settings = admin_find_write_settings($adminroot, $data);
  3950. $count = 0;
  3951. foreach ($settings as $fullname=>$setting) {
  3952. $original = serialize($setting->get_setting()); // comparison must work for arrays too
  3953. $error = $setting->write_setting($data[$fullname]);
  3954. if ($error !== '') {
  3955. $adminroot->errors[$fullname] = new object();
  3956. $adminroot->errors[$fullname]->data = $data[$fullname];
  3957. $adminroot->errors[$fullname]->id = $setting->get_id();
  3958. $adminroot->errors[$fullname]->error = $error;
  3959. }
  3960. if ($original !== serialize($setting->get_setting())) {
  3961. $count++;
  3962. $callbackfunction = $setting->updatedcallback;
  3963. if (function_exists($callbackfunction)) {
  3964. $callbackfunction($fullname);
  3965. }
  3966. }
  3967. }
  3968. if ($olddbsessions != !empty($CFG->dbsessions)) {
  3969. require_logout();
  3970. }
  3971. // now update $SITE - it might have been changed
  3972. $SITE = get_record('course', 'id', $SITE->id);
  3973. $COURSE = clone($SITE);
  3974. // now reload all settings - some of them might depend on the changed
  3975. admin_get_root(true);
  3976. return $count;
  3977. }
  3978. /**
  3979. * Internal recursive function - finds all settings from submitted form
  3980. */
  3981. function admin_find_write_settings($node, $data) {
  3982. $return = array();
  3983. if (empty($data)) {
  3984. return $return;
  3985. }
  3986. if (is_a($node, 'admin_category')) {
  3987. $entries = array_keys($node->children);
  3988. foreach ($entries as $entry) {
  3989. $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
  3990. }
  3991. } else if (is_a($node, 'admin_settingpage')) {
  3992. foreach ($node->settings as $setting) {
  3993. $fullname = $setting->get_full_name();
  3994. if (array_key_exists($fullname, $data)) {
  3995. $return[$fullname] = $setting;
  3996. }
  3997. }
  3998. }
  3999. return $return;
  4000. }
  4001. /**
  4002. * Internal function - prints the search results
  4003. */
  4004. function admin_search_settings_html($query) {
  4005. global $CFG;
  4006. $textlib = textlib_get_instance();
  4007. if ($textlib->strlen($query) < 2) {
  4008. return '';
  4009. }
  4010. $query = $textlib->strtolower($query);
  4011. $adminroot =& admin_get_root();
  4012. $findings = $adminroot->search($query);
  4013. $return = '';
  4014. $savebutton = false;
  4015. foreach ($findings as $found) {
  4016. $page = $found->page;
  4017. $settings = $found->settings;
  4018. if ($page->is_hidden()) {
  4019. // hidden pages are not displayed in search results
  4020. continue;
  4021. }
  4022. if (is_a($page, 'admin_externalpage')) {
  4023. $return .= print_heading(get_string('searchresults','admin').' - <a href="'.$page->url.'">'.highlight($query, $page->visiblename).'</a>', '', 2, 'main', true);
  4024. } else if (is_a($page, 'admin_settingpage')) {
  4025. $return .= print_heading(get_string('searchresults','admin').' - <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section='.$page->name.'">'.highlight($query, $page->visiblename).'</a>', '', 2, 'main', true);
  4026. } else {
  4027. continue;
  4028. }
  4029. if (!empty($settings)) {
  4030. $savebutton = true;
  4031. $return .= '<fieldset class="adminsettings">'."\n";
  4032. foreach ($settings as $setting) {
  4033. $return .= '<div class="clearer"><!-- --></div>'."\n";
  4034. $fullname = $setting->get_full_name();
  4035. if (array_key_exists($fullname, $adminroot->errors)) {
  4036. $data = $adminroot->errors[$fullname]->data;
  4037. } else {
  4038. $data = $setting->get_setting();
  4039. if (is_null($data)) {
  4040. $data = $setting->get_defaultsetting();
  4041. }
  4042. }
  4043. $return .= $setting->output_html($data, $query);
  4044. }
  4045. $return .= '</fieldset>';
  4046. }
  4047. }
  4048. if ($savebutton) {
  4049. $return .= '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges','admin').'" /></div>';
  4050. }
  4051. return $return;
  4052. }
  4053. /**
  4054. * Internal function - returns arrays of html pages with uninitialised settings
  4055. */
  4056. function admin_output_new_settings_by_page($node) {
  4057. $return = array();
  4058. if (is_a($node, 'admin_category')) {
  4059. $entries = array_keys($node->children);
  4060. foreach ($entries as $entry) {
  4061. $return += admin_output_new_settings_by_page($node->children[$entry]);
  4062. }
  4063. } else if (is_a($node, 'admin_settingpage')) {
  4064. $newsettings = array();
  4065. foreach ($node->settings as $setting) {
  4066. if (is_null($setting->get_setting())) {
  4067. $newsettings[] = $setting;
  4068. }
  4069. }
  4070. if (count($newsettings) > 0) {
  4071. $adminroot =& admin_get_root();
  4072. $page = print_heading(get_string('upgradesettings','admin').' - '.$node->visiblename, '', 2, 'main', true);
  4073. $page .= '<fieldset class="adminsettings">'."\n";
  4074. foreach ($newsettings as $setting) {
  4075. $fullname = $setting->get_full_name();
  4076. if (array_key_exists($fullname, $adminroot->errors)) {
  4077. $data = $adminroot->errors[$fullname]->data;
  4078. } else {
  4079. $data = $setting->get_setting();
  4080. if (is_null($data)) {
  4081. $data = $setting->get_defaultsetting();
  4082. }
  4083. }
  4084. $page .= '<div class="clearer"><!-- --></div>'."\n";
  4085. $page .= $setting->output_html($data);
  4086. }
  4087. $page .= '</fieldset>';
  4088. $return[$node->name] = $page;
  4089. }
  4090. }
  4091. return $return;
  4092. }
  4093. /**
  4094. * Unconditionally applies default admin settings in main config table
  4095. * @param array $defaults array of string values
  4096. */
  4097. function apply_default_exception_settings($defaults) {
  4098. foreach($defaults as $key => $value) {
  4099. set_config($key, $value, NULL);
  4100. }
  4101. }
  4102. /**
  4103. * Format admin settings
  4104. * @param string $object setting
  4105. * @param string $title label element
  4106. * @param string $form form fragment, html code - not highlighed automaticaly
  4107. * @param string $description
  4108. * @param bool $label link label to id
  4109. * @param string $warning warning text
  4110. * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string
  4111. * @param string $query search query to be highlighted
  4112. */
  4113. function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
  4114. global $CFG;
  4115. $name = $setting->name;
  4116. $fullname = $setting->get_full_name();
  4117. // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
  4118. if ($label) {
  4119. $labelfor = 'for = "'.$setting->get_id().'"';
  4120. } else {
  4121. $labelfor = '';
  4122. }
  4123. if (empty($setting->plugin) and array_key_exists($name, $CFG->config_php_settings)) {
  4124. $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
  4125. } else {
  4126. $override = '';
  4127. }
  4128. if ($warning !== '') {
  4129. $warning = '<div class="form-warning">'.$warning.'</div>';
  4130. }
  4131. if (is_null($defaultinfo)) {
  4132. $defaultinfo = '';
  4133. } else {
  4134. if ($defaultinfo === '') {
  4135. $defaultinfo = get_string('emptysettingvalue', 'admin');
  4136. }
  4137. $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
  4138. $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>';
  4139. }
  4140. $str = '
  4141. <div class="form-item clearfix" id="admin-'.$setting->name.'">
  4142. <div class="form-label">
  4143. <label '.$labelfor.'>'.highlightfast($query, $title).'<span class="form-shortname">'.highlightfast($query, $name).'</span>
  4144. '.$override.$warning.'
  4145. </label>
  4146. </div>
  4147. <div class="form-setting">'.$form.$defaultinfo.'</div>
  4148. <div class="form-description">'.highlight($query, $description).'</div>
  4149. </div>';
  4150. $adminroot =& admin_get_root();
  4151. if (array_key_exists($fullname, $adminroot->errors)) {
  4152. $str = '<fieldset class="error"><legend>'.$adminroot->errors[$fullname]->error.'</legend>'.$str.'</fieldset>';
  4153. }
  4154. return $str;
  4155. }
  4156. /**
  4157. * Try to upgrade the given language pack (or current language)
  4158. * If it doesn't work, fail silently and return false
  4159. */
  4160. function upgrade_language_pack($lang='') {
  4161. global $CFG;
  4162. if (empty($lang)) {
  4163. $lang = current_language();
  4164. }
  4165. if ($lang == 'en_utf8') {
  4166. return true; // Nothing to do
  4167. }
  4168. notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess');
  4169. @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there
  4170. @mkdir ($CFG->dataroot.'/lang/');
  4171. require_once($CFG->libdir.'/componentlib.class.php');
  4172. if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) {
  4173. $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
  4174. if ($status == COMPONENT_INSTALLED) {
  4175. debugging('Downloading successful: '.$lang);
  4176. @unlink($CFG->dataroot.'/cache/languages');
  4177. return true;
  4178. }
  4179. }
  4180. return false;
  4181. }
  4182. /**
  4183. * Based on find_new_settings{@link ()} in upgradesettings.php
  4184. * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
  4185. *
  4186. * @param string $node The node at which to start searching.
  4187. * @return boolen true if any settings haven't been initialised, false if they all have
  4188. */
  4189. function any_new_admin_settings($node) {
  4190. if (is_a($node, 'admin_category')) {
  4191. $entries = array_keys($node->children);
  4192. foreach ($entries as $entry) {
  4193. if (any_new_admin_settings($node->children[$entry])){
  4194. return true;
  4195. }
  4196. }
  4197. } else if (is_a($node, 'admin_settingpage')) {
  4198. foreach ($node->settings as $setting) {
  4199. if ($setting->get_setting() === NULL) {
  4200. return true;
  4201. }
  4202. }
  4203. }
  4204. return false;
  4205. }
  4206. /**
  4207. * Moved from admin/replace.php so that we can use this in cron
  4208. * @param string $search - string to look for (with magic quotes)
  4209. * @param string $replace - string to replace (with magic quotes)
  4210. * @return bool - success or fail
  4211. */
  4212. function db_replace($search, $replace) {
  4213. global $db, $CFG;
  4214. /// Turn off time limits, sometimes upgrades can be slow.
  4215. @set_time_limit(0);
  4216. @ob_implicit_flush(true);
  4217. while(@ob_end_flush());
  4218. if (!$tables = $db->Metatables() ) { // No tables yet at all.
  4219. return false;
  4220. }
  4221. foreach ($tables as $table) {
  4222. if (in_array($table, array($CFG->prefix.'config'))) { // Don't process these
  4223. continue;
  4224. }
  4225. if ($columns = $db->MetaColumns($table, false)) {
  4226. foreach ($columns as $column => $data) {
  4227. if (in_array($data->type, array('text','mediumtext','longtext','varchar'))) { // Text stuff only
  4228. $db->debug = true;
  4229. execute_sql("UPDATE $table SET $column = REPLACE($column, '$search', '$replace')");
  4230. $db->debug = false;
  4231. }
  4232. }
  4233. }
  4234. }
  4235. return true;
  4236. }
  4237. /**
  4238. * Prints tables of detected plugins, one table per plugin type,
  4239. * and prints whether they are part of the standard Moodle
  4240. * distribution or not.
  4241. */
  4242. function print_plugin_tables() {
  4243. $plugins_standard = array();
  4244. $plugins_standard['mod'] = array('assignment',
  4245. 'chat',
  4246. 'choice',
  4247. 'data',
  4248. 'exercise',
  4249. 'forum',
  4250. 'glossary',
  4251. 'hotpot',
  4252. 'journal',
  4253. 'label',
  4254. 'lams',
  4255. 'lesson',
  4256. 'quiz',
  4257. 'resource',
  4258. 'scorm',
  4259. 'survey',
  4260. 'wiki',
  4261. 'workshop');
  4262. $plugins_standard['blocks'] = array('activity_modules',
  4263. 'admin',
  4264. 'admin_bookmarks',
  4265. 'admin_tree',
  4266. 'blog_menu',
  4267. 'blog_tags',
  4268. 'calendar_month',
  4269. 'calendar_upcoming',
  4270. 'course_list',
  4271. 'course_summary',
  4272. 'glossary_random',
  4273. 'html',
  4274. 'loancalc',
  4275. 'login',
  4276. 'mentees',
  4277. 'messages',
  4278. 'mnet_hosts',
  4279. 'news_items',
  4280. 'online_users',
  4281. 'participants',
  4282. 'quiz_results',
  4283. 'recent_activity',
  4284. 'rss_client',
  4285. 'search',
  4286. 'search_forums',
  4287. 'section_links',
  4288. 'site_main_menu',
  4289. 'social_activities',
  4290. 'tag_flickr',
  4291. 'tag_youtube',
  4292. 'tags');
  4293. $plugins_standard['filter'] = array('activitynames',
  4294. 'algebra',
  4295. 'censor',
  4296. 'emailprotect',
  4297. 'filter',
  4298. 'mediaplugin',
  4299. 'multilang',
  4300. 'tex',
  4301. 'tidy');
  4302. $plugins_installed = array();
  4303. $installed_mods = get_records_list('modules', '', '', '', 'name');
  4304. $installed_blocks = get_records_list('block', '', '', '', 'name');
  4305. $plugins_installed['mod'] = array();
  4306. foreach($installed_mods as $mod) {
  4307. $plugins_installed['mod'][] = $mod->name;
  4308. }
  4309. $plugins_installed['blocks'] = array();
  4310. foreach($installed_blocks as $block) {
  4311. $plugins_installed['blocks'][] = $block->name;
  4312. }
  4313. $plugins_installed['filter'] = array();
  4314. $plugins_ondisk = array();
  4315. $plugins_ondisk['mod'] = get_list_of_plugins('mod', 'db');
  4316. $plugins_ondisk['blocks'] = get_list_of_plugins('blocks', 'db');
  4317. $plugins_ondisk['filter'] = get_list_of_plugins('filter', 'db');
  4318. $strstandard = get_string('standard');
  4319. $strnonstandard = get_string('nonstandard');
  4320. $strmissingfromdisk = '(' . get_string('missingfromdisk') . ')';
  4321. $strabouttobeinstalled = '(' . get_string('abouttobeinstalled') . ')';
  4322. $html = '';
  4323. $html .= '<table class="generaltable plugincheckwrapper" cellspacing="4" cellpadding="1"><tr valign="top">';
  4324. foreach ($plugins_ondisk as $cat => $list_ondisk) {
  4325. $strcaption = get_string($cat);
  4326. if ($cat == 'mod') {
  4327. $strcaption = get_string('activitymodule');
  4328. } elseif ($cat == 'filter') {
  4329. $strcaption = get_string('managefilters');
  4330. }
  4331. $html .= '<td><table class="plugincompattable generaltable boxaligncenter" cellspacing="1" cellpadding="5" '
  4332. . 'id="' . $cat . 'compattable" summary="compatibility table"><caption>' . $strcaption . '</caption>' . "\n";
  4333. $html .= '<tr class="r0"><th class="header c0">' . get_string('directory') . "</th>\n"
  4334. . '<th class="header c1">' . get_string('name') . "</th>\n"
  4335. . '<th class="header c2">' . get_string('status') . "</th>\n</tr>\n";
  4336. $row = 1;
  4337. foreach ($list_ondisk as $k => $plugin) {
  4338. $status = 'ok';
  4339. $standard = 'standard';
  4340. $note = '';
  4341. if (!in_array($plugin, $plugins_standard[$cat])) {
  4342. $standard = 'nonstandard';
  4343. $status = 'warning';
  4344. }
  4345. // Get real name and full path of plugin
  4346. $plugin_name = "[[$plugin]]";
  4347. $plugin_path = "$cat/$plugin";
  4348. $plugin_name = get_plugin_name($plugin, $cat);
  4349. // Determine if the plugin is about to be installed
  4350. if ($cat != 'filter' && !in_array($plugin, $plugins_installed[$cat])) {
  4351. $note = $strabouttobeinstalled;
  4352. $plugin_name = $plugin;
  4353. }
  4354. $html .= "<tr class=\"r$row\">\n"
  4355. . "<td class=\"cell c0\">$plugin_path</td>\n"
  4356. . "<td class=\"cell c1\">$plugin_name</td>\n"
  4357. . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $note</td>\n</tr>\n";
  4358. $row++;
  4359. // If the plugin was both on disk and in the db, unset the value from the installed plugins list
  4360. if ($key = array_search($plugin, $plugins_installed[$cat])) {
  4361. unset($plugins_installed[$cat][$key]);
  4362. }
  4363. }
  4364. // If there are plugins left in the plugins_installed list, it means they are missing from disk
  4365. foreach ($plugins_installed[$cat] as $k => $missing_plugin) {
  4366. // Make sure the plugin really is missing from disk
  4367. if (!in_array($missing_plugin, $plugins_ondisk[$cat])) {
  4368. $standard = 'standard';
  4369. $status = 'warning';
  4370. if (!in_array($missing_plugin, $plugins_standard[$cat])) {
  4371. $standard = 'nonstandard';
  4372. }
  4373. $plugin_name = $missing_plugin;
  4374. $html .= "<tr class=\"r$row\">\n"
  4375. . "<td class=\"cell c0\">?</td>\n"
  4376. . "<td class=\"cell c1\">$plugin_name</td>\n"
  4377. . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $strmissingfromdisk</td>\n</tr>\n";
  4378. $row++;
  4379. }
  4380. }
  4381. $html .= '</table></td>';
  4382. }
  4383. $html .= '</tr></table><br />';
  4384. echo $html;
  4385. }
  4386. ?>