Automatic installer.php lang files by installer_builder (20060808)
[moodle.git] / lib / adminlib.php
CommitLineData
88a7228a 1<?php //
2 //
3
4/**
5 * adminlib.php - Contains functions that only administrators will ever need to use
6 *
7 * @author Martin Dougiamas
8 * @version $Id$
9 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
10 * @package moodlecore
11 */
12
13/**
ead29342 14 * Upgrade plugins
88a7228a 15 *
16 * @uses $db
17 * @uses $CFG
ead29342 18 * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype')
19 * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes')
20 * @param string $return The url to prompt the user to continue to
88a7228a 21 */
ead29342 22function upgrade_plugins($type, $dir, $return) {
e69ef14b 23 global $CFG, $db;
173cc1c3 24
ead29342 25 if (!$plugs = get_list_of_plugins($dir) ) {
26 error('No '.$type.' plugins installed!');
173cc1c3 27 }
28
583fad99 29 $updated_plugins = false;
30 $strpluginsetup = get_string('pluginsetup');
31
ead29342 32 foreach ($plugs as $plug) {
173cc1c3 33
ead29342 34 $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug;
173cc1c3 35
ead29342 36 unset($plugin);
173cc1c3 37
ead29342 38 if ( is_readable($fullplug .'/version.php')) {
39 include_once($fullplug .'/version.php'); // defines $plugin with version etc
173cc1c3 40 } else {
41 continue; // Nothing to do.
42 }
43
ead29342 44 if ( is_readable($fullplug .'/db/'. $CFG->dbtype .'.php')) {
45 include_once($fullplug .'/db/'. $CFG->dbtype .'.php'); // defines upgrading function
173cc1c3 46 } else {
47 continue;
48 }
49
ead29342 50 if (!isset($plugin)) {
173cc1c3 51 continue;
52 }
53
ead29342 54 if (!empty($plugin->requires)) {
55 if ($plugin->requires > $CFG->version) {
56 $info->pluginname = $plug;
57 $info->pluginversion = $plugin->version;
173cc1c3 58 $info->currentmoodle = $CFG->version;
ead29342 59 $info->requiremoodle = $plugin->requires;
583fad99 60 if (!$updated_plugins) {
61 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
62 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
63 false, '&nbsp;', '&nbsp;');
64 }
65 upgrade_log_start();
ead29342 66 notify(get_string('pluginrequirementsnotmet', 'error', $info));
583fad99 67 $updated_plugins = true;
173cc1c3 68 unset($info);
69 continue;
70 }
71 }
72
ead29342 73 $plugin->name = $plug; // The name MUST match the directory
173cc1c3 74
ead29342 75 $pluginversion = $type.'_'.$plug.'_version';
173cc1c3 76
ead29342 77 if (!isset($CFG->$pluginversion)) {
78 set_config($pluginversion, 0);
173cc1c3 79 }
80
ead29342 81 if ($CFG->$pluginversion == $plugin->version) {
173cc1c3 82 // do nothing
ead29342 83 } else if ($CFG->$pluginversion < $plugin->version) {
583fad99 84 if (!$updated_plugins) {
a36f058e 85 print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '',
86 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
87 false, '&nbsp;', '&nbsp;');
173cc1c3 88 }
583fad99 89 upgrade_log_start();
ead29342 90 print_heading($plugin->name .' plugin needs upgrading');
d87a9d73 91 if ($CFG->$pluginversion == 0) { // It's a new install of this plugin
92 if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
93 $db->debug = true;
94 @set_time_limit(0); // To allow slow databases to complete the long SQL
95 if (modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql')) {
96 // OK so far, now update the plugins record
97 set_config($pluginversion, $plugin->version);
98 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
99 } else {
100 notify('Installing '. $plugin->name .' FAILED!');
101 }
102 $db->debug = false;
103 } else { // We'll assume no tables are necessary
ead29342 104 set_config($pluginversion, $plugin->version);
105 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
d87a9d73 106 }
107 } else { // Upgrade existing install
108 $upgrade_function = $type.'_'.$plugin->name .'_upgrade';
109 if (function_exists($upgrade_function)) {
110 $db->debug=true;
111 if ($upgrade_function($CFG->$pluginversion)) {
112 $db->debug=false;
113 // OK so far, now update the plugins record
114 set_config($pluginversion, $plugin->version);
115 notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess');
116 } else {
117 $db->debug=false;
118 notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!');
119 }
173cc1c3 120 }
121 }
d87a9d73 122 echo '<hr />';
ead29342 123 $updated_plugins = true;
173cc1c3 124 } else {
583fad99 125 upgrade_log_start();
ead29342 126 error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !');
173cc1c3 127 }
128 }
129
583fad99 130 upgrade_log_finish();
131
132 if ($updated_plugins) {
173cc1c3 133 print_continue($return);
134 die;
135 }
136}
137
88a7228a 138/**
139 * Find and check all modules and load them up or upgrade them if necessary
140 *
141 * @uses $db
142 * @uses $CFG
143 * @param string $return The url to prompt the user to continue to
144 * @todo Finish documenting this function
145 */
173cc1c3 146function upgrade_activity_modules($return) {
173cc1c3 147
e69ef14b 148 global $CFG, $db;
173cc1c3 149
88a7228a 150 if (!$mods = get_list_of_plugins('mod') ) {
151 error('No modules installed!');
173cc1c3 152 }
153
583fad99 154 $updated_modules = false;
155 $strmodulesetup = get_string('modulesetup');
156
173cc1c3 157 foreach ($mods as $mod) {
158
88a7228a 159 if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it
173cc1c3 160 continue;
161 }
162
88a7228a 163 $fullmod = $CFG->dirroot .'/mod/'. $mod;
173cc1c3 164
165 unset($module);
166
88a7228a 167 if ( is_readable($fullmod .'/version.php')) {
168 include_once($fullmod .'/version.php'); // defines $module with version etc
173cc1c3 169 } else {
88a7228a 170 notify('Module '. $mod .': '. $fullmod .'/version.php was not readable');
173cc1c3 171 continue;
172 }
173
88a7228a 174 if ( is_readable($fullmod .'/db/'. $CFG->dbtype .'.php')) {
175 include_once($fullmod .'/db/'. $CFG->dbtype .'.php'); // defines upgrading function
173cc1c3 176 } else {
88a7228a 177 notify('Module '. $mod .': '. $fullmod .'/db/'. $CFG->dbtype .'.php was not readable');
173cc1c3 178 continue;
179 }
180
181 if (!isset($module)) {
182 continue;
183 }
184
185 if (!empty($module->requires)) {
186 if ($module->requires > $CFG->version) {
187 $info->modulename = $mod;
188 $info->moduleversion = $module->version;
189 $info->currentmoodle = $CFG->version;
190 $info->requiremoodle = $module->requires;
583fad99 191 if (!$updated_modules) {
192 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
193 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
194 false, '&nbsp;', '&nbsp;');
195 }
196 upgrade_log_start();
173cc1c3 197 notify(get_string('modulerequirementsnotmet', 'error', $info));
583fad99 198 $updated_modules = true;
173cc1c3 199 unset($info);
200 continue;
201 }
202 }
203
204 $module->name = $mod; // The name MUST match the directory
205
88a7228a 206 if ($currmodule = get_record('modules', 'name', $module->name)) {
173cc1c3 207 if ($currmodule->version == $module->version) {
208 // do nothing
209 } else if ($currmodule->version < $module->version) {
583fad99 210 if (!$updated_modules) {
a36f058e 211 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
212 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
213 false, '&nbsp;', '&nbsp;');
173cc1c3 214 }
583fad99 215 upgrade_log_start();
88a7228a 216 print_heading($module->name .' module needs upgrading');
217 $upgrade_function = $module->name.'_upgrade';
173cc1c3 218 if (function_exists($upgrade_function)) {
219 $db->debug=true;
220 if ($upgrade_function($currmodule->version, $module)) {
221 $db->debug=false;
222 // OK so far, now update the modules record
223 $module->id = $currmodule->id;
88a7228a 224 if (! update_record('modules', $module)) {
225 error('Could not update '. $module->name .' record in modules table!');
173cc1c3 226 }
d6ead3a2 227 remove_dir($CFG->dataroot . '/cache', true); // flush cache
a8f68426 228 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
88a7228a 229 echo '<hr />';
173cc1c3 230 } else {
231 $db->debug=false;
88a7228a 232 notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!');
173cc1c3 233 }
234 }
235 $updated_modules = true;
236 } else {
583fad99 237 upgrade_log_start();
88a7228a 238 error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !');
173cc1c3 239 }
240
241 } else { // module not installed yet, so install it
583fad99 242 if (!$updated_modules) {
a36f058e 243 print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '',
244 '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>',
245 false, '&nbsp;', '&nbsp;');
173cc1c3 246 }
583fad99 247 upgrade_log_start();
173cc1c3 248 print_heading($module->name);
249 $updated_modules = true;
250 $db->debug = true;
251 @set_time_limit(0); // To allow slow databases to complete the long SQL
88a7228a 252 if (modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql')) {
173cc1c3 253 $db->debug = false;
88a7228a 254 if ($module->id = insert_record('modules', $module)) {
a8f68426 255 notify(get_string('modulesuccess', '', $module->name), 'notifysuccess');
88a7228a 256 echo '<hr />';
173cc1c3 257 } else {
88a7228a 258 error($module->name .' module could not be added to the module list!');
173cc1c3 259 }
260 } else {
88a7228a 261 error($module->name .' tables could NOT be set up successfully!');
173cc1c3 262 }
263 }
e5bd4e58 264
265 /// Check submodules of this module if necessary
266
267 include_once($fullmod.'/lib.php'); // defines upgrading function
268
269 $submoduleupgrade = $module->name.'_upgrade_submodules';
270 if (function_exists($submoduleupgrade)) {
271 $submoduleupgrade();
272 }
273
274
275 /// Run any defaults or final code that is necessary for this module
276
a5c0990e 277 if ( is_readable($fullmod .'/defaults.php')) {
278 // Insert default values for any important configuration variables
9e6e7502 279 unset($defaults);
a5c0990e 280 include_once($fullmod .'/defaults.php');
f9a2e515 281 if (!empty($defaults)) {
282 foreach ($defaults as $name => $value) {
283 if (!isset($CFG->$name)) {
284 set_config($name, $value);
285 }
a5c0990e 286 }
287 }
288 }
173cc1c3 289 }
290
583fad99 291 upgrade_log_finish(); // finish logging if started
292
293 if ($updated_modules) {
173cc1c3 294 print_continue($return);
136f43dc 295 print_footer();
173cc1c3 296 die;
297 }
298}
299
f3221af9 300/**
301 * This function will return FALSE if the lock fails to be set (ie, if it's already locked)
80be7ee3 302 *
303 * @param string $name ?
304 * @param bool $value ?
305 * @param int $staleafter ?
306 * @param bool $clobberstale ?
307 * @todo Finish documenting this function
f3221af9 308 */
309function set_cron_lock($name,$value=true,$staleafter=7200,$clobberstale=false) {
310
311 if (empty($name)) {
312 mtrace("Tried to get a cron lock for a null fieldname");
313 return false;
314 }
315
316 if (empty($value)) {
317 set_config($name,0);
318 return true;
319 }
320
321 if ($config = get_record('config','name',$name)) {
322 if (empty($config->value)) {
323 set_config($name,time());
324 } else {
325 // check for stale.
326 if ((time() - $staleafter) > $config->value) {
327 mtrace("STALE LOCKFILE FOR $name - was $config->value");
328 if (!empty($clobberstale)) {
329 set_config($name,time());
330 return true;
331 }
332 } else {
333 return false; // was not stale - ie, we're ok to still be running.
334 }
335 }
336 }
337 else {
338 set_config($name,time());
339 }
340 return true;
341}
a597f8a8 342
fb06b255 343function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') {
a597f8a8 344 static $starttime;
345 static $lasttime;
346
347 if (empty($starttime)) {
348 $starttime = $lasttime = time();
349 $lasttime = $starttime - $updatetime;
350 echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">';
351 echo '<div id="bar" style="border-style:solid;border-width:1px;width:500px;height:50px;">';
352 echo '<div id="slider" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>';
353 echo '</div>';
354 echo '<div id="text" align="center" style="width:500px;"></div>';
355 echo '</td></tr></table>';
356 echo '</div>';
357 }
358
a597f8a8 359 $now = time();
360
361 if ($done && (($now - $lasttime) >= $updatetime)) {
362 $elapsedtime = $now - $starttime;
363 $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime;
364 $percentage = format_float((float)$done / (float)$total, 2);
365 $width = (int)(500 * $percentage);
366
fb06b255 367 if ($projectedtime > 10) {
368 $projectedtext = ' Ending: '.format_time($projectedtime);
369 } else {
370 $projectedtext = '';
371 }
372
a597f8a8 373 echo '<script>';
fb06b255 374 echo 'document.getElementById("text").innerHTML = "'.addslashes($donetext).' '.$done.' done.'.$projectedtext.'";'."\n";
a597f8a8 375 echo 'document.getElementById("slider").style.width = \''.$width.'px\';'."\n";
376 echo '</script>';
377
378 $lasttime = $now;
379 sleep($sleeptime);
380 }
381}
583fad99 382
383////////////////////////////////////////////////
384/// upgrade logging functions
385////////////////////////////////////////////////
386
387$upgradeloghandle = false;
388global $upgradeloghandle; // needed for access from callback funtion
389
390/**
391 * Check if upgrade is already running.
392 *
393 * If anything goes wrong due to missing call to upgrade_log_finish()
394 * just restart the browser.
395 *
396 * @param string warning message indicating upgrade is already running
397 * @param int page reload timeout
398 */
399function upgrade_check_running($message, $timeout) {
400 if (!empty($_SESSION['upgraderunning'])) {
401 print_header();
402 redirect(me(), $message, $timeout);
403 }
404}
405
406/**
407 * Start logging of output into file (if not disabled) and
408 * prevent aborting and concurrent execution of upgrade script.
409 *
410 * Please note that you can not write into session variables after calling this function!
411 *
412 * This function may be called repeatedly.
413 */
414function upgrade_log_start() {
415 global $upgradeloghandle;
416
417 if (!empty($_SESSION['upgraderunning'])) {
418 return; // logging already started
419 }
420
421 @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading
422 $_SESSION['upgraderunning'] = 1; // set upgrade indicator
423 session_write_close(); // from now on user can reload page - will be displayed warning
424 make_upload_directory('upgradelogs');
425 ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP
426}
427
428/**
429 * Terminate logging of output, flush all data, allow script aborting
430 * and reopen session for writing. Function error() does terminate the logging too.
431 *
432 * Please make sure that each upgrade_log_start() is properly terminated by
433 * this function or error().
434 *
435 * This function may be called repeatedly.
436 */
437function upgrade_log_finish() {
438 global $upgradeloghandle;
439
440 if (empty($_SESSION['upgraderunning'])) {
441 return; // logging already terminated
442 }
443
444 @ob_end_flush();
445 @fclose($upgradeloghandle);
446 @session_start(); // ignore header errors, we only need to reopen session
447 $_SESSION['upgraderunning'] = 0; // clear upgrade indicator
448 if (connection_aborted()) {
449 die;
450 }
451 @ignore_user_abort(false);
452}
453
454/**
455 * Callback function for logging into files. Not more than one file is created per minute,
456 * upgrade session (terminated by upgrade_log_finish()) is always stored in one file.
457 *
458 * This function must not output any characters or throw warnigns and errors!
459 */
460function upgrade_log_callback($string) {
461 global $CFG, $upgradeloghandle;
462
463 if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) {
464 if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) {
465 @fwrite($upgradeloghandle, $string);
466 } else {
467 $upgradeloghandle = 'error';
468 }
469 }
470 return $string;
471}
472
9e6e7502 473?>