[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * @package moodlecore 20 * @subpackage backup-helper 21 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 /** 28 * Non instantiable helper class providing general helper methods for backup/restore 29 * 30 * This class contains various general helper static methods available for backup/restore 31 * 32 * TODO: Finish phpdocs 33 */ 34 abstract class backup_general_helper extends backup_helper { 35 36 /** 37 * Calculate one checksum for any array/object. Works recursively 38 */ 39 public static function array_checksum_recursive($arr) { 40 41 $checksum = ''; // Init checksum 42 43 // Check we are going to process one array always, objects must be cast before 44 if (!is_array($arr)) { 45 throw new backup_helper_exception('array_expected'); 46 } 47 foreach ($arr as $key => $value) { 48 if ($value instanceof checksumable) { 49 $checksum = md5($checksum . '-' . $key . '-' . $value->calculate_checksum()); 50 } else if (is_object($value)) { 51 $checksum = md5($checksum . '-' . $key . '-' . self::array_checksum_recursive((array)$value)); 52 } else if (is_array($value)) { 53 $checksum = md5($checksum . '-' . $key . '-' . self::array_checksum_recursive($value)); 54 } else { 55 $checksum = md5($checksum . '-' . $key . '-' . $value); 56 } 57 } 58 return $checksum; 59 } 60 61 /** 62 * Load all the blocks information needed for a given path within moodle2 backup 63 * 64 * This function, given one full path (course, activities/xxxx) will look for all the 65 * blocks existing in the backup file, returning one array used to build the 66 * proper restore plan by the @restore_plan_builder 67 */ 68 public static function get_blocks_from_path($path) { 69 global $DB; 70 71 $blocks = array(); // To return results 72 73 static $availableblocks = array(); // Get and cache available blocks 74 if (empty($availableblocks)) { 75 $availableblocks = array_keys(core_component::get_plugin_list('block')); 76 } 77 78 $path = $path . '/blocks'; // Always look under blocks subdir 79 80 if (!is_dir($path)) { 81 return array(); 82 } 83 84 if (!$dir = opendir($path)) { 85 return array(); 86 } 87 while (false !== ($file = readdir($dir))) { 88 if ($file == '.' || $file == '..') { // Skip dots 89 continue; 90 } 91 if (is_dir($path .'/' . $file)) { // Dir found, check it's a valid block 92 if (!file_exists($path .'/' . $file . '/block.xml')) { // Skip if xml file not found 93 continue; 94 } 95 // Extract block name 96 $blockname = preg_replace('/(.*)_\d+/', '\\1', $file); 97 // Check block exists and is installed 98 if (in_array($blockname, $availableblocks) && $DB->record_exists('block', array('name' => $blockname))) { 99 $blocks[$path .'/' . $file] = $blockname; 100 } 101 } 102 } 103 closedir($dir); 104 105 return $blocks; 106 } 107 108 /** 109 * Load and format all the needed information from moodle_backup.xml 110 * 111 * This function loads and process all the moodle_backup.xml 112 * information, composing a big information structure that will 113 * be the used by the plan builder in order to generate the 114 * appropiate tasks / steps / settings 115 */ 116 public static function get_backup_information($tempdir) { 117 global $CFG; 118 // Make a request cache and store the data in there. 119 static $cachesha1 = null; 120 static $cache = null; 121 122 $info = new stdclass(); // Final information goes here 123 124 $moodlefile = $CFG->tempdir . '/backup/' . $tempdir . '/moodle_backup.xml'; 125 if (!file_exists($moodlefile)) { // Shouldn't happen ever, but... 126 throw new backup_helper_exception('missing_moodle_backup_xml_file', $moodlefile); 127 } 128 129 $moodlefilesha1 = sha1_file($moodlefile); 130 if ($moodlefilesha1 === $cachesha1) { 131 return clone $cache; 132 } 133 134 // Load the entire file to in-memory array 135 $xmlparser = new progressive_parser(); 136 $xmlparser->set_file($moodlefile); 137 $xmlprocessor = new restore_moodlexml_parser_processor(); 138 $xmlparser->set_processor($xmlprocessor); 139 $xmlparser->process(); 140 $infoarr = $xmlprocessor->get_all_chunks(); 141 if (count($infoarr) !== 1) { // Shouldn't happen ever, but... 142 throw new backup_helper_exception('problem_parsing_moodle_backup_xml_file'); 143 } 144 $infoarr = $infoarr[0]['tags']; // for commodity 145 146 // Let's build info 147 $info->moodle_version = $infoarr['moodle_version']; 148 $info->moodle_release = $infoarr['moodle_release']; 149 $info->backup_version = $infoarr['backup_version']; 150 $info->backup_release = $infoarr['backup_release']; 151 $info->backup_date = $infoarr['backup_date']; 152 $info->mnet_remoteusers = $infoarr['mnet_remoteusers']; 153 $info->original_wwwroot = $infoarr['original_wwwroot']; 154 $info->original_site_identifier_hash = $infoarr['original_site_identifier_hash']; 155 $info->original_course_id = $infoarr['original_course_id']; 156 $info->original_course_fullname = $infoarr['original_course_fullname']; 157 $info->original_course_shortname= $infoarr['original_course_shortname']; 158 $info->original_course_startdate= $infoarr['original_course_startdate']; 159 $info->original_course_contextid= $infoarr['original_course_contextid']; 160 $info->original_system_contextid= $infoarr['original_system_contextid']; 161 // Moodle backup file don't have this option before 2.3 162 if (!empty($infoarr['include_file_references_to_external_content'])) { 163 $info->include_file_references_to_external_content = 1; 164 } else { 165 $info->include_file_references_to_external_content = 0; 166 } 167 // Introduced in Moodle 2.9. 168 $info->original_course_format = ''; 169 if (!empty($infoarr['original_course_format'])) { 170 $info->original_course_format = $infoarr['original_course_format']; 171 } 172 // include_files is a new setting in 2.6. 173 if (isset($infoarr['include_files'])) { 174 $info->include_files = $infoarr['include_files']; 175 } else { 176 $info->include_files = 1; 177 } 178 $info->type = $infoarr['details']['detail'][0]['type']; 179 $info->format = $infoarr['details']['detail'][0]['format']; 180 $info->mode = $infoarr['details']['detail'][0]['mode']; 181 // Build the role mappings custom object 182 $rolemappings = new stdclass(); 183 $rolemappings->modified = false; 184 $rolemappings->mappings = array(); 185 $info->role_mappings = $rolemappings; 186 // Some initially empty containers 187 $info->sections = array(); 188 $info->activities = array(); 189 190 // Now the contents 191 $contentsarr = $infoarr['contents']; 192 if (isset($contentsarr['course']) && isset($contentsarr['course'][0])) { 193 $info->course = new stdclass(); 194 $info->course = (object)$contentsarr['course'][0]; 195 $info->course->settings = array(); 196 } 197 if (isset($contentsarr['sections']) && isset($contentsarr['sections']['section'])) { 198 $sectionarr = $contentsarr['sections']['section']; 199 foreach ($sectionarr as $section) { 200 $section = (object)$section; 201 $section->settings = array(); 202 $sections[basename($section->directory)] = $section; 203 } 204 $info->sections = $sections; 205 } 206 if (isset($contentsarr['activities']) && isset($contentsarr['activities']['activity'])) { 207 $activityarr = $contentsarr['activities']['activity']; 208 foreach ($activityarr as $activity) { 209 $activity = (object)$activity; 210 $activity->settings = array(); 211 $activities[basename($activity->directory)] = $activity; 212 } 213 $info->activities = $activities; 214 } 215 $info->root_settings = array(); // For root settings 216 217 // Now the settings, putting each one under its owner 218 $settingsarr = $infoarr['settings']['setting']; 219 foreach($settingsarr as $setting) { 220 switch ($setting['level']) { 221 case 'root': 222 $info->root_settings[$setting['name']] = $setting['value']; 223 break; 224 case 'course': 225 $info->course->settings[$setting['name']] = $setting['value']; 226 break; 227 case 'section': 228 $info->sections[$setting['section']]->settings[$setting['name']] = $setting['value']; 229 break; 230 case 'activity': 231 $info->activities[$setting['activity']]->settings[$setting['name']] = $setting['value']; 232 break; 233 default: // Shouldn't happen but tolerated for portability of customized backups. 234 debugging("Unknown backup setting level: {$setting['level']}", DEBUG_DEVELOPER); 235 break; 236 } 237 } 238 239 $cache = clone $info; 240 $cachesha1 = $moodlefilesha1; 241 return $info; 242 } 243 244 /** 245 * Load and format all the needed information from a backup file. 246 * 247 * This will only extract the moodle_backup.xml file from an MBZ 248 * file and then call {@link self::get_backup_information()}. 249 * 250 * This can be a long-running (multi-minute) operation for large backups. 251 * Pass a $progress value to receive progress updates. 252 * 253 * @param string $filepath absolute path to the MBZ file. 254 * @param file_progress $progress Progress updates 255 * @return stdClass containing information. 256 * @since Moodle 2.4 257 */ 258 public static function get_backup_information_from_mbz($filepath, file_progress $progress = null) { 259 global $CFG; 260 if (!is_readable($filepath)) { 261 throw new backup_helper_exception('missing_moodle_backup_file', $filepath); 262 } 263 264 // Extract moodle_backup.xml. 265 $tmpname = 'info_from_mbz_' . time() . '_' . random_string(4); 266 $tmpdir = $CFG->tempdir . '/backup/' . $tmpname; 267 $fp = get_file_packer('application/vnd.moodle.backup'); 268 269 $extracted = $fp->extract_to_pathname($filepath, $tmpdir, array('moodle_backup.xml'), $progress); 270 $moodlefile = $tmpdir . '/' . 'moodle_backup.xml'; 271 if (!$extracted || !is_readable($moodlefile)) { 272 throw new backup_helper_exception('missing_moodle_backup_xml_file', $moodlefile); 273 } 274 275 // Read the information and delete the temporary directory. 276 $info = self::get_backup_information($tmpname); 277 remove_dir($tmpdir); 278 return $info; 279 } 280 281 /** 282 * Given the information fetched from moodle_backup.xml file 283 * decide if we are restoring in the same site the backup was 284 * generated or no. Behavior of various parts of restore are 285 * dependent of this. 286 * 287 * Backups created natively in 2.0 and later declare the hashed 288 * site identifier. Backups created by conversion from a 1.9 289 * backup do not declare such identifier, so there is a fallback 290 * to wwwroot comparison. See MDL-16614. 291 */ 292 public static function backup_is_samesite($info) { 293 global $CFG; 294 $hashedsiteid = md5(get_site_identifier()); 295 if (isset($info->original_site_identifier_hash) && !empty($info->original_site_identifier_hash)) { 296 return $info->original_site_identifier_hash == $hashedsiteid; 297 } else { 298 return $info->original_wwwroot == $CFG->wwwroot; 299 } 300 } 301 302 /** 303 * Detects the format of the given unpacked backup directory 304 * 305 * @param string $tempdir the name of the backup directory 306 * @return string one of backup::FORMAT_xxx constants 307 */ 308 public static function detect_backup_format($tempdir) { 309 global $CFG; 310 require_once($CFG->dirroot . '/backup/util/helper/convert_helper.class.php'); 311 312 if (convert_helper::detect_moodle2_format($tempdir)) { 313 return backup::FORMAT_MOODLE; 314 } 315 316 // see if a converter can identify the format 317 $converters = convert_helper::available_converters(); 318 foreach ($converters as $name) { 319 $classname = "{$name}_converter"; 320 if (!class_exists($classname)) { 321 throw new coding_exception("available_converters() is supposed to load 322 converter classes but class $classname not found"); 323 } 324 325 $detected = call_user_func($classname .'::detect_format', $tempdir); 326 if (!empty($detected)) { 327 return $detected; 328 } 329 } 330 331 return backup::FORMAT_UNKNOWN; 332 } 333 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |