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 |
22 | function upgrade_plugins($type, $dir, $return) { |
e69ef14b |
23 | global $CFG, $db; |
173cc1c3 |
24 | |
ead29342 |
25 | if (!$plugs = get_list_of_plugins($dir) ) { |
26 | error('No '.$type.' plugins installed!'); |
173cc1c3 |
27 | } |
28 | |
583fad99 |
29 | $updated_plugins = false; |
30 | $strpluginsetup = get_string('pluginsetup'); |
31 | |
ead29342 |
32 | foreach ($plugs as $plug) { |
173cc1c3 |
33 | |
ead29342 |
34 | $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug; |
173cc1c3 |
35 | |
ead29342 |
36 | unset($plugin); |
173cc1c3 |
37 | |
bbbf2d40 |
38 | if (is_readable($fullplug .'/version.php')) { |
ead29342 |
39 | include_once($fullplug .'/version.php'); // defines $plugin with version etc |
173cc1c3 |
40 | } else { |
41 | continue; // Nothing to do. |
42 | } |
43 | |
e79a09a2 |
44 | $oldupgrade = false; |
45 | $newupgrade = false; |
7c006e34 |
46 | if (is_readable($fullplug . '/db/'. $CFG->dbtype . '.php')) { |
47 | include_once($fullplug . '/db/'. $CFG->dbtype . '.php'); // defines old upgrading function |
e79a09a2 |
48 | $oldupgrade = true; |
49 | } |
7c006e34 |
50 | if (is_readable($fullplug . '/db/upgrade.php') && $CFG->xmldb_enabled) { |
51 | include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function |
e79a09a2 |
52 | $newupgrade = true; |
53 | } |
54 | |
ead29342 |
55 | if (!isset($plugin)) { |
173cc1c3 |
56 | continue; |
57 | } |
58 | |
ead29342 |
59 | if (!empty($plugin->requires)) { |
60 | if ($plugin->requires > $CFG->version) { |
61 | $info->pluginname = $plug; |
62 | $info->pluginversion = $plugin->version; |
173cc1c3 |
63 | $info->currentmoodle = $CFG->version; |
ead29342 |
64 | $info->requiremoodle = $plugin->requires; |
583fad99 |
65 | if (!$updated_plugins) { |
66 | print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '', |
67 | '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>', |
68 | false, ' ', ' '); |
69 | } |
70 | upgrade_log_start(); |
ead29342 |
71 | notify(get_string('pluginrequirementsnotmet', 'error', $info)); |
583fad99 |
72 | $updated_plugins = true; |
173cc1c3 |
73 | unset($info); |
74 | continue; |
75 | } |
76 | } |
77 | |
ead29342 |
78 | $plugin->name = $plug; // The name MUST match the directory |
173cc1c3 |
79 | |
ead29342 |
80 | $pluginversion = $type.'_'.$plug.'_version'; |
173cc1c3 |
81 | |
ead29342 |
82 | if (!isset($CFG->$pluginversion)) { |
83 | set_config($pluginversion, 0); |
173cc1c3 |
84 | } |
85 | |
ead29342 |
86 | if ($CFG->$pluginversion == $plugin->version) { |
173cc1c3 |
87 | // do nothing |
ead29342 |
88 | } else if ($CFG->$pluginversion < $plugin->version) { |
583fad99 |
89 | if (!$updated_plugins) { |
a36f058e |
90 | print_header($strpluginsetup, $strpluginsetup, $strpluginsetup, '', |
91 | '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>', |
92 | false, ' ', ' '); |
173cc1c3 |
93 | } |
e79a09a2 |
94 | $updated_plugins = true; |
583fad99 |
95 | upgrade_log_start(); |
ead29342 |
96 | print_heading($plugin->name .' plugin needs upgrading'); |
e79a09a2 |
97 | $db->debug = true; |
98 | @set_time_limit(0); // To allow slow databases to complete the long SQL |
99 | |
d87a9d73 |
100 | if ($CFG->$pluginversion == 0) { // It's a new install of this plugin |
e79a09a2 |
101 | /// Both old .sql files and new install.xml are supported |
102 | /// but we priorize install.xml (XMLDB) if present |
103 | $status = false; |
450cf307 |
104 | if (file_exists($fullplug . '/db/install.xml') && $CFG->xmldb_enabled) { |
105 | $status = install_from_xmldb_file($fullplug . '/db/install.xml'); //New method |
e79a09a2 |
106 | } else if (file_exists($fullplug .'/db/'. $CFG->dbtype .'.sql')) { |
107 | $status = modify_database($fullplug .'/db/'. $CFG->dbtype .'.sql'); //Old method |
7c006e34 |
108 | } else { |
109 | $status = true; |
d87a9d73 |
110 | } |
e79a09a2 |
111 | |
112 | $db->debug = false; |
113 | /// Continue with the instalation, roles and other stuff |
114 | if ($status) { |
115 | // OK so far, now update the plugins record |
116 | set_config($pluginversion, $plugin->version); |
117 | if (!update_capabilities($dir.'/'.$plug)) { |
118 | error('Could not set up the capabilities for '.$module->name.'!'); |
119 | } |
120 | notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess'); |
121 | } else { |
122 | notify('Installing '. $plugin->name .' FAILED!'); |
123 | } |
d87a9d73 |
124 | } else { // Upgrade existing install |
e79a09a2 |
125 | /// Run de old and new upgrade functions for the module |
126 | $oldupgrade_function = $type.'_'.$plugin->name .'_upgrade'; |
127 | $newupgrade_function = 'xmldb_' . $type.'_'.$plugin->name .'_upgrade'; |
128 | |
129 | /// First, the old function if exists |
130 | $oldupgrade_status = true; |
131 | if ($oldupgrade && function_exists($oldupgrade_function)) { |
132 | $db->debug = true; |
133 | $oldupgrade_status = $oldupgrade_function($CFG->$pluginversion); |
134 | } else if ($oldupgrade) { |
135 | notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' . |
136 | $fullplug . '/db/' . $CFG->dbtype . '.php'); |
137 | } |
138 | |
139 | /// Then, the new function if exists and the old one was ok |
140 | $newupgrade_status = true; |
141 | if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) { |
142 | $db->debug = true; |
143 | $newupgrade_status = $newupgrade_function($CFG->$pluginversion); |
144 | } else if ($newupgrade) { |
145 | notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' . |
146 | $fullplug . '/db/upgrade.php'); |
147 | } |
148 | |
149 | $db->debug=false; |
150 | /// Now analyze upgrade results |
151 | if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed |
152 | // OK so far, now update the plugins record |
153 | set_config($pluginversion, $plugin->version); |
154 | if (!update_capabilities($dir.'/'.$plug)) { |
155 | error('Could not update '.$plugin->name.' capabilities!'); |
d87a9d73 |
156 | } |
e79a09a2 |
157 | notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess'); |
158 | } else { |
159 | notify('Upgrading '. $plugin->name .' from '. $CFG->$pluginversion .' to '. $plugin->version .' FAILED!'); |
173cc1c3 |
160 | } |
161 | } |
d87a9d73 |
162 | echo '<hr />'; |
173cc1c3 |
163 | } else { |
583fad99 |
164 | upgrade_log_start(); |
ead29342 |
165 | error('Version mismatch: '. $plugin->name .' can\'t downgrade '. $CFG->$pluginversion .' -> '. $plugin->version .' !'); |
173cc1c3 |
166 | } |
167 | } |
168 | |
583fad99 |
169 | upgrade_log_finish(); |
170 | |
171 | if ($updated_plugins) { |
173cc1c3 |
172 | print_continue($return); |
173 | die; |
174 | } |
175 | } |
176 | |
88a7228a |
177 | /** |
178 | * Find and check all modules and load them up or upgrade them if necessary |
179 | * |
180 | * @uses $db |
181 | * @uses $CFG |
182 | * @param string $return The url to prompt the user to continue to |
183 | * @todo Finish documenting this function |
184 | */ |
173cc1c3 |
185 | function upgrade_activity_modules($return) { |
173cc1c3 |
186 | |
e69ef14b |
187 | global $CFG, $db; |
173cc1c3 |
188 | |
88a7228a |
189 | if (!$mods = get_list_of_plugins('mod') ) { |
190 | error('No modules installed!'); |
173cc1c3 |
191 | } |
192 | |
583fad99 |
193 | $updated_modules = false; |
194 | $strmodulesetup = get_string('modulesetup'); |
195 | |
173cc1c3 |
196 | foreach ($mods as $mod) { |
197 | |
88a7228a |
198 | if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it |
173cc1c3 |
199 | continue; |
200 | } |
201 | |
88a7228a |
202 | $fullmod = $CFG->dirroot .'/mod/'. $mod; |
173cc1c3 |
203 | |
204 | unset($module); |
205 | |
88a7228a |
206 | if ( is_readable($fullmod .'/version.php')) { |
207 | include_once($fullmod .'/version.php'); // defines $module with version etc |
173cc1c3 |
208 | } else { |
88a7228a |
209 | notify('Module '. $mod .': '. $fullmod .'/version.php was not readable'); |
173cc1c3 |
210 | continue; |
211 | } |
212 | |
d6eb06b6 |
213 | $oldupgrade = false; |
214 | $newupgrade = false; |
7c006e34 |
215 | if ( is_readable($fullmod .'/db/' . $CFG->dbtype . '.php')) { |
216 | include_once($fullmod .'/db/' . $CFG->dbtype . '.php'); // defines old upgrading function |
d6eb06b6 |
217 | $oldupgrade = true; |
218 | } |
7c006e34 |
219 | if ( is_readable($fullmod . '/db/upgrade.php') && $CFG->xmldb_enabled) { |
220 | include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function |
d6eb06b6 |
221 | $newupgrade = true; |
173cc1c3 |
222 | } |
223 | |
224 | if (!isset($module)) { |
225 | continue; |
226 | } |
227 | |
228 | if (!empty($module->requires)) { |
229 | if ($module->requires > $CFG->version) { |
230 | $info->modulename = $mod; |
231 | $info->moduleversion = $module->version; |
232 | $info->currentmoodle = $CFG->version; |
233 | $info->requiremoodle = $module->requires; |
583fad99 |
234 | if (!$updated_modules) { |
235 | print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '', |
236 | '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>', |
237 | false, ' ', ' '); |
238 | } |
239 | upgrade_log_start(); |
173cc1c3 |
240 | notify(get_string('modulerequirementsnotmet', 'error', $info)); |
583fad99 |
241 | $updated_modules = true; |
173cc1c3 |
242 | unset($info); |
243 | continue; |
244 | } |
245 | } |
246 | |
247 | $module->name = $mod; // The name MUST match the directory |
248 | |
88a7228a |
249 | if ($currmodule = get_record('modules', 'name', $module->name)) { |
173cc1c3 |
250 | if ($currmodule->version == $module->version) { |
251 | // do nothing |
252 | } else if ($currmodule->version < $module->version) { |
d6eb06b6 |
253 | /// If versions say that we need to upgrade but no upgrade files are available, notify and continue |
254 | if (!$oldupgrade && !$newupgrade) { |
255 | notify('Upgrade files ' . $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php or ' . |
256 | $fullmod . '/db/upgrade.php were not readable'); |
257 | continue; |
258 | } |
583fad99 |
259 | if (!$updated_modules) { |
a36f058e |
260 | print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '', |
261 | '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>', |
262 | false, ' ', ' '); |
173cc1c3 |
263 | } |
583fad99 |
264 | upgrade_log_start(); |
88a7228a |
265 | print_heading($module->name .' module needs upgrading'); |
d6eb06b6 |
266 | |
267 | /// Run de old and new upgrade functions for the module |
268 | $oldupgrade_function = $module->name . '_upgrade'; |
269 | $newupgrade_function = 'xmldb_' . $module->name . '_upgrade'; |
270 | |
271 | /// First, the old function if exists |
272 | $oldupgrade_status = true; |
273 | if ($oldupgrade && function_exists($oldupgrade_function)) { |
274 | $db->debug = true; |
275 | $oldupgrade_status = $oldupgrade_function($currmodule->version, $module); |
ba05965e |
276 | } else if ($oldupgrade) { |
d6eb06b6 |
277 | notify ('Upgrade function ' . $oldupgrade_function . ' was not available in ' . |
278 | $mod . ': ' . $fullmod . '/db/' . $CFG->dbtype . '.php'); |
d6eb06b6 |
279 | } |
280 | |
281 | /// Then, the new function if exists and the old one was ok |
282 | $newupgrade_status = true; |
ba05965e |
283 | if ($newupgrade && function_exists($newupgrade_function) && $oldupgrade_status) { |
d6eb06b6 |
284 | $db->debug = true; |
285 | $newupgrade_status = $newupgrade_function($currmodule->version, $module); |
ba05965e |
286 | } else if ($newupgrade) { |
d6eb06b6 |
287 | notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' . |
288 | $mod . ': ' . $fullmod . '/db/upgrade.php'); |
d6eb06b6 |
289 | } |
290 | |
e79a09a2 |
291 | $db->debug=false; |
d6eb06b6 |
292 | /// Now analyze upgrade results |
668896e5 |
293 | if ($oldupgrade_status && $newupgrade_status) { // No upgrading failed |
d6eb06b6 |
294 | // OK so far, now update the modules record |
295 | $module->id = $currmodule->id; |
296 | if (! update_record('modules', $module)) { |
297 | error('Could not update '. $module->name .' record in modules table!'); |
173cc1c3 |
298 | } |
d6eb06b6 |
299 | remove_dir($CFG->dataroot . '/cache', true); // flush cache |
300 | notify(get_string('modulesuccess', '', $module->name), 'notifysuccess'); |
301 | echo '<hr />'; |
302 | } else { |
d6eb06b6 |
303 | notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!'); |
173cc1c3 |
304 | } |
bbbf2d40 |
305 | |
d6eb06b6 |
306 | /// Update the capabilities table? |
bbbf2d40 |
307 | if (!update_capabilities('mod/'.$module->name)) { |
308 | error('Could not update '.$module->name.' capabilities!'); |
309 | } |
310 | |
173cc1c3 |
311 | $updated_modules = true; |
bbbf2d40 |
312 | |
173cc1c3 |
313 | } else { |
583fad99 |
314 | upgrade_log_start(); |
88a7228a |
315 | error('Version mismatch: '. $module->name .' can\'t downgrade '. $currmodule->version .' -> '. $module->version .' !'); |
173cc1c3 |
316 | } |
317 | |
318 | } else { // module not installed yet, so install it |
583fad99 |
319 | if (!$updated_modules) { |
a36f058e |
320 | print_header($strmodulesetup, $strmodulesetup, $strmodulesetup, '', |
321 | '<script type="text/javascript" src="' . $CFG->wwwroot . '/lib/scroll_to_errors.js"></script>', |
322 | false, ' ', ' '); |
173cc1c3 |
323 | } |
583fad99 |
324 | upgrade_log_start(); |
173cc1c3 |
325 | print_heading($module->name); |
326 | $updated_modules = true; |
327 | $db->debug = true; |
328 | @set_time_limit(0); // To allow slow databases to complete the long SQL |
d6eb06b6 |
329 | |
330 | /// Both old .sql files and new install.xml are supported |
331 | /// but we priorize install.xml (XMLDB) if present |
332 | if (file_exists($fullmod . '/db/install.xml') && $CFG->xmldb_enabled) { |
333 | $status = install_from_xmldb_file($fullmod . '/db/install.xml'); //New method |
334 | } else { |
335 | $status = modify_database($fullmod .'/db/'. $CFG->dbtype .'.sql'); //Old method |
336 | } |
337 | |
e79a09a2 |
338 | $db->debug = false; |
d6eb06b6 |
339 | /// Continue with the instalation, roles and other stuff |
340 | if ($status) { |
88a7228a |
341 | if ($module->id = insert_record('modules', $module)) { |
bbbf2d40 |
342 | if (!update_capabilities('mod/'.$module->name)) { |
343 | error('Could not set up the capabilities for '.$module->name.'!'); |
344 | } |
a8f68426 |
345 | notify(get_string('modulesuccess', '', $module->name), 'notifysuccess'); |
88a7228a |
346 | echo '<hr />'; |
173cc1c3 |
347 | } else { |
88a7228a |
348 | error($module->name .' module could not be added to the module list!'); |
173cc1c3 |
349 | } |
350 | } else { |
88a7228a |
351 | error($module->name .' tables could NOT be set up successfully!'); |
173cc1c3 |
352 | } |
353 | } |
e5bd4e58 |
354 | |
355 | /// Check submodules of this module if necessary |
356 | |
357 | include_once($fullmod.'/lib.php'); // defines upgrading function |
358 | |
359 | $submoduleupgrade = $module->name.'_upgrade_submodules'; |
360 | if (function_exists($submoduleupgrade)) { |
361 | $submoduleupgrade(); |
362 | } |
363 | |
364 | |
365 | /// Run any defaults or final code that is necessary for this module |
366 | |
a5c0990e |
367 | if ( is_readable($fullmod .'/defaults.php')) { |
368 | // Insert default values for any important configuration variables |
9e6e7502 |
369 | unset($defaults); |
a5c0990e |
370 | include_once($fullmod .'/defaults.php'); |
f9a2e515 |
371 | if (!empty($defaults)) { |
372 | foreach ($defaults as $name => $value) { |
373 | if (!isset($CFG->$name)) { |
374 | set_config($name, $value); |
375 | } |
a5c0990e |
376 | } |
377 | } |
378 | } |
173cc1c3 |
379 | } |
380 | |
583fad99 |
381 | upgrade_log_finish(); // finish logging if started |
382 | |
383 | if ($updated_modules) { |
173cc1c3 |
384 | print_continue($return); |
136f43dc |
385 | print_footer(); |
173cc1c3 |
386 | die; |
387 | } |
388 | } |
389 | |
f3221af9 |
390 | /** |
391 | * This function will return FALSE if the lock fails to be set (ie, if it's already locked) |
80be7ee3 |
392 | * |
393 | * @param string $name ? |
394 | * @param bool $value ? |
395 | * @param int $staleafter ? |
396 | * @param bool $clobberstale ? |
397 | * @todo Finish documenting this function |
f3221af9 |
398 | */ |
399 | function set_cron_lock($name,$value=true,$staleafter=7200,$clobberstale=false) { |
400 | |
401 | if (empty($name)) { |
402 | mtrace("Tried to get a cron lock for a null fieldname"); |
403 | return false; |
404 | } |
405 | |
406 | if (empty($value)) { |
407 | set_config($name,0); |
408 | return true; |
409 | } |
410 | |
411 | if ($config = get_record('config','name',$name)) { |
412 | if (empty($config->value)) { |
413 | set_config($name,time()); |
414 | } else { |
415 | // check for stale. |
416 | if ((time() - $staleafter) > $config->value) { |
417 | mtrace("STALE LOCKFILE FOR $name - was $config->value"); |
418 | if (!empty($clobberstale)) { |
419 | set_config($name,time()); |
420 | return true; |
421 | } |
422 | } else { |
423 | return false; // was not stale - ie, we're ok to still be running. |
424 | } |
425 | } |
426 | } |
427 | else { |
428 | set_config($name,time()); |
429 | } |
430 | return true; |
431 | } |
a597f8a8 |
432 | |
fb06b255 |
433 | function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') { |
a597f8a8 |
434 | static $starttime; |
435 | static $lasttime; |
436 | |
437 | if (empty($starttime)) { |
438 | $starttime = $lasttime = time(); |
439 | $lasttime = $starttime - $updatetime; |
440 | echo '<table width="500" cellpadding="0" cellspacing="0" align="center"><tr><td width="500">'; |
441 | echo '<div id="bar" style="border-style:solid;border-width:1px;width:500px;height:50px;">'; |
442 | echo '<div id="slider" style="border-style:solid;border-width:1px;height:48px;width:10px;background-color:green;"></div>'; |
443 | echo '</div>'; |
444 | echo '<div id="text" align="center" style="width:500px;"></div>'; |
445 | echo '</td></tr></table>'; |
446 | echo '</div>'; |
447 | } |
448 | |
a597f8a8 |
449 | $now = time(); |
450 | |
451 | if ($done && (($now - $lasttime) >= $updatetime)) { |
452 | $elapsedtime = $now - $starttime; |
453 | $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime; |
454 | $percentage = format_float((float)$done / (float)$total, 2); |
455 | $width = (int)(500 * $percentage); |
456 | |
fb06b255 |
457 | if ($projectedtime > 10) { |
458 | $projectedtext = ' Ending: '.format_time($projectedtime); |
459 | } else { |
460 | $projectedtext = ''; |
461 | } |
462 | |
a597f8a8 |
463 | echo '<script>'; |
fb06b255 |
464 | echo 'document.getElementById("text").innerHTML = "'.addslashes($donetext).' '.$done.' done.'.$projectedtext.'";'."\n"; |
a597f8a8 |
465 | echo 'document.getElementById("slider").style.width = \''.$width.'px\';'."\n"; |
466 | echo '</script>'; |
467 | |
468 | $lasttime = $now; |
469 | sleep($sleeptime); |
470 | } |
471 | } |
583fad99 |
472 | |
473 | //////////////////////////////////////////////// |
474 | /// upgrade logging functions |
475 | //////////////////////////////////////////////// |
476 | |
477 | $upgradeloghandle = false; |
26c91c73 |
478 | $upgradelogbuffer = ''; |
479 | // I did not find out how to use static variable in callback function, |
480 | // the problem was that I could not flush the static buffer :-( |
481 | global $upgradeloghandle, $upgradelogbuffer; |
583fad99 |
482 | |
483 | /** |
484 | * Check if upgrade is already running. |
485 | * |
486 | * If anything goes wrong due to missing call to upgrade_log_finish() |
487 | * just restart the browser. |
488 | * |
489 | * @param string warning message indicating upgrade is already running |
490 | * @param int page reload timeout |
491 | */ |
492 | function upgrade_check_running($message, $timeout) { |
493 | if (!empty($_SESSION['upgraderunning'])) { |
494 | print_header(); |
495 | redirect(me(), $message, $timeout); |
496 | } |
497 | } |
498 | |
499 | /** |
500 | * Start logging of output into file (if not disabled) and |
501 | * prevent aborting and concurrent execution of upgrade script. |
502 | * |
503 | * Please note that you can not write into session variables after calling this function! |
504 | * |
505 | * This function may be called repeatedly. |
506 | */ |
507 | function upgrade_log_start() { |
426a369b |
508 | global $CFG, $upgradeloghandle; |
583fad99 |
509 | |
510 | if (!empty($_SESSION['upgraderunning'])) { |
511 | return; // logging already started |
512 | } |
513 | |
514 | @ignore_user_abort(true); // ignore if user stops or otherwise aborts page loading |
515 | $_SESSION['upgraderunning'] = 1; // set upgrade indicator |
426a369b |
516 | if (empty($CFG->dbsessions)) { // workaround for bug in adodb, db session can not be restarted |
517 | session_write_close(); // from now on user can reload page - will be displayed warning |
518 | } |
583fad99 |
519 | make_upload_directory('upgradelogs'); |
520 | ob_start('upgrade_log_callback', 2); // function for logging to disk; flush each line of text ASAP |
dedb2304 |
521 | register_shutdown_function('upgrade_log_finish'); // in case somebody forgets to stop logging |
583fad99 |
522 | } |
523 | |
524 | /** |
525 | * Terminate logging of output, flush all data, allow script aborting |
526 | * and reopen session for writing. Function error() does terminate the logging too. |
527 | * |
528 | * Please make sure that each upgrade_log_start() is properly terminated by |
529 | * this function or error(). |
530 | * |
531 | * This function may be called repeatedly. |
532 | */ |
533 | function upgrade_log_finish() { |
426a369b |
534 | global $CFG, $upgradeloghandle, $upgradelogbuffer; |
583fad99 |
535 | |
536 | if (empty($_SESSION['upgraderunning'])) { |
537 | return; // logging already terminated |
538 | } |
539 | |
540 | @ob_end_flush(); |
26c91c73 |
541 | if ($upgradelogbuffer !== '') { |
542 | @fwrite($upgradeloghandle, $upgradelogbuffer); |
40896537 |
543 | $upgradelogbuffer = ''; |
26c91c73 |
544 | } |
545 | if ($upgradeloghandle and ($upgradeloghandle !== 'error')) { |
546 | @fclose($upgradeloghandle); |
40896537 |
547 | $upgradeloghandle = false; |
26c91c73 |
548 | } |
426a369b |
549 | if (empty($CFG->dbsessions)) { |
550 | @session_start(); // ignore header errors, we only need to reopen session |
551 | } |
583fad99 |
552 | $_SESSION['upgraderunning'] = 0; // clear upgrade indicator |
553 | if (connection_aborted()) { |
554 | die; |
555 | } |
556 | @ignore_user_abort(false); |
557 | } |
558 | |
559 | /** |
560 | * Callback function for logging into files. Not more than one file is created per minute, |
561 | * upgrade session (terminated by upgrade_log_finish()) is always stored in one file. |
562 | * |
563 | * This function must not output any characters or throw warnigns and errors! |
564 | */ |
565 | function upgrade_log_callback($string) { |
26c91c73 |
566 | global $CFG, $upgradeloghandle, $upgradelogbuffer; |
583fad99 |
567 | |
568 | if (empty($CFG->disableupgradelogging) and ($string != '') and ($upgradeloghandle !== 'error')) { |
569 | if ($upgradeloghandle or ($upgradeloghandle = @fopen($CFG->dataroot.'/upgradelogs/upg_'.date('Ymd-Hi').'.html', 'a'))) { |
26c91c73 |
570 | $upgradelogbuffer .= $string; |
571 | if (strlen($upgradelogbuffer) > 2048) { // 2kB write buffer |
572 | @fwrite($upgradeloghandle, $upgradelogbuffer); |
573 | $upgradelogbuffer = ''; |
574 | } |
583fad99 |
575 | } else { |
576 | $upgradeloghandle = 'error'; |
577 | } |
578 | } |
579 | return $string; |
580 | } |
581 | |
57e35f32 |
582 | /** |
583 | * Try to verify that dataroot is not accessible from web. |
584 | * It is not 100% correct but might help to reduce number of vulnerable sites. |
585 | * |
586 | * Protection from httpd.conf and .htaccess is not detected properly. |
587 | */ |
588 | function is_dataroot_insecure() { |
589 | global $CFG; |
590 | |
591 | $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround |
592 | |
593 | $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1); |
594 | $rp = strrev(trim($rp, '/')); |
595 | $rp = explode('/', $rp); |
596 | foreach($rp as $r) { |
597 | if (strpos($siteroot, '/'.$r.'/') === 0) { |
598 | $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory |
599 | } else { |
600 | break; // probably alias root |
601 | } |
602 | } |
603 | |
604 | $siteroot = strrev($siteroot); |
605 | $dataroot = str_replace('\\', '/', $CFG->dataroot.'/'); |
606 | |
607 | if (strpos($dataroot, $siteroot) === 0) { |
608 | return true; |
609 | } |
610 | return false; |
611 | } |
9e6e7502 |
612 | ?> |