diff --git a/admin/index.php b/admin/index.php index 27b74138116..1e9c4f25c0c 100644 --- a/admin/index.php +++ b/admin/index.php @@ -21,6 +21,7 @@ require('../config.php'); require_once($CFG->libdir.'/adminlib.php'); // Contains various admin-only functions + require_once($CFG->libdir.'/upgradelib.php'); $id = optional_param('id', '', PARAM_TEXT); $confirmupgrade = optional_param('confirmupgrade', 0, PARAM_BOOL); diff --git a/lib/adminlib.php b/lib/adminlib.php index c0f8401f013..7705a2dd867 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -17,184 +17,6 @@ require_once($CFG->libdir.'/messagelib.php'); // Messagelib functions define('INSECURE_DATAROOT_WARNING', 1); define('INSECURE_DATAROOT_ERROR', 2); -/** - * Insert or update log display entry. Entry may already exist. - * $module, $action must be unique - * - * @param string $module - * @param string $action - * @param string $mtable - * @param string $field - * @return void - * - */ -function update_log_display_entry($module, $action, $mtable, $field) { - global $DB; - - if ($type = $DB->get_record('log_display', array('module'=>$module, 'action'=>$action))) { - $type->mtable = $mtable; - $type->field = $field; - $DB->update_record('log_display', $type); - - } else { - $type = new object(); - $type->module = $module; - $type->action = $action; - $type->mtable = $mtable; - $type->field = $field; - - $DB->insert_record('log_display', $type, false); - } -} - -/** - * Upgrade savepoint, marks end of each upgrade block. - * It stores new main version, resets upgrade timeout - * and abort upgrade if user cancels page loading. - * - * Please do not make large upgrade blocks with lots of operations, - * for example when adding tables keep only one table operation per block. - * - * @param bool $result false if upgrade step failed, true if completed - * @param string or float $version main version - * @param bool $allowabort allow user to abort script execution here - * @return void - */ -function upgrade_main_savepoint($result, $version, $allowabort=true) { - global $CFG; - - if ($result) { - if ($CFG->version >= $version) { - // something really wrong is going on in main upgrade script - print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$CFG->version, 'newversion'=>$version)); - } - set_config('version', $version); - } else { - error("Upgrade savepoint: Error during main upgrade to version $version"); // TODO: localise - } - - // reset upgrade timeout to default - upgrade_set_timeout(); - - // this is a safe place to stop upgrades if user aborts page loading - if ($allowabort and connection_aborted()) { - die; - } -} - -/** - * Module upgrade savepoint, marks end of module upgrade blocks - * It stores module version, resets upgrade timeout - * and abort upgrade if user cancels page loading. - * - * @param bool $result false if upgrade step failed, true if completed - * @param string or float $version main version - * @param string $modname name of module - * @param bool $allowabort allow user to abort script execution here - * @return void - */ -function upgrade_mod_savepoint($result, $version, $modname, $allowabort=true) { - global $DB; - - if (!$module = $DB->get_record('modules', array('name'=>$modname))) { - print_error('modulenotexist', 'debug', '', $modname); - } - - if ($result) { - if ($module->version >= $version) { - // something really wrong is going on in upgrade script - print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$module->version, 'newversion'=>$version)); - } - $module->version = $version; - $DB->update_record('modules', $module); - } else { - error("Upgrade savepoint: Error during mod upgrade to version $version"); // TODO: localise - } - - // reset upgrade timeout to default - upgrade_set_timeout(); - - // this is a safe place to stop upgrades if user aborts page loading - if ($allowabort and connection_aborted()) { - die; - } -} - -/** - * Blocks upgrade savepoint, marks end of blocks upgrade blocks - * It stores block version, resets upgrade timeout - * and abort upgrade if user cancels page loading. - * - * @param bool $result false if upgrade step failed, true if completed - * @param string or float $version main version - * @param string $blockname name of block - * @param bool $allowabort allow user to abort script execution here - * @return void - */ -function upgrade_blocks_savepoint($result, $version, $blockname, $allowabort=true) { - global $DB; - - if (!$block = $DB->get_record('block', array('name'=>$blockname))) { - print_error('blocknotexist', 'debug', '', $blockname); - } - - if ($result) { - if ($block->version >= $version) { - // something really wrong is going on in upgrade script - print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$block->version, 'newversion'=>$version)); - } - $block->version = $version; - $DB->update_record('block', $block); - } else { - error("Upgrade savepoint: Error during mod upgrade to version $version"); // TODO: localise - } - - // reset upgrade timeout to default - upgrade_set_timeout(); - - // this is a safe place to stop upgrades if user aborts page loading - if ($allowabort and connection_aborted()) { - die; - } -} - -/** - * Plugins upgrade savepoint, marks end of blocks upgrade blocks - * It stores plugin version, resets upgrade timeout - * and abort upgrade if user cancels page loading. - * - * @param bool $result false if upgrade step failed, true if completed - * @param string or float $version main version - * @param string $type name of plugin - * @param string $dir location of plugin - * @param bool $allowabort allow user to abort script execution here - * @return void - */ -function upgrade_plugin_savepoint($result, $version, $type, $dir, $allowabort=true) { - if ($result) { - $fullname = $type . '_' . $dir; - $installedversion = get_config($fullname, 'version'); - if ($installedversion >= $version) { - // Something really wrong is going on in the upgrade script - $a = new stdClass; - $a->oldversion = $installedversion; - $a->newversion = $version; - print_error('cannotdowngrade', 'debug', '', $a); - } - set_config('version', $version, $fullname); - } else { - error("Upgrade savepoint: Error during mod upgrade to version $version"); // TODO: localise - } - - // Reset upgrade timeout to default - upgrade_set_timeout(); - - // This is a safe place to stop upgrades if user aborts page loading - if ($allowabort and connection_aborted()) { - die; - } -} - /** * Delete all plugin tables * @name string name of plugin, used as table prefix @@ -373,321 +195,6 @@ function get_db_directories() { return $dbdirs; } -/** - * Upgrade plugins - * - * @uses $CFG - * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype') - * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes') - * @param string $return The url to prompt the user to continue to - */ -function upgrade_plugins($type, $dir) { - global $CFG, $DB; - -/// special cases - if ($type === 'mod') { - return upgrade_activity_modules(); - } else if ($type === 'blocks') { - return upgrade_blocks_plugins(); - } - - $plugs = get_list_of_plugins($dir); - $updated_plugins = false; - $strpluginsetup = get_string('pluginsetup'); - - foreach ($plugs as $plug) { - - $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug; - - unset($plugin); - - if (is_readable($fullplug .'/version.php')) { - include($fullplug .'/version.php'); // defines $plugin with version etc - } else { - continue; // Nothing to do. - } - - $newupgrade = false; - if (is_readable($fullplug . '/db/upgrade.php')) { - include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function - $newupgrade = true; - } - - if (!isset($plugin)) { - continue; - } - - if (!empty($plugin->requires)) { - if ($plugin->requires > $CFG->version) { - $info = new object(); - $info->pluginname = $plug; - $info->pluginversion = $plugin->version; - $info->currentmoodle = $CFG->version; - $info->requiremoodle = $plugin->requires; - upgrade_started(); - notify(get_string('pluginrequirementsnotmet', 'error', $info)); - $updated_plugins = true; - continue; - } - } - - $plugin->name = $plug; // The name MUST match the directory - $plugin->fullname = $type.'_'.$plug; // The name MUST match the directory - - $installedversion = get_config($plugin->fullname, 'version'); - - if ($installedversion === false) { - set_config('version', 0, $plugin->fullname); - } - - if ($installedversion == $plugin->version) { - // do nothing - } else if ($installedversion < $plugin->version) { - $updated_plugins = true; - upgrade_started(); - print_heading($dir.'/'. $plugin->name .' plugin needs upgrading'); - @set_time_limit(0); // To allow slow databases to complete the long SQL - - if ($installedversion == 0) { // It's a new install of this plugin - /// Both old .sql files and new install.xml are supported - /// but we priorize install.xml (XMLDB) if present - if (file_exists($fullplug . '/db/install.xml')) { - $DB->get_manager()->install_from_xmldb_file($fullplug . '/db/install.xml'); //New method - } - $status = true; - /// Continue with the instalation, roles and other stuff - if ($status) { - /// OK so far, now update the plugins record - set_config('version', $plugin->version, $plugin->fullname); - - /// Install capabilities - update_capabilities($type.'/'.$plug); - - /// Install events - events_update_definition($type.'/'.$plug); - - /// Install message providers - message_update_providers($type.'/'.$plug); - - /// Run local install function if there is one - if (is_readable($fullplug . '/lib.php')) { - include_once($fullplug . '/lib.php'); - $installfunction = $plugin->name.'_install'; - if (function_exists($installfunction)) { - if (! $installfunction() ) { - notify('Encountered a problem running install function for '.$module->name.'!'); - } - } - } - - notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess'); - } else { - notify('Installing '. $plugin->name .' FAILED!'); - } - } else { // Upgrade existing install - /// Run the upgrade function for the plugin. - $newupgrade_function = 'xmldb_' .$plugin->fullname .'_upgrade'; - $newupgrade_status = true; - if ($newupgrade && function_exists($newupgrade_function)) { - $newupgrade_status = $newupgrade_function($installedversion); - } else if ($newupgrade) { - notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' . - $fullplug . '/db/upgrade.php'); - } - /// Now analyze upgrade results - if ($newupgrade_status) { // No upgrading failed - /// OK so far, now update the plugins record - set_config('version', $plugin->version, $plugin->fullname); - update_capabilities($type.'/'.$plug); - /// Update events - events_update_definition($type.'/'.$plug); - - /// Update message providers - message_update_providers($type.'/'.$plug); - - notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess'); - } else { - notify('Upgrading '. $plugin->name .' from '. $installedversion .' to '. $plugin->version .' FAILED!'); - } - } - print_upgrade_separator(); - } else { - print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$installedversion, 'newversion'=>$plugin->version)); - } - } - - return $updated_plugins; -} - -/** - * Find and check all modules and load them up or upgrade them if necessary - */ -function upgrade_activity_modules() { - global $CFG, $DB; - - if (!$mods = get_list_of_plugins('mod') ) { - print_error('nomodules', 'debug'); - } - - $strmodulesetup = get_string('modulesetup'); - - foreach ($mods as $mod) { - - if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it - continue; - } - - $fullmod = $CFG->dirroot .'/mod/'. $mod; - - unset($module); - - - if (is_readable($fullmod .'/version.php')) { - require($fullmod .'/version.php'); // defines $module with version etc - } else { - error('Module '. $mod .': '. $fullmod .'/version.php was not readable'); // TODO: localise - } - - $newupgrade = false; - if ( is_readable($fullmod . '/db/upgrade.php')) { - include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function - $newupgrade = true; - } - - if (!isset($module)) { - continue; - } - - if (!empty($module->requires)) { - if ($module->requires > $CFG->version) { - $info = new object(); - $info->modulename = $mod; - $info->moduleversion = $module->version; - $info->currentmoodle = $CFG->version; - $info->requiremoodle = $module->requires; - upgrade_started(); - notify(get_string('modulerequirementsnotmet', 'error', $info)); - continue; - } - } - - $module->name = $mod; // The name MUST match the directory - - include_once($fullmod.'/lib.php'); // defines upgrading and/or installing functions - - if ($currmodule = $DB->get_record('modules', array('name'=>$module->name))) { - if ($currmodule->version == $module->version) { - // do nothing - } else if ($currmodule->version < $module->version) { - /// If versions say that we need to upgrade but no upgrade files are available, notify and continue - if (!$newupgrade) { - notify('Upgrade file ' . $mod . ': ' . $fullmod . '/db/upgrade.php is not readable'); - continue; - } - upgrade_started(); - - print_heading($module->name .' module needs upgrading'); - - /// Run de old and new upgrade functions for the module - $newupgrade_function = 'xmldb_' . $module->name . '_upgrade'; - - /// Then, the new function if exists and the old one was ok - $newupgrade_status = true; - if ($newupgrade && function_exists($newupgrade_function)) { - $newupgrade_status = $newupgrade_function($currmodule->version, $module); - } else if ($newupgrade) { - notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' . - $mod . ': ' . $fullmod . '/db/upgrade.php'); - } - /// Now analyze upgrade results - if ($newupgrade_status) { // No upgrading failed - // OK so far, now update the modules record - $module->id = $currmodule->id; - $DB->update_record('modules', $module); - remove_dir($CFG->dataroot . '/cache', true); // flush cache - notify(get_string('modulesuccess', '', $module->name), 'notifysuccess'); - print_upgrade_separator(); - } else { - notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!'); - } - - /// Update the capabilities table? - update_capabilities('mod/'.$module->name); - - /// Update events - events_update_definition('mod/'.$module->name); - - /// Update message providers - message_update_providers('mod/'.$module->name); - - } else { - print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$currmodule->version, 'newversion'=>$module->version)); - } - - } else { // module not installed yet, so install it - upgrade_started(); - print_heading($module->name); - - /// Execute install.xml (XMLDB) - must be present - $DB->get_manager()->install_from_xmldb_file($fullmod . '/db/install.xml'); //New method - - /// Post installation hook - optional - if (file_exists("$fullmod/db/install.php")) { - require_once("$fullmod/db/install.php"); - $post_install_function = 'xmldb_'.$module->name.'_install';; - $post_install_function(); - } - - /// Continue with the installation, roles and other stuff - $module->id = $DB->insert_record('modules', $module); - - /// Capabilities - update_capabilities('mod/'.$module->name); - - /// Events - events_update_definition('mod/'.$module->name); - - /// Message providers - message_update_providers('mod/'.$module->name); - - notify(get_string('modulesuccess', '', $module->name), 'notifysuccess'); - print_upgrade_separator(); - } - - /// Check submodules of this module if necessary - - $submoduleupgrade = $module->name.'_upgrade_submodules'; - if (function_exists($submoduleupgrade)) { - $submoduleupgrade(); - } - - /// Run any defaults or final code that is necessary for this module - - if ( is_readable($fullmod .'/defaults.php')) { - // Insert default values for any important configuration variables - unset($defaults); - include($fullmod .'/defaults.php'); // include here means execute, not library include - if (!empty($defaults)) { - if (!empty($defaults['_use_config_plugins'])) { - unset($defaults['_use_config_plugins']); - $localcfg = get_config($module->name); - foreach ($defaults as $name => $value) { - if (!isset($localcfg->$name)) { - set_config($name, $value, $module->name); - } - } - } else { - foreach ($defaults as $name => $value) { - if (!isset($CFG->$name)) { - set_config($name, $value); - } - } - } - } - } - } -} - /** * Try to obtain or release the cron lock. * @@ -723,77 +230,6 @@ function set_cron_lock($name, $until, $ignorecurrent=false) { return true; } -function print_progress($done, $total, $updatetime=5, $sleeptime=1, $donetext='') { - static $thisbarid; - static $starttime; - static $lasttime; - - if ($total < 2) { // No need to show anything - return; - } - - // Are we done? - if ($done >= $total) { - $done = $total; - if (!empty($thisbarid)) { - $donetext .= ' ('.$done.'/'.$total.') '.get_string('success'); - print_progress_redraw($thisbarid, $done, $total, 500, $donetext); - $thisbarid = $starttime = $lasttime = NULL; - } - return; - } - - if (empty($starttime)) { - $starttime = $lasttime = time(); - $lasttime = $starttime - $updatetime; - $thisbarid = uniqid(); - echo '
'; - echo '
'; - echo '
'; - echo '
'; - echo '
'; - echo '
'; - echo ''; - } - - $now = time(); - - if ($done && (($now - $lasttime) >= $updatetime)) { - $elapsedtime = $now - $starttime; - $projectedtime = (int)(((float)$total / (float)$done) * $elapsedtime) - $elapsedtime; - $percentage = round((float)$done / (float)$total, 2); - $width = (int)(500 * $percentage); - - if ($projectedtime > 10) { - $projectedtext = ' Ending: '.format_time($projectedtime); - } else { - $projectedtext = ''; - } - - $donetext .= ' ('.$done.'/'.$total.') '.$projectedtext; - print_progress_redraw($thisbarid, $done, $total, $width, $donetext); - - $lasttime = $now; - } -} - -// Don't call this function directly, it's called from print_progress. -function print_progress_redraw($thisbarid, $done, $total, $width, $donetext='') { - if (empty($thisbarid)) { - return; - } - echo ''; -} - -function upgrade_get_javascript() { - global $CFG; - - return ''; -} - function create_admin_user($user_input=NULL) { global $CFG, $DB; @@ -844,93 +280,6 @@ function create_admin_user($user_input=NULL) { return $user; } -//////////////////////////////////////////////// -/// upgrade logging functions -//////////////////////////////////////////////// - -/** - * Marks start of upgrade, blocks any other access to site. - * The upgrade is finished at the end of script or after timeout. - */ -function upgrade_started($preinstall=false) { - global $CFG, $DB; - - static $started = false; - - if ($preinstall) { - ignore_user_abort(true); - upgrade_setup_debug(true); - - } else if ($started) { - upgrade_set_timeout(120); - - } else { - if (!CLI_SCRIPT and !defined('HEADER_PRINTED')) { - $strupgrade = get_string('upgradingversion', 'admin'); - - print_header($strupgrade, $strupgrade, - build_navigation(array(array('name' => $strupgrade, 'link' => null, 'type' => 'misc'))), '', - upgrade_get_javascript(), false, ' ', ' '); - } - - ignore_user_abort(true); - register_shutdown_function('upgrade_finished_handler'); - upgrade_setup_debug(true); - set_config('upgraderunning', time()+300); - $started = true; - } -} - -/** - * Internal function - executed if upgrade interruped. - */ -function upgrade_finished_handler() { - upgrade_finished(); -} - -/** - * Indicates upgrade is finished. - * - * This function may be called repeatedly. - */ -function upgrade_finished($continueurl=null) { - global $CFG, $DB; - - if (!empty($CFG->upgraderunning)) { - unset_config('upgraderunning'); - upgrade_setup_debug(false); - ignore_user_abort(false); - if ($continueurl) { - print_continue($continueurl); - print_footer('none'); - die; - } - } -} - -function upgrade_setup_debug($starting) { - global $CFG, $DB; - - static $originaldebug = null; - - if ($starting) { - if ($originaldebug === null) { - $originaldebug = $DB->get_debug(); - } - if (!empty($CFG->upgradeshowsql)) { - $DB->set_debug(true); - } - } else { - $DB->set_debug($originaldebug); - } -} - -function print_upgrade_separator() { - if (!CLI_SCRIPT) { - echo '
'; - } -} - /** * Test if and critical warnings are present * @return bool @@ -5154,41 +4503,6 @@ function format_admin_setting($setting, $title='', $form='', $description='', $l return $str; } -/** - * Try to upgrade the given language pack (or current language) - * If it doesn't work, fail silently and return false - */ -function upgrade_language_pack($lang='') { - global $CFG; - - if (empty($lang)) { - $lang = current_language(); - } - - if ($lang == 'en_utf8') { - return true; // Nothing to do - } - - notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess'); - - @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there - @mkdir ($CFG->dataroot.'/lang/'); - - require_once($CFG->libdir.'/componentlib.class.php'); - - if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) { - $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED) - - if ($status == COMPONENT_INSTALLED) { - debugging('Downloading successful: '.$lang); - @unlink($CFG->dataroot.'/cache/languages'); - return true; - } - } - - return false; -} - /** * Based on find_new_settings{@link ()} in upgradesettings.php * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any. diff --git a/lib/upgradelib.php b/lib/upgradelib.php new file mode 100644 index 00000000000..e143c0ebe8b --- /dev/null +++ b/lib/upgradelib.php @@ -0,0 +1,702 @@ +get_record('log_display', array('module'=>$module, 'action'=>$action))) { + $type->mtable = $mtable; + $type->field = $field; + $DB->update_record('log_display', $type); + + } else { + $type = new object(); + $type->module = $module; + $type->action = $action; + $type->mtable = $mtable; + $type->field = $field; + + $DB->insert_record('log_display', $type, false); + } +} + +/** + * Upgrade savepoint, marks end of each upgrade block. + * It stores new main version, resets upgrade timeout + * and abort upgrade if user cancels page loading. + * + * Please do not make large upgrade blocks with lots of operations, + * for example when adding tables keep only one table operation per block. + * + * @param bool $result false if upgrade step failed, true if completed + * @param string or float $version main version + * @param bool $allowabort allow user to abort script execution here + * @return void + */ +function upgrade_main_savepoint($result, $version, $allowabort=true) { + global $CFG; + + if ($result) { + if ($CFG->version >= $version) { + // something really wrong is going on in main upgrade script + print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$CFG->version, 'newversion'=>$version)); + } + set_config('version', $version); + } else { + error("Upgrade savepoint: Error during main upgrade to version $version"); // TODO: localise + } + + // reset upgrade timeout to default + upgrade_set_timeout(); + + // this is a safe place to stop upgrades if user aborts page loading + if ($allowabort and connection_aborted()) { + die; + } +} + +/** + * Module upgrade savepoint, marks end of module upgrade blocks + * It stores module version, resets upgrade timeout + * and abort upgrade if user cancels page loading. + * + * @param bool $result false if upgrade step failed, true if completed + * @param string or float $version main version + * @param string $modname name of module + * @param bool $allowabort allow user to abort script execution here + * @return void + */ +function upgrade_mod_savepoint($result, $version, $modname, $allowabort=true) { + global $DB; + + if (!$module = $DB->get_record('modules', array('name'=>$modname))) { + print_error('modulenotexist', 'debug', '', $modname); + } + + if ($result) { + if ($module->version >= $version) { + // something really wrong is going on in upgrade script + print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$module->version, 'newversion'=>$version)); + } + $module->version = $version; + $DB->update_record('modules', $module); + } else { + error("Upgrade savepoint: Error during mod upgrade to version $version"); // TODO: localise + } + + // reset upgrade timeout to default + upgrade_set_timeout(); + + // this is a safe place to stop upgrades if user aborts page loading + if ($allowabort and connection_aborted()) { + die; + } +} + +/** + * Blocks upgrade savepoint, marks end of blocks upgrade blocks + * It stores block version, resets upgrade timeout + * and abort upgrade if user cancels page loading. + * + * @param bool $result false if upgrade step failed, true if completed + * @param string or float $version main version + * @param string $blockname name of block + * @param bool $allowabort allow user to abort script execution here + * @return void + */ +function upgrade_blocks_savepoint($result, $version, $blockname, $allowabort=true) { + global $DB; + + if (!$block = $DB->get_record('block', array('name'=>$blockname))) { + print_error('blocknotexist', 'debug', '', $blockname); + } + + if ($result) { + if ($block->version >= $version) { + // something really wrong is going on in upgrade script + print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$block->version, 'newversion'=>$version)); + } + $block->version = $version; + $DB->update_record('block', $block); + } else { + error("Upgrade savepoint: Error during mod upgrade to version $version"); // TODO: localise + } + + // reset upgrade timeout to default + upgrade_set_timeout(); + + // this is a safe place to stop upgrades if user aborts page loading + if ($allowabort and connection_aborted()) { + die; + } +} + +/** + * Plugins upgrade savepoint, marks end of blocks upgrade blocks + * It stores plugin version, resets upgrade timeout + * and abort upgrade if user cancels page loading. + * + * @param bool $result false if upgrade step failed, true if completed + * @param string or float $version main version + * @param string $type name of plugin + * @param string $dir location of plugin + * @param bool $allowabort allow user to abort script execution here + * @return void + */ +function upgrade_plugin_savepoint($result, $version, $type, $dir, $allowabort=true) { + if ($result) { + $fullname = $type . '_' . $dir; + $installedversion = get_config($fullname, 'version'); + if ($installedversion >= $version) { + // Something really wrong is going on in the upgrade script + $a = new stdClass; + $a->oldversion = $installedversion; + $a->newversion = $version; + print_error('cannotdowngrade', 'debug', '', $a); + } + set_config('version', $version, $fullname); + } else { + error("Upgrade savepoint: Error during mod upgrade to version $version"); // TODO: localise + } + + // Reset upgrade timeout to default + upgrade_set_timeout(); + + // This is a safe place to stop upgrades if user aborts page loading + if ($allowabort and connection_aborted()) { + die; + } +} + + +/** + * Upgrade plugins + * + * @uses $CFG + * @param string $type The type of plugins that should be updated (e.g. 'enrol', 'qtype') + * @param string $dir The directory where the plugins are located (e.g. 'question/questiontypes') + * @param string $return The url to prompt the user to continue to + */ +function upgrade_plugins($type, $dir) { + global $CFG, $DB; + +/// special cases + if ($type === 'mod') { + return upgrade_activity_modules(); + } else if ($type === 'blocks') { + return upgrade_blocks_plugins(); + } + + $plugs = get_list_of_plugins($dir); + $updated_plugins = false; + $strpluginsetup = get_string('pluginsetup'); + + foreach ($plugs as $plug) { + + $fullplug = $CFG->dirroot .'/'.$dir.'/'. $plug; + + unset($plugin); + + if (is_readable($fullplug .'/version.php')) { + include($fullplug .'/version.php'); // defines $plugin with version etc + } else { + continue; // Nothing to do. + } + + $newupgrade = false; + if (is_readable($fullplug . '/db/upgrade.php')) { + include_once($fullplug . '/db/upgrade.php'); // defines new upgrading function + $newupgrade = true; + } + + if (!isset($plugin)) { + continue; + } + + if (!empty($plugin->requires)) { + if ($plugin->requires > $CFG->version) { + $info = new object(); + $info->pluginname = $plug; + $info->pluginversion = $plugin->version; + $info->currentmoodle = $CFG->version; + $info->requiremoodle = $plugin->requires; + upgrade_started(); + notify(get_string('pluginrequirementsnotmet', 'error', $info)); + $updated_plugins = true; + continue; + } + } + + $plugin->name = $plug; // The name MUST match the directory + $plugin->fullname = $type.'_'.$plug; // The name MUST match the directory + + $installedversion = get_config($plugin->fullname, 'version'); + + if ($installedversion === false) { + set_config('version', 0, $plugin->fullname); + } + + if ($installedversion == $plugin->version) { + // do nothing + } else if ($installedversion < $plugin->version) { + $updated_plugins = true; + upgrade_started(); + print_heading($dir.'/'. $plugin->name .' plugin needs upgrading'); + @set_time_limit(0); // To allow slow databases to complete the long SQL + + if ($installedversion == 0) { // It's a new install of this plugin + /// Both old .sql files and new install.xml are supported + /// but we priorize install.xml (XMLDB) if present + if (file_exists($fullplug . '/db/install.xml')) { + $DB->get_manager()->install_from_xmldb_file($fullplug . '/db/install.xml'); //New method + } + $status = true; + /// Continue with the instalation, roles and other stuff + if ($status) { + /// OK so far, now update the plugins record + set_config('version', $plugin->version, $plugin->fullname); + + /// Install capabilities + update_capabilities($type.'/'.$plug); + + /// Install events + events_update_definition($type.'/'.$plug); + + /// Install message providers + message_update_providers($type.'/'.$plug); + + /// Run local install function if there is one + if (is_readable($fullplug . '/lib.php')) { + include_once($fullplug . '/lib.php'); + $installfunction = $plugin->name.'_install'; + if (function_exists($installfunction)) { + if (! $installfunction() ) { + notify('Encountered a problem running install function for '.$module->name.'!'); + } + } + } + + notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess'); + } else { + notify('Installing '. $plugin->name .' FAILED!'); + } + } else { // Upgrade existing install + /// Run the upgrade function for the plugin. + $newupgrade_function = 'xmldb_' .$plugin->fullname .'_upgrade'; + $newupgrade_status = true; + if ($newupgrade && function_exists($newupgrade_function)) { + $newupgrade_status = $newupgrade_function($installedversion); + } else if ($newupgrade) { + notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' . + $fullplug . '/db/upgrade.php'); + } + /// Now analyze upgrade results + if ($newupgrade_status) { // No upgrading failed + /// OK so far, now update the plugins record + set_config('version', $plugin->version, $plugin->fullname); + update_capabilities($type.'/'.$plug); + /// Update events + events_update_definition($type.'/'.$plug); + + /// Update message providers + message_update_providers($type.'/'.$plug); + + notify(get_string('modulesuccess', '', $plugin->name), 'notifysuccess'); + } else { + notify('Upgrading '. $plugin->name .' from '. $installedversion .' to '. $plugin->version .' FAILED!'); + } + } + print_upgrade_separator(); + } else { + print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$installedversion, 'newversion'=>$plugin->version)); + } + } + + return $updated_plugins; +} + +/** + * Find and check all modules and load them up or upgrade them if necessary + */ +function upgrade_activity_modules() { + global $CFG, $DB; + + if (!$mods = get_list_of_plugins('mod') ) { + print_error('nomodules', 'debug'); + } + + $strmodulesetup = get_string('modulesetup'); + + foreach ($mods as $mod) { + + if ($mod == 'NEWMODULE') { // Someone has unzipped the template, ignore it + continue; + } + + $fullmod = $CFG->dirroot .'/mod/'. $mod; + + unset($module); + + + if (is_readable($fullmod .'/version.php')) { + require($fullmod .'/version.php'); // defines $module with version etc + } else { + error('Module '. $mod .': '. $fullmod .'/version.php was not readable'); // TODO: localise + } + + $newupgrade = false; + if ( is_readable($fullmod . '/db/upgrade.php')) { + include_once($fullmod . '/db/upgrade.php'); // defines new upgrading function + $newupgrade = true; + } + + if (!isset($module)) { + continue; + } + + if (!empty($module->requires)) { + if ($module->requires > $CFG->version) { + $info = new object(); + $info->modulename = $mod; + $info->moduleversion = $module->version; + $info->currentmoodle = $CFG->version; + $info->requiremoodle = $module->requires; + upgrade_started(); + notify(get_string('modulerequirementsnotmet', 'error', $info)); + continue; + } + } + + $module->name = $mod; // The name MUST match the directory + + include_once($fullmod.'/lib.php'); // defines upgrading and/or installing functions + + if ($currmodule = $DB->get_record('modules', array('name'=>$module->name))) { + if ($currmodule->version == $module->version) { + // do nothing + } else if ($currmodule->version < $module->version) { + /// If versions say that we need to upgrade but no upgrade files are available, notify and continue + if (!$newupgrade) { + notify('Upgrade file ' . $mod . ': ' . $fullmod . '/db/upgrade.php is not readable'); + continue; + } + upgrade_started(); + + print_heading($module->name .' module needs upgrading'); + + /// Run de old and new upgrade functions for the module + $newupgrade_function = 'xmldb_' . $module->name . '_upgrade'; + + /// Then, the new function if exists and the old one was ok + $newupgrade_status = true; + if ($newupgrade && function_exists($newupgrade_function)) { + $newupgrade_status = $newupgrade_function($currmodule->version, $module); + } else if ($newupgrade) { + notify ('Upgrade function ' . $newupgrade_function . ' was not available in ' . + $mod . ': ' . $fullmod . '/db/upgrade.php'); + } + /// Now analyze upgrade results + if ($newupgrade_status) { // No upgrading failed + // OK so far, now update the modules record + $module->id = $currmodule->id; + $DB->update_record('modules', $module); + remove_dir($CFG->dataroot . '/cache', true); // flush cache + notify(get_string('modulesuccess', '', $module->name), 'notifysuccess'); + print_upgrade_separator(); + } else { + notify('Upgrading '. $module->name .' from '. $currmodule->version .' to '. $module->version .' FAILED!'); + } + + /// Update the capabilities table? + update_capabilities('mod/'.$module->name); + + /// Update events + events_update_definition('mod/'.$module->name); + + /// Update message providers + message_update_providers('mod/'.$module->name); + + } else { + print_error('cannotdowngrade', 'debug', '', (object)array('oldversion'=>$currmodule->version, 'newversion'=>$module->version)); + } + + } else { // module not installed yet, so install it + upgrade_started(); + print_heading($module->name); + + /// Execute install.xml (XMLDB) - must be present + $DB->get_manager()->install_from_xmldb_file($fullmod . '/db/install.xml'); //New method + + /// Post installation hook - optional + if (file_exists("$fullmod/db/install.php")) { + require_once("$fullmod/db/install.php"); + $post_install_function = 'xmldb_'.$module->name.'_install';; + $post_install_function(); + } + + /// Continue with the installation, roles and other stuff + $module->id = $DB->insert_record('modules', $module); + + /// Capabilities + update_capabilities('mod/'.$module->name); + + /// Events + events_update_definition('mod/'.$module->name); + + /// Message providers + message_update_providers('mod/'.$module->name); + + notify(get_string('modulesuccess', '', $module->name), 'notifysuccess'); + print_upgrade_separator(); + } + + /// Check submodules of this module if necessary + + $submoduleupgrade = $module->name.'_upgrade_submodules'; + if (function_exists($submoduleupgrade)) { + $submoduleupgrade(); + } + + /// Run any defaults or final code that is necessary for this module + + if ( is_readable($fullmod .'/defaults.php')) { + // Insert default values for any important configuration variables + unset($defaults); + include($fullmod .'/defaults.php'); // include here means execute, not library include + if (!empty($defaults)) { + if (!empty($defaults['_use_config_plugins'])) { + unset($defaults['_use_config_plugins']); + $localcfg = get_config($module->name); + foreach ($defaults as $name => $value) { + if (!isset($localcfg->$name)) { + set_config($name, $value, $module->name); + } + } + } else { + foreach ($defaults as $name => $value) { + if (!isset($CFG->$name)) { + set_config($name, $value); + } + } + } + } + } + } +} + + +//////////////////////////////////////////////// +/// upgrade logging functions +//////////////////////////////////////////////// + +function upgrade_handle_exception($exception, $plugin=null) { + //TODO +} + +/** + * Adds log entry into upgrade_log table + * + * @param int $type UPGRADE_LOG_NORMAL, UPGRADE_LOG_NOTICE or UPGRADE_LOG_ERROR + * @param string $plugin plugin or null if main + * @param string $info short description text of log entry + * @param string $details long problem description + * @param string $backtrace string used for errors only + * @return void + */ +function upgrade_log($type, $plugin, $info, $details=null, $backtrace=null) { + global $DB, $USER, $CFG; + + static $plugins = null; + if (!$plugins) { + $plugins = get_plugin_types(); + } + + $version = null; + + //first try to find out current version number + if (is_null($plugin)) { + //main + $version = $CFG->version; + + } else if (strpos('mod/', $plugin) === 0) { + try { + $modname = substr($plugin, strlen('mod/')); + $version = $DB->get_field('modules', 'version', array('name'=>$modname)); + $version = $version === false ? null : $version; + } catch (Exception $ignored) { + } + + } else if (strpos('blocks/', $plugin) === 0) { + try { + $blockname = substr($plugin, strlen('blocks/')); + if ($block = $DB->get_record('block', array('name'=>$blockname))) { + $version = $block->version; + } + } catch (Exception $ignored) { + } + } + + $log = new object(); + $log->type = $type; + $log->plugin = $plugin; + $log->version = $version; + $log->info = $info; + $log->details = $details; + $log->backtrace = $backtrace; + $log->userid = $USER->id; + $log->timemodified = time(); + + try { + $DB->insert_record('upgrade_log', $log); + } catch (Exception $ignored) { + // possible during install or upgrade + } +} + +/** + * Marks start of upgrade, blocks any other access to site. + * The upgrade is finished at the end of script or after timeout. + */ +function upgrade_started($preinstall=false) { + global $CFG, $DB; + + static $started = false; + + if ($preinstall) { + ignore_user_abort(true); + upgrade_setup_debug(true); + + } else if ($started) { + upgrade_set_timeout(120); + + } else { + if (!CLI_SCRIPT and !defined('HEADER_PRINTED')) { + $strupgrade = get_string('upgradingversion', 'admin'); + + print_header($strupgrade, $strupgrade, + build_navigation(array(array('name' => $strupgrade, 'link' => null, 'type' => 'misc'))), '', + upgrade_get_javascript(), false, ' ', ' '); + } + + ignore_user_abort(true); + register_shutdown_function('upgrade_finished_handler'); + upgrade_setup_debug(true); + set_config('upgraderunning', time()+300); + $started = true; + } +} + +/** + * Internal function - executed if upgrade interruped. + */ +function upgrade_finished_handler() { + upgrade_finished(); +} + +/** + * Indicates upgrade is finished. + * + * This function may be called repeatedly. + */ +function upgrade_finished($continueurl=null) { + global $CFG, $DB; + + if (!empty($CFG->upgraderunning)) { + unset_config('upgraderunning'); + upgrade_setup_debug(false); + ignore_user_abort(false); + if ($continueurl) { + print_continue($continueurl); + print_footer('none'); + die; + } + } +} + +function upgrade_setup_debug($starting) { + global $CFG, $DB; + + static $originaldebug = null; + + if ($starting) { + if ($originaldebug === null) { + $originaldebug = $DB->get_debug(); + } + if (!empty($CFG->upgradeshowsql)) { + $DB->set_debug(true); + } + } else { + $DB->set_debug($originaldebug); + } +} + +function print_upgrade_separator() { + if (!CLI_SCRIPT) { + echo '
'; + } +} + + +function upgrade_get_javascript() { + global $CFG; + + return ''; +} + + +/** + * Try to upgrade the given language pack (or current language) + * If it doesn't work, fail silently and return false + */ +function upgrade_language_pack($lang='') { + global $CFG; + + if (empty($lang)) { + $lang = current_language(); + } + + if ($lang == 'en_utf8') { + return true; // Nothing to do + } + + notify(get_string('langimport', 'admin').': '.$lang.' ... ', 'notifysuccess'); + + @mkdir ($CFG->dataroot.'/temp/'); //make it in case it's a fresh install, it might not be there + @mkdir ($CFG->dataroot.'/lang/'); + + require_once($CFG->libdir.'/componentlib.class.php'); + + if ($cd = new component_installer('http://download.moodle.org', 'lang16', $lang.'.zip', 'languages.md5', 'lang')) { + $status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED) + + if ($status == COMPONENT_INSTALLED) { + debugging('Downloading successful: '.$lang); + @unlink($CFG->dataroot.'/cache/languages'); + return true; + } + } + + return false; +}