101
* Misplaced plugin exception.
103
* Note: this should be used only from the upgrade/admin code.
102
106
* @subpackage upgrade
103
107
* @copyright 2009 Petr Skoda {@link http://skodak.org}
104
108
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
106
110
class plugin_misplaced_exception extends moodle_exception {
107
function __construct($component, $expected, $current) {
113
* @param string $component the component from version.php
114
* @param string $expected expected directory, null means calculate
115
* @param string $current plugin directory path
117
public function __construct($component, $expected, $current) {
119
if (empty($expected)) {
120
list($type, $plugin) = core_component::normalize_component($component);
121
$plugintypes = core_component::get_plugin_types();
122
if (isset($plugintypes[$type])) {
123
$expected = $plugintypes[$type] . '/' . $plugin;
126
if (strpos($expected, '$CFG->dirroot') !== 0) {
127
$expected = str_replace($CFG->dirroot, '$CFG->dirroot', $expected);
129
if (strpos($current, '$CFG->dirroot') !== 0) {
130
$current = str_replace($CFG->dirroot, '$CFG->dirroot', $current);
109
132
$a = new stdClass();
110
133
$a->component = $component;
111
134
$a->expected = $expected;
222
245
function upgrade_mod_savepoint($result, $version, $modname, $allowabort=true) {
248
$component = 'mod_'.$modname;
226
throw new upgrade_exception("mod_$modname", $version);
251
throw new upgrade_exception($component, $version);
254
$dbversion = $DB->get_field('config_plugins', 'value', array('plugin'=>$component, 'name'=>'version'));
229
256
if (!$module = $DB->get_record('modules', array('name'=>$modname))) {
230
257
print_error('modulenotexist', 'debug', '', $modname);
233
if ($module->version >= $version) {
260
if ($dbversion >= $version) {
234
261
// something really wrong is going on in upgrade script
235
throw new downgrade_exception("mod_$modname", $module->version, $version);
262
throw new downgrade_exception($component, $dbversion, $version);
237
$module->version = $version;
238
$DB->update_record('modules', $module);
239
upgrade_log(UPGRADE_LOG_NORMAL, "mod_$modname", 'Upgrade savepoint reached');
264
set_config('version', $version, $component);
266
upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached');
241
268
// reset upgrade timeout to default
242
269
upgrade_set_timeout();
262
289
function upgrade_block_savepoint($result, $version, $blockname, $allowabort=true) {
292
$component = 'block_'.$blockname;
266
throw new upgrade_exception("block_$blockname", $version);
295
throw new upgrade_exception($component, $version);
298
$dbversion = $DB->get_field('config_plugins', 'value', array('plugin'=>$component, 'name'=>'version'));
269
300
if (!$block = $DB->get_record('block', array('name'=>$blockname))) {
270
301
print_error('blocknotexist', 'debug', '', $blockname);
273
if ($block->version >= $version) {
304
if ($dbversion >= $version) {
274
305
// something really wrong is going on in upgrade script
275
throw new downgrade_exception("block_$blockname", $block->version, $version);
306
throw new downgrade_exception($component, $dbversion, $version);
277
$block->version = $version;
278
$DB->update_record('block', $block);
279
upgrade_log(UPGRADE_LOG_NORMAL, "block_$blockname", 'Upgrade savepoint reached');
308
set_config('version', $version, $component);
310
upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached');
281
312
// reset upgrade timeout to default
282
313
upgrade_set_timeout();
303
334
function upgrade_plugin_savepoint($result, $version, $type, $plugin, $allowabort=true) {
304
337
$component = $type.'_'.$plugin;
307
340
throw new upgrade_exception($component, $version);
310
$installedversion = get_config($component, 'version');
311
if ($installedversion >= $version) {
343
$dbversion = $DB->get_field('config_plugins', 'value', array('plugin'=>$component, 'name'=>'version'));
345
if ($dbversion >= $version) {
312
346
// Something really wrong is going on in the upgrade script
313
throw new downgrade_exception($component, $installedversion, $version);
347
throw new downgrade_exception($component, $dbversion, $version);
315
349
set_config('version', $version, $component);
316
350
upgrade_log(UPGRADE_LOG_NORMAL, $component, 'Upgrade savepoint reached');
402
439
$plugin = new stdClass();
403
$module = new stdClass(); // Prevent some notices when plugin placed in wrong directory.
440
$plugin->version = null;
441
$module = $plugin; // Prevent some notices when plugin placed in wrong directory.
404
442
require($fullplug.'/version.php'); // defines $plugin with version etc
406
if (!isset($plugin->version) and isset($module->version)) {
410
445
// if plugin tells us it's full name we may check the location
411
446
if (isset($plugin->component)) {
412
447
if ($plugin->component !== $component) {
413
$current = str_replace($CFG->dirroot, '$CFG->dirroot', $fullplug);
414
$expected = str_replace($CFG->dirroot, '$CFG->dirroot', get_component_directory($plugin->component));
415
throw new plugin_misplaced_exception($component, $expected, $current);
448
throw new plugin_misplaced_exception($plugin->component, null, $fullplug);
506
$installedversion = get_config($plugin->fullname, 'version');
536
$installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
507
537
if ($installedversion < $plugin->version) {
508
538
// store version if not already there
509
539
upgrade_plugin_savepoint($result, $plugin->version, $type, $plug, false);
516
546
events_update_definition($component);
517
547
message_update_providers($component);
518
548
if ($type === 'message') {
519
550
message_update_processors($plug);
521
552
upgrade_plugin_mnet_functions($component);
522
cache_helper::purge_all(true);
524
553
$endcallback($component, false, $verbose);
526
555
} else if ($installedversion > $plugin->version) {
557
586
throw new plugin_defective_exception($component, 'Missing version.php');
560
$module = new stdClass();
561
$plugin = new stdClass(); // Prevent some notices when plugin placed in wrong directory.
562
require($fullmod .'/version.php'); // defines $module with version etc
564
if (!isset($module->version) and isset($plugin->version)) {
589
$plugin = new stdClass();
590
$plugin->version = null;
592
require($fullmod .'/version.php'); // Defines $module/$plugin with version etc.
593
$plugin = clone($module);
594
unset($module->version);
595
unset($module->component);
596
unset($module->dependencies);
597
unset($module->release);
568
599
// if plugin tells us it's full name we may check the location
569
if (isset($module->component)) {
570
if ($module->component !== $component) {
571
$current = str_replace($CFG->dirroot, '$CFG->dirroot', $fullmod);
572
$expected = str_replace($CFG->dirroot, '$CFG->dirroot', get_component_directory($module->component));
573
throw new plugin_misplaced_exception($component, $expected, $current);
600
if (isset($plugin->component)) {
601
if ($plugin->component !== $component) {
602
throw new plugin_misplaced_exception($plugin->component, null, $fullmod);
577
if (empty($module->version)) {
578
if (isset($module->version)) {
579
// Version is empty but is set - it means its value is 0 or ''. Let us skip such module.
580
// This is intended for developers so they can work on the early stages of the module.
606
if (empty($plugin->version)) {
607
// Version must be always set now!
583
608
throw new plugin_defective_exception($component, 'Missing version value in version.php');
586
if (!empty($module->requires)) {
587
if ($module->requires > $CFG->version) {
588
throw new upgrade_requires_exception($component, $module->version, $CFG->version, $module->requires);
589
} else if ($module->requires < 2010000000) {
611
if (!empty($plugin->requires)) {
612
if ($plugin->requires > $CFG->version) {
613
throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires);
614
} else if ($plugin->requires < 2010000000) {
590
615
throw new plugin_defective_exception($component, 'Plugin is not compatible with Moodle 2.x or later.');
651
677
message_update_providers($component);
652
678
upgrade_plugin_mnet_functions($component);
655
680
$endcallback($component, true, $verbose);
657
} else if ($currmodule->version < $module->version) {
682
} else if ($installedversion < $plugin->version) {
658
683
/// If versions say that we need to upgrade but no upgrade files are available, notify and continue
659
684
$startcallback($component, false, $verbose);
661
686
if (is_readable($fullmod.'/db/upgrade.php')) {
662
687
require_once($fullmod.'/db/upgrade.php'); // defines new upgrading function
663
688
$newupgrade_function = 'xmldb_'.$module->name.'_upgrade';
664
$result = $newupgrade_function($currmodule->version, $module);
689
$result = $newupgrade_function($installedversion, $module);
694
$installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
669
695
$currmodule = $DB->get_record('modules', array('name'=>$module->name));
670
if ($currmodule->version < $module->version) {
696
if ($installedversion < $plugin->version) {
671
697
// store version if not already there
672
upgrade_mod_savepoint($result, $module->version, $mod, false);
698
upgrade_mod_savepoint($result, $plugin->version, $mod, false);
675
701
// update cron flag if needed
685
711
message_update_providers($component);
686
712
upgrade_plugin_mnet_functions($component);
690
714
$endcallback($component, false, $verbose);
692
} else if ($currmodule->version > $module->version) {
693
throw new downgrade_exception($component, $currmodule->version, $module->version);
716
} else if ($installedversion > $plugin->version) {
717
throw new downgrade_exception($component, $installedversion, $plugin->version);
736
760
throw new plugin_defective_exception('block/'.$blockname, 'Missing version.php file.');
738
762
$plugin = new stdClass();
739
$module = new stdClass(); // Prevent some notices when module placed in wrong directory.
740
$plugin->version = NULL;
763
$plugin->version = null;
741
764
$plugin->cron = 0;
765
$module = $plugin; // Prevent some notices when module placed in wrong directory.
742
766
include($fullblock.'/version.php');
743
if (!isset($plugin->version) and isset($module->version)) {
768
$block = clone($plugin);
769
unset($block->version);
770
unset($block->component);
771
unset($block->dependencies);
772
unset($block->release);
748
774
// if plugin tells us it's full name we may check the location
749
if (isset($block->component)) {
750
if ($block->component !== $component) {
751
$current = str_replace($CFG->dirroot, '$CFG->dirroot', $fullblock);
752
$expected = str_replace($CFG->dirroot, '$CFG->dirroot', get_component_directory($block->component));
753
throw new plugin_misplaced_exception($component, $expected, $current);
775
if (isset($plugin->component)) {
776
if ($plugin->component !== $component) {
777
throw new plugin_misplaced_exception($plugin->component, null, $fullblock);
781
if (empty($plugin->version)) {
782
throw new plugin_defective_exception($component, 'Missing block version.');
757
785
if (!empty($plugin->requires)) {
758
786
if ($plugin->requires > $CFG->version) {
759
787
throw new upgrade_requires_exception($component, $plugin->version, $CFG->version, $plugin->requires);
784
812
$block->name = $blockname; // The name MUST match the directory
786
if (empty($block->version)) {
787
throw new plugin_defective_exception($component, 'Missing block version.');
790
$currblock = $DB->get_record('block', array('name'=>$block->name));
814
$installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
792
816
if (file_exists($fullblock.'/db/install.php')) {
793
817
if (get_config('block_'.$blockname, 'installrunning')) {
842
867
message_update_providers($component);
843
868
upgrade_plugin_mnet_functions($component);
846
870
$endcallback($component, true, $verbose);
848
} else if ($currblock->version < $block->version) {
872
} else if ($installedversion < $plugin->version) {
849
873
$startcallback($component, false, $verbose);
851
875
if (is_readable($fullblock.'/db/upgrade.php')) {
852
876
require_once($fullblock.'/db/upgrade.php'); // defines new upgrading function
853
877
$newupgrade_function = 'xmldb_block_'.$blockname.'_upgrade';
854
$result = $newupgrade_function($currblock->version, $block);
878
$result = $newupgrade_function($installedversion, $block);
883
$installedversion = $DB->get_field('config_plugins', 'value', array('name'=>'version', 'plugin'=>$component)); // No caching!
859
884
$currblock = $DB->get_record('block', array('name'=>$block->name));
860
if ($currblock->version < $block->version) {
885
if ($installedversion < $plugin->version) {
861
886
// store version if not already there
862
upgrade_block_savepoint($result, $block->version, $block->name, false);
887
upgrade_block_savepoint($result, $plugin->version, $block->name, false);
865
890
if ($currblock->cron != $block->cron) {
875
900
message_update_providers($component);
876
901
upgrade_plugin_mnet_functions($component);
879
903
$endcallback($component, false, $verbose);
881
} else if ($currblock->version > $block->version) {
882
throw new downgrade_exception($component, $currblock->version, $block->version);
905
} else if ($installedversion > $plugin->version) {
906
throw new downgrade_exception($component, $installedversion, $plugin->version);
1140
1170
upgrade_log(UPGRADE_LOG_ERROR, $plugin, 'Exception: ' . get_class($ex), $info->message, $info->backtrace);
1142
1172
// Always turn on debugging - admins need to know what is going on
1143
$CFG->debug = DEBUG_DEVELOPER;
1173
set_debugging(DEBUG_DEVELOPER, true);
1145
1175
default_exception_handler($ex, true, $plugin);
1179
1209
include("$CFG->dirroot/version.php");
1180
1210
$targetversion = $version;
1182
} else if ($plugintype === 'mod') {
1184
$currentversion = $DB->get_field('modules', 'version', array('name'=>$pluginname));
1185
$currentversion = ($currentversion === false) ? null : $currentversion;
1186
} catch (Exception $ignored) {
1188
$cd = get_component_directory($component);
1189
if (file_exists("$cd/version.php")) {
1190
$module = new stdClass();
1191
$module->version = null;
1192
include("$cd/version.php");
1193
$targetversion = $module->version;
1196
} else if ($plugintype === 'block') {
1198
if ($block = $DB->get_record('block', array('name'=>$pluginname))) {
1199
$currentversion = $block->version;
1201
} catch (Exception $ignored) {
1203
$cd = get_component_directory($component);
1204
if (file_exists("$cd/version.php")) {
1205
$plugin = new stdClass();
1206
$plugin->version = null;
1207
include("$cd/version.php");
1208
$targetversion = $plugin->version;
1212
1213
$pluginversion = get_config($component, 'version');
1213
1214
if (!empty($pluginversion)) {
1214
1215
$currentversion = $pluginversion;
1216
$cd = get_component_directory($component);
1217
$cd = core_component::get_component_directory($component);
1217
1218
if (file_exists("$cd/version.php")) {
1218
1219
$plugin = new stdClass();
1219
1220
$plugin->version = null;
1220
1222
include("$cd/version.php");
1221
1223
$targetversion = $plugin->version;
1465
1467
global $CFG, $DB;
1467
1469
// We can not call purge_all_caches() yet, make sure the temp and cache dirs exist and are empty.
1470
remove_dir($CFG->cachedir.'', true);
1468
1471
make_cache_directory('', true);
1469
remove_dir($CFG->cachedir.'', true);
1473
remove_dir($CFG->localcachedir.'', true);
1474
make_localcache_directory('', true);
1476
remove_dir($CFG->tempdir.'', true);
1470
1477
make_temp_directory('', true);
1471
remove_dir($CFG->tempdir.'', true);
1479
remove_dir($CFG->dataroot.'/muc', true);
1472
1480
make_writable_directory($CFG->dataroot.'/muc', true);
1473
remove_dir($CFG->dataroot.'/muc', true);
1476
1483
set_time_limit(600);
1512
1519
* @return void, may throw exception
1514
1521
function upgrade_core($version, $verbose) {
1522
global $CFG, $SITE, $DB, $COURSE;
1517
1524
raise_memory_limit(MEMORY_EXTRA);
1519
1526
require_once($CFG->libdir.'/db/upgrade.php'); // Defines upgrades
1522
// Reset caches before any output
1529
// Reset caches before any output.
1530
cache_helper::purge_all(true);
1523
1531
purge_all_caches();
1524
cache_helper::purge_all(true);
1526
1533
// Upgrade current language pack if we can
1527
1534
upgrade_language_pack();
1582
1593
// upgrade all plugins types
1584
$plugintypes = get_plugin_types();
1595
// Reset caches before any output.
1596
cache_helper::purge_all(true);
1599
$plugintypes = core_component::get_plugin_types();
1585
1600
foreach ($plugintypes as $type=>$location) {
1586
1601
upgrade_plugins($type, 'print_upgrade_part_start', 'print_upgrade_part_end', $verbose);
1588
1603
// Update cache definitions. Involves scanning each plugin for any changes.
1589
1604
cache_helper::update_definitions();
1605
// Mark the site as upgraded.
1606
set_config('allversionshash', core_component::get_all_versions_hash());
1608
// Purge caches again, just to be sure we arn't holding onto old stuff now.
1609
cache_helper::purge_all(true);
1590
1612
} catch (Exception $ex) {
1591
1613
upgrade_handle_exception($ex);
1976
require_once($CFG->libdir.'/textlib.class.php');
1977
1998
require_once($CFG->dirroot.'/backup/util/includes/backup_includes.php');
1978
$backupword = str_replace(' ', '_', textlib::strtolower(get_string('backupfilename')));
1999
$backupword = str_replace(' ', '_', core_text::strtolower(get_string('backupfilename')));
1979
2000
$backupword = trim(clean_filename($backupword), '_');
1980
2001
$filename = $backupword . '-' . backup::FORMAT_MOODLE . '-' . backup::TYPE_1COURSE . '-';
1981
2002
$regex = '#^'.preg_quote($filename, '#').'.*\.mbz$#';
2026
2047
$newname = $filename . $bcinfo->original_course_id . '-';
2027
2048
if ($useshortname) {
2028
2049
$shortname = str_replace(' ', '_', $bcinfo->original_course_shortname);
2029
$shortname = textlib::strtolower(trim(clean_filename($shortname), '_'));
2050
$shortname = core_text::strtolower(trim(clean_filename($shortname), '_'));
2030
2051
$newname .= $shortname . '-';
2033
2054
$backupdateformat = str_replace(' ', '_', get_string('backupnameformat', 'langconfig'));
2034
2055
$date = userdate($bcinfo->backup_date, $backupdateformat, 99, false);
2035
$date = textlib::strtolower(trim(clean_filename($date), '_'));
2056
$date = core_text::strtolower(trim(clean_filename($date), '_'));
2036
2057
$newname .= $date;
2038
2059
if (isset($bcinfo->root_settings['users']) && !$bcinfo->root_settings['users']) {
2049
2070
@rename($dir . '/' . $file, $dir . '/' . $newname);
2075
* Detect duplicate grade item sortorders and resort the
2076
* items to remove them.
2078
function upgrade_grade_item_fix_sortorder() {
2081
// The simple way to fix these sortorder duplicates would be simply to resort each
2082
// affected course. But in order to reduce the impact of this upgrade step we're trying
2083
// to do it more efficiently by doing a series of update statements rather than updating
2084
// every single grade item in affected courses.
2086
$sql = "SELECT DISTINCT g1.courseid
2087
FROM {grade_items} g1
2088
JOIN {grade_items} g2 ON g1.courseid = g2.courseid
2089
WHERE g1.sortorder = g2.sortorder AND g1.id != g2.id
2090
ORDER BY g1.courseid ASC";
2091
foreach ($DB->get_fieldset_sql($sql) as $courseid) {
2092
$transaction = $DB->start_delegated_transaction();
2093
$items = $DB->get_records('grade_items', array('courseid' => $courseid), '', 'id, sortorder, sortorder AS oldsort');
2095
// Get all duplicates in course order, highest sort order, and higest id first so that we can make space at the
2096
// bottom higher end of the sort orders and work down by id.
2097
$sql = "SELECT DISTINCT g1.id, g1.sortorder
2098
FROM {grade_items} g1
2099
JOIN {grade_items} g2 ON g1.courseid = g2.courseid
2100
WHERE g1.sortorder = g2.sortorder AND g1.id != g2.id AND g1.courseid = :courseid
2101
ORDER BY g1.sortorder DESC, g1.id DESC";
2103
// This is the O(N*N) like the database version we're replacing, but at least the constants are a billion times smaller...
2104
foreach ($DB->get_records_sql($sql, array('courseid' => $courseid)) as $duplicate) {
2105
foreach ($items as $item) {
2106
if ($item->sortorder > $duplicate->sortorder || ($item->sortorder == $duplicate->sortorder && $item->id > $duplicate->id)) {
2107
$item->sortorder += 1;
2111
foreach ($items as $item) {
2112
if ($item->sortorder != $item->oldsort) {
2113
$DB->update_record('grade_items', array('id' => $item->id, 'sortorder' => $item->sortorder));
2117
$transaction->allow_commit();
2122
* Detect file areas with missing root directory records and add them.
2124
function upgrade_fix_missing_root_folders() {
2127
$transaction = $DB->start_delegated_transaction();
2129
$sql = "SELECT contextid, component, filearea, itemid
2131
WHERE (component <> 'user' OR filearea <> 'draft')
2132
GROUP BY contextid, component, filearea, itemid
2133
HAVING MAX(CASE WHEN filename = '.' AND filepath = '/' THEN 1 ELSE 0 END) = 0";
2135
$rs = $DB->get_recordset_sql($sql);
2136
$defaults = array('filepath' => '/',
2138
'userid' => 0, // Don't rely on any particular user for these system records.
2140
'timecreated' => time(),
2141
'timemodified' => time(),
2142
'contenthash' => sha1(''));
2143
foreach ($rs as $r) {
2144
$pathhash = sha1("/$r->contextid/$r->component/$r->filearea/$r->itemid/.");
2145
$DB->insert_record('files', (array)$r + $defaults +
2146
array('pathnamehash' => $pathhash));
2149
$transaction->allow_commit();