/** * Get details information for main moodle_backup.xml file, extracting it from * the specified controller. * * If you specify the progress monitor, this will start a new progress section * to track progress in processing (in case this task takes a long time). * * @param string $backupid Backup ID * @param core_backup_progress $progress Optional progress monitor */ public static function get_moodle_backup_information($backupid, core_backup_progress $progress = null) { // Start tracking progress if required (for load_controller). if ($progress) { $progress->start_progress('get_moodle_backup_information', 2); } $detailsinfo = array(); // Information details $contentsinfo = array(); // Information about backup contents $settingsinfo = array(); // Information about backup settings $bc = self::load_controller($backupid); // Load controller // Note that we have loaded controller. if ($progress) { $progress->progress(1); } // Details info $detailsinfo['id'] = $bc->get_id(); $detailsinfo['backup_id'] = $bc->get_backupid(); $detailsinfo['type'] = $bc->get_type(); $detailsinfo['format'] = $bc->get_format(); $detailsinfo['interactive'] = $bc->get_interactive(); $detailsinfo['mode'] = $bc->get_mode(); $detailsinfo['execution'] = $bc->get_execution(); $detailsinfo['executiontime'] = $bc->get_executiontime(); $detailsinfo['userid'] = $bc->get_userid(); $detailsinfo['courseid'] = $bc->get_courseid(); // Init content placeholders $contentsinfo['activities'] = array(); $contentsinfo['sections'] = array(); $contentsinfo['course'] = array(); // Get tasks and start nested progress. $tasks = $bc->get_plan()->get_tasks(); if ($progress) { $progress->start_progress('get_moodle_backup_information', count($tasks)); $done = 1; } // Contents info (extract information from tasks) foreach ($tasks as $task) { if ($task instanceof backup_activity_task) { // Activity task if ($task->get_setting_value('included')) { // Only return info about included activities list($contentinfo, $settings) = self::get_activity_backup_information($task); $contentsinfo['activities'][] = $contentinfo; $settingsinfo = array_merge($settingsinfo, $settings); } } else { if ($task instanceof backup_section_task) { // Section task if ($task->get_setting_value('included')) { // Only return info about included sections list($contentinfo, $settings) = self::get_section_backup_information($task); $contentsinfo['sections'][] = $contentinfo; $settingsinfo = array_merge($settingsinfo, $settings); } } else { if ($task instanceof backup_course_task) { // Course task list($contentinfo, $settings) = self::get_course_backup_information($task); $contentsinfo['course'][] = $contentinfo; $settingsinfo = array_merge($settingsinfo, $settings); } else { if ($task instanceof backup_root_task) { // Root task list($contentinfo, $settings) = self::get_root_backup_information($task); $settingsinfo = array_merge($settingsinfo, $settings); } } } } // Report task handled. if ($progress) { $progress->progress($done++); } } $bc->destroy(); // Always need to destroy controller to handle circular references // Finish progress reporting. if ($progress) { $progress->end_progress(); $progress->end_progress(); } return array(array((object) $detailsinfo), $contentsinfo, $settingsinfo); }
/** * Check all the included users, deciding the action to perform * for each one (mapping / creation) and returning one array * of problems in case something is wrong (lack of permissions, * conficts) * * @param string $restoreid Restore id * @param int $courseid Course id * @param int $userid User id * @param bool $samesite True if restore is to same site * @param core_backup_progress $progress Progress reporter */ public static function precheck_included_users($restoreid, $courseid, $userid, $samesite, core_backup_progress $progress) { global $CFG, $DB; // To return any problem found $problems = array(); // We are going to map mnethostid, so load all the available ones $mnethosts = $DB->get_records('mnet_host', array(), 'wwwroot', 'wwwroot, id'); // Calculate the context we are going to use for capability checking $context = context_course::instance($courseid); // Calculate if we have perms to create users, by checking: // to 'moodle/restore:createuser' and 'moodle/restore:userinfo' // and also observe $CFG->disableusercreationonrestore $cancreateuser = false; if (has_capability('moodle/restore:createuser', $context, $userid) and has_capability('moodle/restore:userinfo', $context, $userid) and empty($CFG->disableusercreationonrestore)) { // Can create users $cancreateuser = true; } // Prepare for reporting progress. $conditions = array('backupid' => $restoreid, 'itemname' => 'user'); $max = $DB->count_records('backup_ids_temp', $conditions); $done = 0; $progress->start_progress('Checking users', $max); // Iterate over all the included users $rs = $DB->get_recordset('backup_ids_temp', $conditions, '', 'itemid, info'); foreach ($rs as $recuser) { $user = (object) backup_controller_dbops::decode_backup_temp_info($recuser->info); // Find the correct mnethostid for user before performing any further check if (empty($user->mnethosturl) || $user->mnethosturl === $CFG->wwwroot) { $user->mnethostid = $CFG->mnet_localhost_id; } else { // fast url-to-id lookups if (isset($mnethosts[$user->mnethosturl])) { $user->mnethostid = $mnethosts[$user->mnethosturl]->id; } else { $user->mnethostid = $CFG->mnet_localhost_id; } } // Now, precheck that user and, based on returned results, annotate action/problem $usercheck = self::precheck_user($user, $samesite); if (is_object($usercheck)) { // No problem, we have found one user in DB to be mapped to // Annotate it, for later process. Set newitemid to mapping user->id self::set_backup_ids_record($restoreid, 'user', $recuser->itemid, $usercheck->id); } else { if ($usercheck === false) { // Found conflict, report it as problem $problems[] = get_string('restoreuserconflict', '', $user->username); } else { if ($usercheck === true) { // User needs to be created, check if we are able if ($cancreateuser) { // Can create user, set newitemid to 0 so will be created later self::set_backup_ids_record($restoreid, 'user', $recuser->itemid, 0, null, (array) $user); } else { // Cannot create user, report it as problem $problems[] = get_string('restorecannotcreateuser', '', $user->username); } } else { // Shouldn't arrive here ever, something is for sure wrong. Exception throw new restore_dbops_exception('restore_error_processing_user', $user->username); } } } $done++; $progress->progress($done); } $rs->close(); $progress->end_progress(); return $problems; }
/** * Moves all the existing 'item' annotations to their final 'itemfinal' ones * for a given backup. * * @param string $backupid Backup ID * @param string $itemname Item name * @param core_backup_progress $progress Progress tracker */ public static function move_annotations_to_final($backupid, $itemname, core_backup_progress $progress) { global $DB; $progress->start_progress('move_annotations_to_final'); $rs = $DB->get_recordset('backup_ids_temp', array('backupid' => $backupid, 'itemname' => $itemname)); $progress->progress(); foreach ($rs as $annotation) { // If corresponding 'itemfinal' annotation does not exist, update 'item' to 'itemfinal' if (!$DB->record_exists('backup_ids_temp', array('backupid' => $backupid, 'itemname' => $itemname . 'final', 'itemid' => $annotation->itemid))) { $DB->set_field('backup_ids_temp', 'itemname', $itemname . 'final', array('id' => $annotation->id)); } $progress->progress(); } $rs->close(); // All the remaining $itemname annotations can be safely deleted $DB->delete_records('backup_ids_temp', array('backupid' => $backupid, 'itemname' => $itemname)); $progress->end_progress(); }
/** * Given one fullpath to directory, delete its contents recursively * Copied originally from somewhere in the net. * TODO: Modernise this * * If supplied, progress object should be ready to receive indeterminate * progress reports. * * @param string $dir Directory to delete * @param string $excludedir Exclude this directory * @param core_backup_progress $progress Optional progress reporting object */ public static function delete_dir_contents($dir, $excludeddir = '', core_backup_progress $progress = null) { global $CFG; if ($progress) { $progress->progress(); } if (!is_dir($dir)) { // if we've been given a directory that doesn't exist yet, return true. // this happens when we're trying to clear out a course that has only just // been created. return true; } $slash = "/"; // Create arrays to store files and directories $dir_files = array(); $dir_subdirs = array(); // Make sure we can delete it chmod($dir, $CFG->directorypermissions); if (($handle = opendir($dir)) == false) { // The directory could not be opened return false; } // Loop through all directory entries, and construct two temporary arrays containing files and sub directories while (false !== ($entry = readdir($handle))) { if (is_dir($dir . $slash . $entry) && $entry != ".." && $entry != "." && $entry != $excludeddir) { $dir_subdirs[] = $dir . $slash . $entry; } else { if ($entry != ".." && $entry != "." && $entry != $excludeddir) { $dir_files[] = $dir . $slash . $entry; } } } // Delete all files in the curent directory return false and halt if a file cannot be removed for ($i = 0; $i < count($dir_files); $i++) { chmod($dir_files[$i], $CFG->directorypermissions); if (unlink($dir_files[$i]) == false) { return false; } } // Empty sub directories and then remove the directory for ($i = 0; $i < count($dir_subdirs); $i++) { chmod($dir_subdirs[$i], $CFG->directorypermissions); if (self::delete_dir_contents($dir_subdirs[$i], '', $progress) == false) { return false; } else { if (remove_dir($dir_subdirs[$i]) == false) { return false; } } } // Close directory closedir($handle); // Success, every thing is gone return true return true; }