[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/backup/ -> restorelib.php (source)

   1  <?php //$Id: restorelib.php,v 1.283.2.53 2008/08/21 11:26:32 mudrd8mz Exp $
   2      //Functions used in restore
   3  
   4      require_once($CFG->libdir.'/gradelib.php');
   5  
   6  /**
   7   * Group backup/restore constants, 0.
   8   */
   9  define('RESTORE_GROUPS_NONE', 0);
  10  
  11  /**
  12   * Group backup/restore constants, 1.
  13   */
  14  define('RESTORE_GROUPS_ONLY', 1);
  15  
  16  /**
  17   * Group backup/restore constants, 2.
  18   */
  19  define('RESTORE_GROUPINGS_ONLY', 2);
  20  
  21  /**
  22   * Group backup/restore constants, course/all.
  23   */
  24  define('RESTORE_GROUPS_GROUPINGS', 3);
  25  
  26      //This function unzips a zip file in the same directory that it is
  27      //It automatically uses pclzip or command line unzip
  28      function restore_unzip ($file) {
  29  
  30          return unzip_file($file, '', false);
  31  
  32      }
  33  
  34      //This function checks if moodle.xml seems to be a valid xml file
  35      //(exists, has an xml header and a course main tag
  36      function restore_check_moodle_file ($file) {
  37  
  38          $status = true;
  39  
  40          //Check if it exists
  41          if ($status = is_file($file)) {
  42              //Open it and read the first 200 bytes (chars)
  43              $handle = fopen ($file, "r");
  44              $first_chars = fread($handle,200);
  45              $status = fclose ($handle);
  46              //Chek if it has the requires strings
  47              if ($status) {
  48                  $status = strpos($first_chars,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  49                  if ($status !== false) {
  50                      $status = strpos($first_chars,"<MOODLE_BACKUP>");
  51                  }
  52              }
  53          }
  54  
  55          return $status;
  56      }
  57  
  58      //This function iterates over all modules in backup file, searching for a
  59      //MODNAME_refresh_events() to execute. Perhaps it should ve moved to central Moodle...
  60      function restore_refresh_events($restore) {
  61  
  62          global $CFG;
  63          $status = true;
  64  
  65          //Take all modules in backup
  66          $modules = $restore->mods;
  67          //Iterate
  68          foreach($modules as $name => $module) {
  69              //Only if the module is being restored
  70              if (isset($module->restore) && $module->restore == 1) {
  71                  //Include module library
  72                  include_once("$CFG->dirroot/mod/$name/lib.php");
  73                  //If module_refresh_events exists
  74                  $function_name = $name."_refresh_events";
  75                  if (function_exists($function_name)) {
  76                      $status = $function_name($restore->course_id);
  77                  }
  78              }
  79          }
  80          return $status;
  81      }
  82  
  83      //This function makes all the necessary calls to xxxx_decode_content_links_caller()
  84      //function in each module, passing them the desired contents to be decoded
  85      //from backup format to destination site/course in order to mantain inter-activities
  86      //working in the backup/restore process
  87      function restore_decode_content_links($restore) {
  88          global $CFG;
  89  
  90          $status = true;
  91  
  92          if (!defined('RESTORE_SILENTLY')) {
  93              echo "<ul>";
  94          }
  95  
  96          // Recode links in the course summary.
  97          if (!defined('RESTORE_SILENTLY')) {
  98              echo '<li>' . get_string('from') . ' ' . get_string('course');
  99          }
 100          $course = get_record('course', 'id', $restore->course_id, '', '', '', '', 'id,summary');
 101          $coursesummary = restore_decode_content_links_worker($course->summary, $restore);
 102          if ($coursesummary != $course->summary) {
 103              $course->summary = addslashes($coursesummary);
 104              if (!update_record('course', $course)) {
 105                  $status = false;
 106              }
 107          }
 108          if (!defined('RESTORE_SILENTLY')) {
 109              echo '</li>';
 110          }
 111  
 112          // Recode links in section summaries.
 113          $sections = get_records('course_sections', 'course', $restore->course_id, 'id', 'id,summary');
 114          if ($sections) {
 115              if (!defined('RESTORE_SILENTLY')) {
 116                  echo '<li>' . get_string('from') . ' ' . get_string('sections');
 117              }
 118              foreach ($sections as $section) {
 119                  $sectionsummary = restore_decode_content_links_worker($section->summary, $restore);
 120                  if ($sectionsummary != $section->summary) {
 121                      $section->summary = addslashes($sectionsummary);
 122                      if (!update_record('course_sections', $section)) {
 123                          $status = false;
 124                      }
 125                  }
 126              }
 127              if (!defined('RESTORE_SILENTLY')) {
 128                  echo '</li>';
 129              }
 130          }
 131  
 132          // Restore links in modules.
 133          foreach ($restore->mods as $name => $info) {
 134              //If the module is being restored
 135              if (isset($info->restore) && $info->restore == 1) {
 136                  //Check if the xxxx_decode_content_links_caller exists
 137                  include_once("$CFG->dirroot/mod/$name/restorelib.php");
 138                  $function_name = $name."_decode_content_links_caller";
 139                  if (function_exists($function_name)) {
 140                      if (!defined('RESTORE_SILENTLY')) {
 141                          echo "<li>".get_string ("from")." ".get_string("modulenameplural",$name);
 142                      }
 143                      $status = $function_name($restore) && $status;
 144                      if (!defined('RESTORE_SILENTLY')) {
 145                          echo '</li>';
 146                      }
 147                  }
 148              }
 149          }
 150  
 151          // Process all html text also in blocks too
 152          if (!defined('RESTORE_SILENTLY')) {
 153              echo '<li>'.get_string ('from').' '.get_string('blocks');
 154          }
 155  
 156          if ($blocks = get_records('block', 'visible', 1)) {
 157              foreach ($blocks as $block) {
 158                  if ($blockobject = block_instance($block->name)) {
 159                      $blockobject->decode_content_links_caller($restore);
 160                  }
 161              }
 162          }
 163  
 164          if (!defined('RESTORE_SILENTLY')) {
 165              echo '</li>';
 166          }
 167  
 168          // Restore links in questions.
 169          require_once("$CFG->dirroot/question/restorelib.php");
 170          if (!defined('RESTORE_SILENTLY')) {
 171              echo '<li>' . get_string('from') . ' ' . get_string('questions', 'quiz');
 172          }
 173          $status = question_decode_content_links_caller($restore) && $status;
 174          if (!defined('RESTORE_SILENTLY')) {
 175              echo '</li>';
 176          }
 177  
 178          if (!defined('RESTORE_SILENTLY')) {
 179              echo "</ul>";
 180          }
 181  
 182          return $status;
 183      }
 184  
 185      //This function is called from all xxxx_decode_content_links_caller(),
 186      //its task is to ask all modules (maybe other linkable objects) to restore
 187      //links to them.
 188      function restore_decode_content_links_worker($content,$restore) {
 189          foreach($restore->mods as $name => $info) {
 190              $function_name = $name."_decode_content_links";
 191              if (function_exists($function_name)) {
 192                  $content = $function_name($content,$restore);
 193              }
 194          }
 195  
 196          // For each block, call its encode_content_links method
 197          static $blockobjects = null; 
 198          if (!isset($blockobjects)) { 
 199              $blockobjects = array(); 
 200              if ($blocks = get_records('block', 'visible', 1)) { 
 201                  foreach ($blocks as $block) { 
 202                      if ($blockobject = block_instance($block->name)) {
 203                          $blockobjects[] = $blockobject; 
 204                      }
 205                  }
 206              }
 207          }
 208          
 209          foreach ($blockobjects as $blockobject) { 
 210              $content = $blockobject->decode_content_links($content,$restore); 
 211          }
 212  
 213          return $content;
 214      }
 215  
 216      //This function converts all the wiki texts in the restored course
 217      //to the Markdown format. Used only for backup files prior 2005041100.
 218      //It calls every module xxxx_convert_wiki2markdown function
 219      function restore_convert_wiki2markdown($restore) {
 220  
 221          $status = true;
 222  
 223          if (!defined('RESTORE_SILENTLY')) {
 224              echo "<ul>";
 225          }
 226          foreach ($restore->mods as $name => $info) {
 227              //If the module is being restored
 228              if ($info->restore == 1) {
 229                  //Check if the xxxx_restore_wiki2markdown exists
 230                  $function_name = $name."_restore_wiki2markdown";
 231                  if (function_exists($function_name)) {
 232                      $status = $function_name($restore);
 233                      if (!defined('RESTORE_SILENTLY')) {
 234                          echo "<li>".get_string("modulenameplural",$name);
 235                          echo '</li>';
 236                      }
 237                  }
 238              }
 239          }
 240          if (!defined('RESTORE_SILENTLY')) {
 241              echo "</ul>";
 242          }
 243          return $status;
 244      }
 245  
 246      //This function receives a wiki text in the restore process and
 247      //return it with every link to modules " modulename:moduleid"
 248      //converted if possible. See the space before modulename!!
 249      function restore_decode_wiki_content($content,$restore) {
 250  
 251          global $CFG;
 252  
 253          $result = $content;
 254  
 255          $searchstring='/ ([a-zA-Z]+):([0-9]+)\(([^)]+)\)/';
 256          //We look for it
 257          preg_match_all($searchstring,$content,$foundset);
 258          //If found, then we are going to look for its new id (in backup tables)
 259          if ($foundset[0]) {
 260              //print_object($foundset);                                     //Debug
 261              //Iterate over foundset[2]. They are the old_ids
 262              foreach($foundset[2] as $old_id) {
 263                  //We get the needed variables here (course id)
 264                  $rec = backup_getid($restore->backup_unique_code,"course_modules",$old_id);
 265                  //Personalize the searchstring
 266                  $searchstring='/ ([a-zA-Z]+):'.$old_id.'\(([^)]+)\)/';
 267                  //If it is a link to this course, update the link to its new location
 268                  if($rec->new_id) {
 269                      //Now replace it
 270                      $result= preg_replace($searchstring,' $1:'.$rec->new_id.'($2)',$result);
 271                  } else {
 272                      //It's a foreign link so redirect it to its original URL
 273                      $result= preg_replace($searchstring,$restore->original_wwwroot.'/mod/$1/view.php?id='.$old_id.'($2)',$result);
 274                  }
 275              }
 276          }
 277          return $result;
 278      }
 279  
 280  
 281      //This function read the xml file and store it data from the info zone in an object
 282      function restore_read_xml_info ($xml_file) {
 283  
 284          //We call the main read_xml function, with todo = INFO
 285          $info = restore_read_xml ($xml_file,"INFO",false);
 286  
 287          return $info;
 288      }
 289  
 290      //This function read the xml file and store it data from the course header zone in an object
 291      function restore_read_xml_course_header ($xml_file) {
 292  
 293          //We call the main read_xml function, with todo = COURSE_HEADER
 294          $info = restore_read_xml ($xml_file,"COURSE_HEADER",false);
 295  
 296          return $info;
 297      }
 298  
 299      //This function read the xml file and store its data from the blocks in a object
 300      function restore_read_xml_blocks ($restore, $xml_file) {
 301  
 302          //We call the main read_xml function, with todo = BLOCKS
 303          $info = restore_read_xml ($xml_file,'BLOCKS',$restore);
 304  
 305          return $info;
 306      }
 307  
 308      //This function read the xml file and store its data from the sections in a object
 309      function restore_read_xml_sections ($xml_file) {
 310  
 311          //We call the main read_xml function, with todo = SECTIONS
 312          $info = restore_read_xml ($xml_file,"SECTIONS",false);
 313  
 314          return $info;
 315      }
 316  
 317      //This function read the xml file and store its data from the course format in an object
 318      function restore_read_xml_formatdata ($xml_file) {
 319  
 320          //We call the main read_xml function, with todo = FORMATDATA
 321          $info = restore_read_xml ($xml_file,'FORMATDATA',false);
 322  
 323          return $info;
 324      }
 325  
 326      //This function read the xml file and store its data from the metacourse in a object
 327      function restore_read_xml_metacourse ($xml_file) {
 328  
 329          //We call the main read_xml function, with todo = METACOURSE
 330          $info = restore_read_xml ($xml_file,"METACOURSE",false);
 331  
 332          return $info;
 333      }
 334  
 335      //This function read the xml file and store its data from the gradebook in a object
 336      function restore_read_xml_gradebook ($restore, $xml_file) {
 337  
 338          //We call the main read_xml function, with todo = GRADEBOOK
 339          $info = restore_read_xml ($xml_file,"GRADEBOOK",$restore);
 340  
 341          return $info;
 342      }
 343  
 344      //This function read the xml file and store its data from the users in
 345      //backup_ids->info db (and user's id in $info)
 346      function restore_read_xml_users ($restore,$xml_file) {
 347  
 348          //We call the main read_xml function, with todo = USERS
 349          $info = restore_read_xml ($xml_file,"USERS",$restore);
 350  
 351          return $info;
 352      }
 353  
 354      //This function read the xml file and store its data from the messages in
 355      //backup_ids->message backup_ids->message_read and backup_ids->contact and db (and their counters in info)
 356      function restore_read_xml_messages ($restore,$xml_file) {
 357  
 358          //We call the main read_xml function, with todo = MESSAGES
 359          $info = restore_read_xml ($xml_file,"MESSAGES",$restore);
 360  
 361          return $info;
 362      }
 363  
 364      //This function read the xml file and store its data from the blogs in
 365      //backup_ids->blog and backup_ids->blog_tag and db (and their counters in info)
 366      function restore_read_xml_blogs ($restore,$xml_file) {
 367  
 368          //We call the main read_xml function, with todo = BLOGS
 369          $info = restore_read_xml ($xml_file,"BLOGS",$restore);
 370  
 371          return $info;
 372      }
 373  
 374  
 375      //This function read the xml file and store its data from the questions in
 376      //backup_ids->info db (and category's id in $info)
 377      function restore_read_xml_questions ($restore,$xml_file) {
 378  
 379          //We call the main read_xml function, with todo = QUESTIONS
 380          $info = restore_read_xml ($xml_file,"QUESTIONS",$restore);
 381  
 382          return $info;
 383      }
 384  
 385      //This function read the xml file and store its data from the scales in
 386      //backup_ids->info db (and scale's id in $info)
 387      function restore_read_xml_scales ($restore,$xml_file) {
 388  
 389          //We call the main read_xml function, with todo = SCALES
 390          $info = restore_read_xml ($xml_file,"SCALES",$restore);
 391  
 392          return $info;
 393      }
 394  
 395      //This function read the xml file and store its data from the groups in
 396      //backup_ids->info db (and group's id in $info)
 397      function restore_read_xml_groups ($restore,$xml_file) {
 398  
 399          //We call the main read_xml function, with todo = GROUPS
 400          $info = restore_read_xml ($xml_file,"GROUPS",$restore);
 401  
 402          return $info;
 403      }
 404  
 405      //This function read the xml file and store its data from the groupings in
 406      //backup_ids->info db (and grouping's id in $info)
 407      function restore_read_xml_groupings ($restore,$xml_file) {
 408  
 409          //We call the main read_xml function, with todo = GROUPINGS
 410          $info = restore_read_xml ($xml_file,"GROUPINGS",$restore);
 411  
 412          return $info;
 413      }
 414  
 415      //This function read the xml file and store its data from the groupings in
 416      //backup_ids->info db (and grouping's id in $info)
 417      function restore_read_xml_groupings_groups ($restore,$xml_file) {
 418  
 419          //We call the main read_xml function, with todo = GROUPINGS
 420          $info = restore_read_xml ($xml_file,"GROUPINGSGROUPS",$restore);
 421  
 422          return $info;
 423      }
 424  
 425      //This function read the xml file and store its data from the events (course) in
 426      //backup_ids->info db (and event's id in $info)
 427      function restore_read_xml_events ($restore,$xml_file) {
 428  
 429          //We call the main read_xml function, with todo = EVENTS
 430          $info = restore_read_xml ($xml_file,"EVENTS",$restore);
 431  
 432          return $info;
 433      }
 434  
 435      //This function read the xml file and store its data from the modules in
 436      //backup_ids->info
 437      function restore_read_xml_modules ($restore,$xml_file) {
 438  
 439          //We call the main read_xml function, with todo = MODULES
 440          $info = restore_read_xml ($xml_file,"MODULES",$restore);
 441  
 442          return $info;
 443      }
 444  
 445      //This function read the xml file and store its data from the logs in
 446      //backup_ids->info
 447      function restore_read_xml_logs ($restore,$xml_file) {
 448  
 449          //We call the main read_xml function, with todo = LOGS
 450          $info = restore_read_xml ($xml_file,"LOGS",$restore);
 451  
 452          return $info;
 453      }
 454  
 455      function restore_read_xml_roles ($xml_file) {
 456          //We call the main read_xml function, with todo = ROLES
 457          $info = restore_read_xml ($xml_file,"ROLES",false);
 458  
 459          return $info;
 460      }
 461  
 462      //This function prints the contents from the info parammeter passed
 463      function restore_print_info ($info) {
 464  
 465          global $CFG;
 466  
 467          $status = true;
 468          if ($info) {
 469              $table = new object();
 470              //This is tha align to every ingo table
 471              $table->align = array ("right","left");
 472              //This is the nowrap clause
 473              $table->wrap = array ("","nowrap");
 474              //The width
 475              $table->width = "70%";
 476              //Put interesting info in table
 477              //The backup original name
 478              $tab[0][0] = "<b>".get_string("backuporiginalname").":</b>";
 479              $tab[0][1] = $info->backup_name;
 480              //The moodle version
 481              $tab[1][0] = "<b>".get_string("moodleversion").":</b>";
 482              $tab[1][1] = $info->backup_moodle_release." (".$info->backup_moodle_version.")";
 483              //The backup version
 484              $tab[2][0] = "<b>".get_string("backupversion").":</b>";
 485              $tab[2][1] = $info->backup_backup_release." (".$info->backup_backup_version.")";
 486              //The backup date
 487              $tab[3][0] = "<b>".get_string("backupdate").":</b>";
 488              $tab[3][1] = userdate($info->backup_date);
 489              //Print title
 490              print_heading(get_string("backup").":");
 491              $table->data = $tab;
 492              //Print backup general info
 493              print_table($table);
 494  
 495              if ($info->backup_backup_version <= 2005070500) {
 496                   notify(get_string('backupnonisowarning'));  // Message informing that this backup may not work!
 497              }
 498  
 499              //Now backup contents in another table
 500              $tab = array();
 501              //First mods info
 502              $mods = $info->mods;
 503              $elem = 0;
 504              foreach ($mods as $key => $mod) {
 505                  $tab[$elem][0] = "<b>".get_string("modulenameplural",$key).":</b>";
 506                  if ($mod->backup == "false") {
 507                      $tab[$elem][1] = get_string("notincluded");
 508                  } else {
 509                      if ($mod->userinfo == "true") {
 510                          $tab[$elem][1] = get_string("included")." ".get_string("withuserdata");
 511                      } else {
 512                          $tab[$elem][1] = get_string("included")." ".get_string("withoutuserdata");
 513                      }
 514                      if (isset($mod->instances) && is_array($mod->instances) && count($mod->instances)) {
 515                          foreach ($mod->instances as $instance) {
 516                              if ($instance->backup) {
 517                                  $elem++;
 518                                  $tab[$elem][0] = $instance->name;
 519                                  if ($instance->userinfo == 'true') {
 520                                      $tab[$elem][1] = get_string("included")." ".get_string("withuserdata");
 521                                  } else {
 522                                      $tab[$elem][1] = get_string("included")." ".get_string("withoutuserdata");
 523                                  }
 524                              }
 525                          }
 526                      }
 527                  }
 528                  $elem++;
 529              }
 530              //Metacourse info
 531              $tab[$elem][0] = "<b>".get_string("metacourse").":</b>";
 532              if ($info->backup_metacourse == "true") {
 533                  $tab[$elem][1] = get_string("yes");
 534              } else {
 535                  $tab[$elem][1] = get_string("no");
 536              }
 537              $elem++;
 538              //Users info
 539              $tab[$elem][0] = "<b>".get_string("users").":</b>";
 540              $tab[$elem][1] = get_string($info->backup_users);
 541              $elem++;
 542              //Logs info
 543              $tab[$elem][0] = "<b>".get_string("logs").":</b>";
 544              if ($info->backup_logs == "true") {
 545                  $tab[$elem][1] = get_string("yes");
 546              } else {
 547                  $tab[$elem][1] = get_string("no");
 548              }
 549              $elem++;
 550              //User Files info
 551              $tab[$elem][0] = "<b>".get_string("userfiles").":</b>";
 552              if ($info->backup_user_files == "true") {
 553                  $tab[$elem][1] = get_string("yes");
 554              } else {
 555                  $tab[$elem][1] = get_string("no");
 556              }
 557              $elem++;
 558              //Course Files info
 559              $tab[$elem][0] = "<b>".get_string("coursefiles").":</b>";
 560              if ($info->backup_course_files == "true") {
 561                  $tab[$elem][1] = get_string("yes");
 562              } else {
 563                  $tab[$elem][1] = get_string("no");
 564              }
 565              $elem++;
 566              //site Files info
 567              $tab[$elem][0] = "<b>".get_string("sitefiles").":</b>";
 568              if (isset($info->backup_site_files) && $info->backup_site_files == "true") {
 569                  $tab[$elem][1] = get_string("yes");
 570              } else {
 571                  $tab[$elem][1] = get_string("no");
 572              }
 573              $elem++;
 574              //gradebook history info
 575              $tab[$elem][0] = "<b>".get_string('gradebookhistories', 'grades').":</b>";
 576              if (isset($info->gradebook_histories) && $info->gradebook_histories == "true") {
 577                  $tab[$elem][1] = get_string("yes");
 578              } else {
 579                  $tab[$elem][1] = get_string("no");
 580              }
 581              $elem++;
 582              //Messages info (only showed if present)
 583              if ($info->backup_messages == 'true') {
 584                  $tab[$elem][0] = "<b>".get_string('messages','message').":</b>";
 585                  $tab[$elem][1] = get_string('yes');
 586                  $elem++;
 587              } else {
 588                  //Do nothing
 589              }
 590              $elem++;
 591              //Blogs info (only showed if present)
 592              if (isset($info->backup_blogs) && $info->backup_blogs == 'true') {
 593                  $tab[$elem][0] = "<b>".get_string('blogs','blog').":</b>";
 594                  $tab[$elem][1] = get_string('yes');
 595                  $elem++;
 596              } else {
 597                  //Do nothing
 598              }
 599              $table->data = $tab;
 600              //Print title
 601              print_heading(get_string("backupdetails").":");
 602              //Print backup general info
 603              print_table($table);
 604          } else {
 605              $status = false;
 606          }
 607  
 608          return $status;
 609      }
 610  
 611      //This function prints the contents from the course_header parammeter passed
 612      function restore_print_course_header ($course_header) {
 613  
 614          $status = true;
 615          if ($course_header) {
 616              $table = new object();
 617              //This is tha align to every ingo table
 618              $table->align = array ("right","left");
 619              //The width
 620              $table->width = "70%";
 621              //Put interesting course header in table
 622              //The course name
 623              $tab[0][0] = "<b>".get_string("name").":</b>";
 624              $tab[0][1] = $course_header->course_fullname." (".$course_header->course_shortname.")";
 625              //The course summary
 626              $tab[1][0] = "<b>".get_string("summary").":</b>";
 627              $tab[1][1] = $course_header->course_summary;
 628              $table->data = $tab;
 629              //Print title
 630              print_heading(get_string("course").":");
 631              //Print backup course header info
 632              print_table($table);
 633          } else {
 634              $status = false;
 635          }
 636          return $status;
 637      }
 638  
 639      //This function create a new course record.
 640      //When finished, course_header contains the id of the new course
 641      function restore_create_new_course($restore,&$course_header) {
 642  
 643          global $CFG;
 644  
 645          $status = true;
 646  
 647          $fullname = $course_header->course_fullname;
 648          $shortname = $course_header->course_shortname;
 649          $currentfullname = "";
 650          $currentshortname = "";
 651          $counter = 0;
 652          //Iteratere while the name exists
 653          do {
 654              if ($counter) {
 655                  $suffixfull = " ".get_string("copyasnoun")." ".$counter;
 656                  $suffixshort = "_".$counter;
 657              } else {
 658                  $suffixfull = "";
 659                  $suffixshort = "";
 660              }
 661              $currentfullname = $fullname.$suffixfull;
 662              // Limit the size of shortname - database column accepts <= 100 chars
 663              $currentshortname = substr($shortname, 0, 100 - strlen($suffixshort)).$suffixshort;
 664              $coursefull  = get_record("course","fullname",addslashes($currentfullname));
 665              $courseshort = get_record("course","shortname",addslashes($currentshortname));
 666              $counter++;
 667          } while ($coursefull || $courseshort);
 668  
 669          //New name = currentname
 670          $course_header->course_fullname = $currentfullname;
 671          $course_header->course_shortname = $currentshortname;
 672  
 673          // first try to get it from restore
 674          if ($restore->restore_restorecatto) {
 675              $category = get_record('course_categories', 'id', $restore->restore_restorecatto);
 676          }
 677  
 678          // else we try to get it from the xml file
 679          //Now calculate the category
 680          if (empty($category)) {
 681              $category = get_record("course_categories","id",$course_header->category->id,
 682                                     "name",addslashes($course_header->category->name));
 683          }
 684  
 685          //If no exists, try by name only
 686          if (!$category) {
 687              $category = get_record("course_categories","name",addslashes($course_header->category->name));
 688          }
 689  
 690          //If no exists, get category id 1
 691          if (!$category) {
 692              $category = get_record("course_categories","id","1");
 693          }
 694  
 695          //If category 1 doesn'exists, lets create the course category (get it from backup file)
 696          if (!$category) {
 697              $ins_category = new object();
 698              $ins_category->name = addslashes($course_header->category->name);
 699              $ins_category->parent = 0;
 700              $ins_category->sortorder = 0;
 701              $ins_category->coursecount = 0;
 702              $ins_category->visible = 0;            //To avoid interferences with the rest of the site
 703              $ins_category->timemodified = time();
 704              $newid = insert_record("course_categories",$ins_category);
 705              $category->id = $newid;
 706              $category->name = $course_header->category->name;
 707          }
 708          //If exists, put new category id
 709          if ($category) {
 710              $course_header->category->id = $category->id;
 711              $course_header->category->name = $category->name;
 712          //Error, cannot locate category
 713          } else {
 714              $course_header->category->id = 0;
 715              $course_header->category->name = get_string("unknowncategory");
 716              $status = false;
 717          }
 718  
 719          //Create the course_object
 720          if ($status) {
 721              $course = new object();
 722              $course->category = addslashes($course_header->category->id);
 723              $course->password = addslashes($course_header->course_password);
 724              $course->fullname = addslashes($course_header->course_fullname);
 725              $course->shortname = addslashes($course_header->course_shortname);
 726              $course->idnumber = addslashes($course_header->course_idnumber);
 727              $course->idnumber = ''; //addslashes($course_header->course_idnumber); // we don't want this at all.
 728              $course->summary = backup_todb($course_header->course_summary);
 729              $course->format = addslashes($course_header->course_format);
 730              $course->showgrades = addslashes($course_header->course_showgrades);
 731              $course->newsitems = addslashes($course_header->course_newsitems);
 732              $course->teacher = addslashes($course_header->course_teacher);
 733              $course->teachers = addslashes($course_header->course_teachers);
 734              $course->student = addslashes($course_header->course_student);
 735              $course->students = addslashes($course_header->course_students);
 736              $course->guest = addslashes($course_header->course_guest);
 737              $course->startdate = addslashes($course_header->course_startdate);
 738              $course->startdate += $restore->course_startdateoffset;
 739              $course->numsections = addslashes($course_header->course_numsections);
 740              //$course->showrecent = addslashes($course_header->course_showrecent);   INFO: This is out in 1.3
 741              $course->maxbytes = addslashes($course_header->course_maxbytes);
 742              $course->showreports = addslashes($course_header->course_showreports);
 743              if (isset($course_header->course_groupmode)) {
 744                  $course->groupmode = addslashes($course_header->course_groupmode);
 745              }
 746              if (isset($course_header->course_groupmodeforce)) {
 747                  $course->groupmodeforce = addslashes($course_header->course_groupmodeforce);
 748              }
 749              if (isset($course_header->course_defaultgroupingid)) {
 750                  //keep the original now - convert after groupings restored
 751                  $course->defaultgroupingid = addslashes($course_header->course_defaultgroupingid);
 752              }
 753              $course->lang = addslashes($course_header->course_lang);
 754              $course->theme = addslashes($course_header->course_theme);
 755              $course->cost = addslashes($course_header->course_cost);
 756              $course->currency = isset($course_header->course_currency)?addslashes($course_header->course_currency):'';
 757              $course->marker = addslashes($course_header->course_marker);
 758              $course->visible = addslashes($course_header->course_visible);
 759              $course->hiddensections = addslashes($course_header->course_hiddensections);
 760              $course->timecreated = addslashes($course_header->course_timecreated);
 761              $course->timemodified = addslashes($course_header->course_timemodified);
 762              $course->metacourse = addslashes($course_header->course_metacourse);
 763              $course->expirynotify = isset($course_header->course_expirynotify) ? addslashes($course_header->course_expirynotify):0;
 764              $course->notifystudents = isset($course_header->course_notifystudents) ? addslashes($course_header->course_notifystudents) : 0;
 765              $course->expirythreshold = isset($course_header->course_expirythreshold) ? addslashes($course_header->course_expirythreshold) : 0;
 766              $course->enrollable = isset($course_header->course_enrollable) ? addslashes($course_header->course_enrollable) : 1;
 767              $course->enrolstartdate = isset($course_header->course_enrolstartdate) ? addslashes($course_header->course_enrolstartdate) : 0;
 768              if ($course->enrolstartdate)  { //Roll course dates
 769                  $course->enrolstartdate += $restore->course_startdateoffset;
 770              }
 771              $course->enrolenddate = isset($course_header->course_enrolenddate) ? addslashes($course_header->course_enrolenddate) : 0;
 772              if ($course->enrolenddate) { //Roll course dates
 773                  $course->enrolenddate  += $restore->course_startdateoffset;
 774              }
 775              $course->enrolperiod = addslashes($course_header->course_enrolperiod);
 776              //Calculate sortorder field
 777              $sortmax = get_record_sql('SELECT MAX(sortorder) AS max
 778                                         FROM ' . $CFG->prefix . 'course
 779                                         WHERE category=' . $course->category);
 780              if (!empty($sortmax->max)) {
 781                  $course->sortorder = $sortmax->max + 1;
 782                  unset($sortmax);
 783              } else {
 784                  $course->sortorder = 100;
 785              }
 786  
 787              //Now, recode some languages (Moodle 1.5)
 788              if ($course->lang == 'ma_nt') {
 789                  $course->lang = 'mi_nt';
 790              }
 791  
 792              //Disable course->metacourse if avoided in restore config
 793              if (!$restore->metacourse) {
 794                  $course->metacourse = 0;
 795              }
 796  
 797              //Check if the theme exists in destination server
 798              $themes = get_list_of_themes();
 799              if (!in_array($course->theme, $themes)) {
 800                  $course->theme = '';
 801              }
 802  
 803              //Now insert the record
 804              $newid = insert_record("course",$course);
 805              if ($newid) {
 806                  //save old and new course id
 807                  backup_putid ($restore->backup_unique_code,"course",$course_header->course_id,$newid);
 808                  //Replace old course_id in course_header
 809                  $course_header->course_id = $newid;
 810              } else {
 811                  $status = false;
 812              }
 813          }
 814  
 815          return $status;
 816      }
 817  
 818  
 819  
 820      //This function creates all the block stuff when restoring courses
 821      //It calls selectively to  restore_create_block_instances() for 1.5
 822      //and above backups. Upwards compatible with old blocks.
 823      function restore_create_blocks($restore, $backup_block_format, $blockinfo, $xml_file) {
 824          global $CFG;
 825          $status = true;
 826  
 827          delete_records('block_instance', 'pageid', $restore->course_id, 'pagetype', PAGE_COURSE_VIEW);
 828          if (empty($backup_block_format)) {     // This is a backup from Moodle < 1.5
 829              if (empty($blockinfo)) {
 830                  // Looks like it's from Moodle < 1.3. Let's give the course default blocks...
 831                  $newpage = page_create_object(PAGE_COURSE_VIEW, $restore->course_id);
 832                  blocks_repopulate_page($newpage);
 833              } else {
 834                  // We just have a blockinfo field, this is a legacy 1.4 or 1.3 backup
 835                  $blockrecords = get_records_select('block', '', '', 'name, id');
 836                  $temp_blocks_l = array();
 837                  $temp_blocks_r = array();
 838                  @list($temp_blocks_l, $temp_blocks_r) = explode(':', $blockinfo);
 839                  $temp_blocks = array(BLOCK_POS_LEFT => explode(',', $temp_blocks_l), BLOCK_POS_RIGHT => explode(',', $temp_blocks_r));
 840                  foreach($temp_blocks as $blockposition => $blocks) {
 841                      $blockweight = 0;
 842                      foreach($blocks as $blockname) {
 843                          if(!isset($blockrecords[$blockname])) {
 844                              // We don't know anything about this block!
 845                              continue;
 846                          }
 847                          $blockinstance = new stdClass;
 848                          // Remove any - prefix before doing the name-to-id mapping
 849                          if(substr($blockname, 0, 1) == '-') {
 850                              $blockname = substr($blockname, 1);
 851                              $blockinstance->visible = 0;
 852                          } else {
 853                              $blockinstance->visible = 1;
 854                          }
 855                          $blockinstance->blockid  = $blockrecords[$blockname]->id;
 856                          $blockinstance->pageid   = $restore->course_id;
 857                          $blockinstance->pagetype = PAGE_COURSE_VIEW;
 858                          $blockinstance->position = $blockposition;
 859                          $blockinstance->weight   = $blockweight;
 860                          if(!$status = insert_record('block_instance', $blockinstance)) {
 861                              $status = false;
 862                          }
 863                          ++$blockweight;
 864                      }
 865                  }
 866              }
 867          } else if($backup_block_format == 'instances') {
 868              $status = restore_create_block_instances($restore,$xml_file);
 869          }
 870  
 871          return $status;
 872  
 873      }
 874  
 875      //This function creates all the block_instances from xml when restoring in a
 876      //new course
 877      function restore_create_block_instances($restore,$xml_file) {
 878          global $CFG;
 879          $status = true;
 880  
 881          //Check it exists
 882          if (!file_exists($xml_file)) {
 883              $status = false;
 884          }
 885          //Get info from xml
 886          if ($status) {
 887              $info = restore_read_xml_blocks($restore,$xml_file);
 888          }
 889  
 890          if(empty($info->instances)) {
 891              return $status;
 892          }
 893  
 894          // First of all, iterate over the blocks to see which distinct pages we have
 895          // in our hands and arrange the blocks accordingly.
 896          $pageinstances = array();
 897          foreach($info->instances as $instance) {
 898  
 899              //pagetype and pageid black magic, we have to handle the case of blocks for the
 900              //course, blocks from other pages in that course etc etc etc.
 901  
 902              if($instance->pagetype == PAGE_COURSE_VIEW) {
 903                  // This one's easy...
 904                  $instance->pageid  = $restore->course_id;
 905  
 906              } else if (!empty($CFG->showblocksonmodpages)) {
 907                  $parts = explode('-', $instance->pagetype);
 908                  if($parts[0] == 'mod') {
 909                      if(!$restore->mods[$parts[1]]->restore) {
 910                          continue;
 911                      }
 912                      $getid = backup_getid($restore->backup_unique_code, $parts[1], $instance->pageid);
 913  
 914                      if (empty($getid->new_id)) {
 915                          // Failed, perhaps the module was not included in the restore  MDL-13554
 916                          continue;
 917                      }
 918                      $instance->pageid = $getid->new_id;
 919                  }
 920                  else {
 921                      // Not invented here ;-)
 922                      continue;
 923                  }
 924  
 925              } else {
 926                  // do not restore activity blocks if disabled
 927                  continue;
 928              }
 929  
 930              if(!isset($pageinstances[$instance->pagetype])) {
 931                  $pageinstances[$instance->pagetype] = array();
 932              }
 933              if(!isset($pageinstances[$instance->pagetype][$instance->pageid])) {
 934                  $pageinstances[$instance->pagetype][$instance->pageid] = array();
 935              }
 936  
 937              $pageinstances[$instance->pagetype][$instance->pageid][] = $instance;
 938          }
 939  
 940          $blocks = get_records_select('block', 'visible = 1', '', 'name, id, multiple');
 941  
 942          // For each type of page we have restored
 943          foreach($pageinstances as $thistypeinstances) {
 944  
 945              // For each page id of that type
 946              foreach($thistypeinstances as $thisidinstances) {
 947  
 948                  $addedblocks = array();
 949                  $maxweights  = array();
 950  
 951                  // For each block instance in that page
 952                  foreach($thisidinstances as $instance) {
 953  
 954                      if(!isset($blocks[$instance->name])) {
 955                          //We are trying to restore a block we don't have...
 956                          continue;
 957                      }
 958  
 959                      //If we have already added this block once and multiples aren't allowed, disregard it
 960                      if(!$blocks[$instance->name]->multiple && isset($addedblocks[$instance->name])) {
 961                          continue;
 962                      }
 963  
 964                      //If its the first block we add to a new position, start weight counter equal to 0.
 965                      if(empty($maxweights[$instance->position])) {
 966                          $maxweights[$instance->position] = 0;
 967                      }
 968  
 969                      //If the instance weight is greater than the weight counter (we skipped some earlier
 970                      //blocks most probably), bring it back in line.
 971                      if($instance->weight > $maxweights[$instance->position]) {
 972                          $instance->weight = $maxweights[$instance->position];
 973                      }
 974  
 975                      //Add this instance
 976                      $instance->blockid = $blocks[$instance->name]->id;
 977  
 978                      // This will only be set if we come from 1.7 and above backups
 979                      //  Also, must do this before insert (insert_record unsets id)
 980                      if (!empty($instance->id)) { 
 981                          $oldid = $instance->id;
 982                      } else {
 983                          $oldid = 0;
 984                      }
 985  
 986                      if ($instance->id = insert_record('block_instance', $instance)) {
 987                          // Create block instance
 988                          if (!$blockobj = block_instance($instance->name, $instance)) {
 989                              $status = false;
 990                              break;
 991                          }
 992                          // Run the block restore if needed
 993                          if ($blockobj->backuprestore_instancedata_used()) {
 994                              // Get restore information
 995                              $data = backup_getid($restore->backup_unique_code,'block_instance',$oldid);
 996                              $data->new_id = $instance->id;  // For completeness
 997                              if (!$blockobj->instance_restore($restore, $data)) {
 998                                  $status = false;
 999                                  break;
1000                              }
1001                          }
1002                          // Save oldid after block restore process because info will be over-written with blank string
1003                          if ($oldid) {
1004                              backup_putid ($restore->backup_unique_code,"block_instance",$oldid,$instance->id);
1005                          }
1006  
1007                      } else {
1008                          $status = false;
1009                          break;
1010                      }
1011  
1012                      //Get an object for the block and tell it it's been restored so it can update dates
1013                      //etc. if necessary
1014                      if ($blockobj = block_instance($instance->name,$instance)) {
1015                          $blockobj->after_restore($restore);
1016                      }
1017  
1018                      //Now we can increment the weight counter
1019                      ++$maxweights[$instance->position];
1020  
1021                      //Keep track of block types we have already added
1022                      $addedblocks[$instance->name] = true;
1023  
1024                  }
1025              }
1026          }
1027  
1028          return $status;
1029      }
1030  
1031      //This function creates all the course_sections and course_modules from xml
1032      //when restoring in a new course or simply checks sections and create records
1033      //in backup_ids when restoring in a existing course
1034      function restore_create_sections(&$restore, $xml_file) {
1035  
1036          global $CFG,$db;
1037  
1038          $status = true;
1039          //Check it exists
1040          if (!file_exists($xml_file)) {
1041              $status = false;
1042          }
1043          //Get info from xml
1044          if ($status) {
1045              $info = restore_read_xml_sections($xml_file);
1046          }
1047          //Put the info in the DB, recoding ids and saving the in backup tables
1048  
1049          $sequence = "";
1050  
1051          if ($info) {
1052              //For each, section, save it to db
1053              foreach ($info->sections as $key => $sect) {
1054                  $sequence = "";
1055                  $section = new object();
1056                  $section->course = $restore->course_id;
1057                  $section->section = $sect->number;
1058                  $section->summary = backup_todb($sect->summary);
1059                  $section->visible = $sect->visible;
1060                  $section->sequence = "";
1061                  //Now calculate the section's newid
1062                  $newid = 0;
1063                  if ($restore->restoreto == 2) {
1064                      //Save it to db (only if restoring to new course)
1065                      $newid = insert_record("course_sections",$section);
1066                  } else {
1067                      //Get section id when restoring in existing course
1068                      $rec = get_record("course_sections","course",$restore->course_id,
1069                                                          "section",$section->section);
1070                      //If that section doesn't exist, get section 0 (every mod will be
1071                      //asigned there
1072                      if(!$rec) {
1073                          $rec = get_record("course_sections","course",$restore->course_id,
1074                                                              "section","0");
1075                      }
1076                      //New check. If section 0 doesn't exist, insert it here !!
1077                      //Teorically this never should happen but, in practice, some users
1078                      //have reported this issue.
1079                      if(!$rec) {
1080                          $zero_sec = new object();
1081                          $zero_sec->course = $restore->course_id;
1082                          $zero_sec->section = 0;
1083                          $zero_sec->summary = "";
1084                          $zero_sec->sequence = "";
1085                          $newid = insert_record("course_sections",$zero_sec);
1086                          $rec->id = $newid;
1087                          $rec->sequence = "";
1088                      }
1089                      $newid = $rec->id;
1090                      $sequence = $rec->sequence;
1091                  }
1092                  if ($newid) {
1093                      //save old and new section id
1094                      backup_putid ($restore->backup_unique_code,"course_sections",$key,$newid);
1095                  } else {
1096                      $status = false;
1097                  }
1098                  //If all is OK, go with associated mods
1099                  if ($status) {
1100                      //If we have mods in the section
1101                      if (!empty($sect->mods)) {
1102                          //For each mod inside section
1103                          foreach ($sect->mods as $keym => $mod) {
1104                              // Yu: This part is called repeatedly for every instance,
1105                              // so it is necessary to set the granular flag and check isset()
1106                              // when the first instance of this type of mod is processed.
1107  
1108                              //if (!isset($restore->mods[$mod->type]->granular) && isset($restore->mods[$mod->type]->instances) && is_array($restore->mods[$mod->type]->instances)) {
1109  
1110                              if (!isset($restore->mods[$mod->type]->granular)) {
1111                                  if (isset($restore->mods[$mod->type]->instances) && is_array($restore->mods[$mod->type]->instances)) {
1112                                      // This defines whether we want to restore specific
1113                                      // instances of the modules (granular restore), or
1114                                      // whether we don't care and just want to restore
1115                                      // all module instances (non-granular).
1116                                      $restore->mods[$mod->type]->granular = true;
1117                                  } else {
1118                                      $restore->mods[$mod->type]->granular = false;
1119                                  }
1120                              }
1121  
1122                              //Check if we've to restore this module (and instance)
1123                              if (!empty($restore->mods[$mod->type]->restore)) {
1124                                  if (empty($restore->mods[$mod->type]->granular)  // we don't care about per instance
1125                                      || (array_key_exists($mod->instance,$restore->mods[$mod->type]->instances)
1126                                          && !empty($restore->mods[$mod->type]->instances[$mod->instance]->restore))) {
1127  
1128                                      //Get the module id from modules
1129                                      $module = get_record("modules","name",$mod->type);
1130                                      if ($module) {
1131                                          $course_module = new object();
1132                                          $course_module->course = $restore->course_id;
1133                                          $course_module->module = $module->id;
1134                                          $course_module->section = $newid;
1135                                          $course_module->added = $mod->added;
1136                                          $course_module->score = $mod->score;
1137                                          $course_module->indent = $mod->indent;
1138                                          $course_module->visible = $mod->visible;
1139                                          $course_module->groupmode = $mod->groupmode;
1140                                          if ($mod->groupingid and $grouping = restore_grouping_getid($restore, $mod->groupingid)) {
1141                                              $course_module->groupingid = $grouping->new_id;
1142                                          } else {
1143                                              $course_module->groupingid = 0;
1144                                          }
1145                                          $course_module->groupmembersonly = $mod->groupmembersonly;
1146                                          $course_module->instance = 0;
1147                                          //NOTE: The instance (new) is calculated and updated in db in the
1148                                          //      final step of the restore. We don't know it yet.
1149                                          //print_object($course_module);                    //Debug
1150                                          //Save it to db
1151                                          if ($mod->idnumber) {
1152                                              if (grade_verify_idnumber($mod->idnumber, $restore->course_id)) {
1153                                                  $course_module->idnumber = $mod->idnumber;
1154                                              }
1155                                          }
1156  
1157                                          $newidmod = insert_record("course_modules", addslashes_recursive($course_module));
1158                                          if ($newidmod) {
1159                                              //save old and new module id
1160                                              //In the info field, we save the original instance of the module
1161                                              //to use it later
1162                                              backup_putid ($restore->backup_unique_code,"course_modules",
1163                                                            $keym,$newidmod,$mod->instance);
1164  
1165                                              $restore->mods[$mod->type]->instances[$mod->instance]->restored_as_course_module = $newidmod;
1166                                          } else {
1167                                              $status = false;
1168                                          }
1169                                          //Now, calculate the sequence field
1170                                          if ($status) {
1171                                              if ($sequence) {
1172                                                  $sequence .= ",".$newidmod;
1173                                              } else {
1174                                                  $sequence = $newidmod;
1175                                              }
1176                                          }
1177                                      } else {
1178                                          $status = false;
1179                                      }
1180                                  }
1181                              }
1182                          }
1183                      }
1184                  }
1185                  //If all is OK, update sequence field in course_sections
1186                  if ($status) {
1187                      if (isset($sequence)) {
1188                          $update_rec = new object();
1189                          $update_rec->id = $newid;
1190                          $update_rec->sequence = $sequence;
1191                          $status = update_record("course_sections",$update_rec);
1192                      }
1193                  }
1194              }
1195          } else {
1196              $status = false;
1197          }
1198          return $status;
1199      }
1200  
1201      //Called to set up any course-format specific data that may be in the file
1202      function restore_set_format_data($restore,$xml_file) {
1203          global $CFG,$db;
1204  
1205          $status = true;
1206          //Check it exists
1207          if (!file_exists($xml_file)) {
1208              return false;
1209          }
1210          //Load data from XML to info
1211          if(!($info = restore_read_xml_formatdata($xml_file))) {
1212                  return false;
1213          }
1214  
1215          //Process format data if there is any
1216          if (isset($info->format_data)) {
1217                  if(!$format=get_field('course','format','id',$restore->course_id)) {
1218                      return false;
1219                  }
1220                  // If there was any data then it must have a restore method
1221                  $file=$CFG->dirroot."/course/format/$format/restorelib.php";
1222                  if(!file_exists($file)) {
1223                      return false;
1224                  }
1225                  require_once($file);
1226                  $function=$format.'_restore_format_data';
1227                  if(!function_exists($function)) {
1228                      return false;
1229                  }
1230                  return $function($restore,$info->format_data);
1231          }
1232  
1233          // If we got here then there's no data, but that's cool
1234          return true;
1235      }
1236  
1237      //This function creates all the metacourse data from xml, notifying
1238      //about each incidence
1239      function restore_create_metacourse($restore,$xml_file) {
1240  
1241          global $CFG,$db;
1242  
1243          $status = true;
1244          //Check it exists
1245          if (!file_exists($xml_file)) {
1246              $status = false;
1247          }
1248          //Get info from xml
1249          if ($status) {
1250              //Load data from XML to info
1251              $info = restore_read_xml_metacourse($xml_file);
1252          }
1253  
1254          //Process info about metacourse
1255          if ($status and $info) {
1256              //Process child records
1257              if (!empty($info->childs)) {
1258                  foreach ($info->childs as $child) {
1259                      $dbcourse = false;
1260                      $dbmetacourse = false;
1261                      //Check if child course exists in destination server
1262                      //(by id in the same server or by idnumber and shortname in other server)
1263                      if ($restore->original_wwwroot == $CFG->wwwroot) {
1264                          //Same server, lets see by id
1265                          $dbcourse = get_record('course','id',$child->id);
1266                      } else {
1267                          //Different server, lets see by idnumber and shortname, and only ONE record
1268                          $dbcount = count_records('course','idnumber',$child->idnumber,'shortname',$child->shortname);
1269                          if ($dbcount == 1) {
1270                              $dbcourse = get_record('course','idnumber',$child->idnumber,'shortname',$child->shortname);
1271                          }
1272                      }
1273                      //If child course has been found, insert data
1274                      if ($dbcourse) {
1275                          $dbmetacourse->child_course = $dbcourse->id;
1276                          $dbmetacourse->parent_course = $restore->course_id;
1277                          $status = insert_record ('course_meta',$dbmetacourse);
1278                      } else {
1279                          //Child course not found, notice!
1280                          if (!defined('RESTORE_SILENTLY')) {
1281                              echo '<ul><li>'.get_string ('childcoursenotfound').' ('.$child->id.'/'.$child->idnumber.'/'.$child->shortname.')</li></ul>';
1282                          }
1283                      }
1284                  }
1285                  //Now, recreate student enrolments...
1286                  sync_metacourse($restore->course_id);
1287              }
1288              //Process parent records
1289              if (!empty($info->parents)) {
1290                  foreach ($info->parents as $parent) {
1291                      $dbcourse = false;
1292                      $dbmetacourse = false;
1293                      //Check if parent course exists in destination server
1294                      //(by id in the same server or by idnumber and shortname in other server)
1295                      if ($restore->original_wwwroot == $CFG->wwwroot) {
1296                          //Same server, lets see by id
1297                          $dbcourse = get_record('course','id',$parent->id);
1298                      } else {
1299                          //Different server, lets see by idnumber and shortname, and only ONE record
1300                          $dbcount = count_records('course','idnumber',$parent->idnumber,'shortname',$parent->shortname);
1301                          if ($dbcount == 1) {
1302                              $dbcourse = get_record('course','idnumber',$parent->idnumber,'shortname',$parent->shortname);
1303                          }
1304                      }
1305                      //If parent course has been found, insert data if it is a metacourse
1306                      if ($dbcourse) {
1307                          if ($dbcourse->metacourse) {
1308                              $dbmetacourse->parent_course = $dbcourse->id;
1309                              $dbmetacourse->child_course = $restore->course_id;
1310                              $status = insert_record ('course_meta',$dbmetacourse);
1311                              //Now, recreate student enrolments in parent course
1312                              sync_metacourse($dbcourse->id);
1313                          } else {
1314                              //Parent course isn't metacourse, notice!
1315                              if (!defined('RESTORE_SILENTLY')) {
1316                                  echo '<ul><li>'.get_string ('parentcoursenotmetacourse').' ('.$parent->id.'/'.$parent->idnumber.'/'.$parent->shortname.')</li></ul>';
1317                              }
1318                          }
1319                      } else {
1320                          //Parent course not found, notice!
1321                          if (!defined('RESTORE_SILENTLY')) {
1322                              echo '<ul><li>'.get_string ('parentcoursenotfound').' ('.$parent->id.'/'.$parent->idnumber.'/'.$parent->shortname.')</li></ul>';
1323                          }
1324                      }
1325                  }
1326              }
1327  
1328          }
1329          return $status;
1330      }
1331  
1332      /**
1333       * This function migrades all the pre 1.9 gradebook data from xml
1334       */
1335      function restore_migrate_old_gradebook($restore,$xml_file) {
1336          global $CFG;
1337  
1338          $status = true;
1339          //Check it exists
1340          if (!file_exists($xml_file)) {
1341              return false;
1342          }
1343  
1344          // Get info from xml
1345          // info will contain the number of record to process
1346          $info = restore_read_xml_gradebook($restore, $xml_file);
1347  
1348          // If we have info, then process
1349          if (empty($info)) {
1350              return $status;
1351          }
1352  
1353          // make sure top course category exists
1354          $course_category = grade_category::fetch_course_category($restore->course_id);
1355          $course_category->load_grade_item();
1356  
1357          // we need to know if all grade items that were backed up are being restored
1358          // if that is not the case, we do not restore grade categories nor gradeitems of category type or course type
1359          // i.e. the aggregated grades of that category
1360  
1361          $restoreall = true;  // set to false if any grade_item is not selected/restored
1362          $importing  = !empty($SESSION->restore->importing); // there should not be a way to import old backups, but anyway ;-)
1363  
1364          if ($importing) {
1365              $restoreall = false;
1366  
1367          } else {
1368              $prev_grade_items = grade_item::fetch_all(array('courseid'=>$restore->course_id));
1369              $prev_grade_cats  = grade_category::fetch_all(array('courseid'=>$restore->course_id));
1370  
1371               // if any categories already present, skip restore of categories from backup
1372              if (count($prev_grade_items) > 1 or count($prev_grade_cats) > 1) {
1373                  $restoreall = false;
1374              }
1375              unset($prev_grade_items);
1376              unset($prev_grade_cats);
1377          }
1378  
1379          // force creation of all grade_items - the course_modules already exist
1380          grade_force_full_regrading($restore->course_id);
1381          grade_grab_course_grades($restore->course_id);
1382  
1383          // Start ul
1384          if (!defined('RESTORE_SILENTLY')) {
1385              echo '<ul>';
1386          }
1387  
1388      /// Process letters
1389          $context = get_context_instance(CONTEXT_COURSE, $restore->course_id);
1390          // respect current grade letters if defined
1391          if ($status and $restoreall and !record_exists('grade_letters', 'contextid', $context->id)) {
1392              if (!defined('RESTORE_SILENTLY')) {
1393                  echo '<li>'.get_string('gradeletters','grades').'</li>';
1394              }
1395              // Fetch recordset_size records in each iteration
1396              $recs = get_records_select("backup_ids","table_name = 'grade_letter' AND backup_code = $restore->backup_unique_code",
1397                                          "",
1398                                          "old_id");
1399              if ($recs) {
1400                  foreach ($recs as $rec) {
1401                      // Get the full record from backup_ids
1402                      $data = backup_getid($restore->backup_unique_code,'grade_letter',$rec->old_id);
1403                      if ($data) {
1404                          $info = $data->info;
1405                          $dbrec = new object();
1406                          $dbrec->contextid     = $context->id;
1407                          $dbrec->lowerboundary = backup_todb($info['GRADE_LETTER']['#']['GRADE_LOW']['0']['#']);
1408                          $dbrec->letter        = backup_todb($info['GRADE_LETTER']['#']['LETTER']['0']['#']);
1409                          insert_record('grade_letters', $dbrec);
1410                      }
1411                  }
1412              }
1413          }
1414  
1415          if (!defined('RESTORE_SILENTLY')) {
1416              echo '<li>'.get_string('categories','grades').'</li>';
1417          }
1418          //Fetch recordset_size records in each iteration
1419          $recs = get_records_select("backup_ids","table_name = 'grade_category' AND backup_code = $restore->backup_unique_code",
1420                                     "old_id",
1421                                     "old_id");
1422          $cat_count = count($recs);
1423          if ($recs) {
1424              foreach ($recs as $rec) {
1425                  //Get the full record from backup_ids
1426                  $data = backup_getid($restore->backup_unique_code,'grade_category',$rec->old_id);
1427                  if ($data) {
1428                      //Now get completed xmlized object
1429                      $info = $data->info;
1430  
1431                      if ($restoreall) {
1432                          if ($cat_count == 1) {
1433                              $course_category->fullname            = backup_todb($info['GRADE_CATEGORY']['#']['NAME']['0']['#'], false);
1434                              $course_category->droplow             = backup_todb($info['GRADE_CATEGORY']['#']['DROP_X_LOWEST']['0']['#'], false);
1435                              $course_category->aggregation         = GRADE_AGGREGATE_WEIGHTED_MEAN2;
1436                              $course_category->aggregateonlygraded = 0;
1437                              $course_category->update('restore');
1438                              $grade_category = $course_category;
1439  
1440                          } else {
1441                              $grade_category = new grade_category();
1442                              $grade_category->courseid            = $restore->course_id;
1443                              $grade_category->fullname            = backup_todb($info['GRADE_CATEGORY']['#']['NAME']['0']['#'], false);
1444                              $grade_category->droplow             = backup_todb($info['GRADE_CATEGORY']['#']['DROP_X_LOWEST']['0']['#'], false);
1445                              $grade_category->aggregation         = GRADE_AGGREGATE_WEIGHTED_MEAN2;
1446                              $grade_category->aggregateonlygraded = 0;
1447                              $grade_category->insert('restore');
1448                              $grade_category->load_grade_item(); // force cretion of grade_item
1449                          }
1450  
1451                      } else {
1452                          $grade_category = null;
1453                      }
1454  
1455                      /// now, restore grade_items
1456                      $items = array();
1457                      if (!empty($info['GRADE_CATEGORY']['#']['GRADE_ITEMS']['0']['#']['GRADE_ITEM'])) {
1458                          //Iterate over items
1459                          foreach ($info['GRADE_CATEGORY']['#']['GRADE_ITEMS']['0']['#']['GRADE_ITEM'] as $ite_info) {
1460                              $modname         = backup_todb($ite_info['#']['MODULE_NAME']['0']['#'], false);
1461                              $olditeminstance = backup_todb($ite_info['#']['CMINSTANCE']['0']['#'], false);
1462                              if (!$mod = backup_getid($restore->backup_unique_code,$modname, $olditeminstance)) {
1463                                  continue; // not restored
1464                              }
1465                              $iteminstance = $mod->new_id;
1466                              if (!$cm = get_coursemodule_from_instance($modname, $iteminstance, $restore->course_id)) {
1467                                  continue; // does not exist
1468                              }
1469  
1470                              if (!$grade_item = grade_item::fetch(array('itemtype'=>'mod', 'itemmodule'=>$cm->modname, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course, 'itemnumber'=>0))) {
1471                                  continue; // no item yet??
1472                              }
1473  
1474                              if ($grade_category) {
1475                                  $grade_item->sortorder = backup_todb($ite_info['#']['SORT_ORDER']['0']['#'], false);
1476                                  $grade_item->set_parent($grade_category->id);
1477                              }
1478  
1479                              if ($importing
1480                                or ($grade_item->itemtype == 'mod' and !restore_userdata_selected($restore,  $grade_item->itemmodule, $olditeminstance))) {
1481                                  // module instance not selected when restored using granular
1482                                  // skip this item
1483                                  continue;
1484                              }
1485  
1486                              //Now process grade excludes
1487                              if (empty($ite_info['#']['GRADE_EXCEPTIONS'])) {
1488                                  continue;
1489                              }
1490  
1491                              foreach($ite_info['#']['GRADE_EXCEPTIONS']['0']['#']['GRADE_EXCEPTION'] as $exc_info) {
1492                                  if ($u = backup_getid($restore->backup_unique_code,"user",backup_todb($exc_info['#']['USERID']['0']['#']))) {
1493                                      $userid = $u->new_id;
1494                                      $grade_grade = new grade_grade(array('itemid'=>$grade_item->id, 'userid'=>$userid));
1495                                      $grade_grade->excluded = 1;
1496                                      if ($grade_grade->id) {
1497                                          $grade_grade->update('restore');
1498                                      } else {
1499                                          $grade_grade->insert('restore');
1500                                      }
1501                                  }
1502                              }
1503                          }
1504                      }
1505                  }
1506              }
1507          }
1508  
1509          if (!defined('RESTORE_SILENTLY')) {
1510          //End ul
1511              echo '</ul>';
1512          }
1513  
1514          return $status;
1515      }
1516  
1517      /**
1518       * This function creates all the gradebook data from xml
1519       */
1520      function restore_create_gradebook($restore,$xml_file) {
1521          global $CFG;
1522  
1523          $status = true;
1524          //Check it exists
1525          if (!file_exists($xml_file)) {
1526              return false;
1527          }
1528  
1529          // Get info from xml
1530          // info will contain the number of record to process
1531          $info = restore_read_xml_gradebook($restore, $xml_file);
1532  
1533          // If we have info, then process
1534          if (empty($info)) {
1535              return $status;
1536          }
1537  
1538          if (empty($CFG->disablegradehistory) and isset($info->gradebook_histories) and $info->gradebook_histories == "true") {
1539              $restore_histories = true;
1540          } else {
1541              $restore_histories = false;
1542          }
1543  
1544          // make sure top course category exists
1545          $course_category = grade_category::fetch_course_category($restore->course_id);
1546          $course_category->load_grade_item();
1547  
1548          // we need to know if all grade items that were backed up are being restored
1549          // if that is not the case, we do not restore grade categories nor gradeitems of category type or course type
1550          // i.e. the aggregated grades of that category
1551  
1552          $restoreall = true;  // set to false if any grade_item is not selected/restored or already exist
1553          $importing  = !empty($SESSION->restore->importing);
1554  
1555          if ($importing) {
1556              $restoreall = false;
1557  
1558          } else {
1559              $prev_grade_items = grade_item::fetch_all(array('courseid'=>$restore->course_id));
1560              $prev_grade_cats  = grade_category::fetch_all(array('courseid'=>$restore->course_id));
1561  
1562               // if any categories already present, skip restore of categories from backup - course item or category already exist
1563              if (count($prev_grade_items) > 1 or count($prev_grade_cats) > 1) {
1564                  $restoreall = false;
1565              }
1566              unset($prev_grade_items);
1567              unset($prev_grade_cats);
1568  
1569              if ($restoreall) {
1570                  if ($recs = get_records_select("backup_ids","table_name = 'grade_items' AND backup_code = $restore->backup_unique_code", "", "old_id")) {
1571                      foreach ($recs as $rec) {
1572                          if ($data = backup_getid($restore->backup_unique_code,'grade_items',$rec->old_id)) {
1573  
1574                              $info = $data->info;
1575                              // do not restore if this grade_item is a mod, and
1576                              $itemtype = backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#']);
1577  
1578                              if ($itemtype == 'mod') {
1579                                  $olditeminstance = backup_todb($info['GRADE_ITEM']['#']['ITEMINSTANCE']['0']['#']);
1580                                  $itemmodule      = backup_todb($info['GRADE_ITEM']['#']['ITEMMODULE']['0']['#']);
1581  
1582                                  if (empty($restore->mods[$itemmodule]->granular)) {
1583                                      continue;
1584                                  } else if (!empty($restore->mods[$itemmodule]->instances[$olditeminstance]->restore)) {
1585                                      continue;
1586                                  }
1587                                  // at least one activity should not be restored - do not restore categories and manual items at all
1588                                  $restoreall = false;
1589                                  break;
1590                              }
1591                          }
1592                      }
1593                  }
1594              }
1595          }
1596  
1597          // Start ul
1598          if (!defined('RESTORE_SILENTLY')) {
1599              echo '<ul>';
1600          }
1601  
1602          // array of restored categories - speedup ;-)
1603          $cached_categories = array();
1604          $outcomes          = array();
1605  
1606      /// Process letters
1607          $context = get_context_instance(CONTEXT_COURSE, $restore->course_id);
1608          // respect current grade letters if defined
1609          if ($status and $restoreall and !record_exists('grade_letters', 'contextid', $context->id)) {
1610              if (!defined('RESTORE_SILENTLY')) {
1611                  echo '<li>'.get_string('gradeletters','grades').'</li>';
1612              }
1613              // Fetch recordset_size records in each iteration
1614              $recs = get_records_select("backup_ids","table_name = 'grade_letters' AND backup_code = $restore->backup_unique_code",
1615                                          "",
1616                                          "old_id");
1617              if ($recs) {
1618                  foreach ($recs as $rec) {
1619                      // Get the full record from backup_ids
1620                      $data = backup_getid($restore->backup_unique_code,'grade_letters',$rec->old_id);
1621                      if ($data) {
1622                          $info = $data->info;
1623                          $dbrec = new object();
1624                          $dbrec->contextid     = $context->id;
1625                          $dbrec->lowerboundary = backup_todb($info['GRADE_LETTER']['#']['LOWERBOUNDARY']['0']['#']);
1626                          $dbrec->letter        = backup_todb($info['GRADE_LETTER']['#']['LETTER']['0']['#']);
1627                          insert_record('grade_letters', $dbrec);
1628                      }
1629                  }
1630              }
1631          }
1632  
1633      /// Preprocess outcomes - do not store them yet!
1634          if ($status and !$importing and $restoreall) {
1635              if (!defined('RESTORE_SILENTLY')) {
1636                  echo '<li>'.get_string('gradeoutcomes','grades').'</li>';
1637              }
1638              $recs = get_records_select("backup_ids","table_name = 'grade_outcomes' AND backup_code = '$restore->backup_unique_code'",
1639                                          "",
1640                                          "old_id");
1641              if ($recs) {
1642                  foreach ($recs as $rec) {
1643                      //Get the full record from backup_ids
1644                      $data = backup_getid($restore->backup_unique_code,'grade_outcomes',$rec->old_id);
1645                      if ($data) {
1646                          $info = $data->info;
1647  
1648                          //first find out if outcome already exists
1649                          $shortname = backup_todb($info['GRADE_OUTCOME']['#']['SHORTNAME']['0']['#']);
1650  
1651                          if ($candidates = get_records_sql("SELECT *
1652                                                               FROM {$CFG->prefix}grade_outcomes
1653                                                              WHERE (courseid IS NULL OR courseid = $restore->course_id)
1654                                                                    AND shortname = '$shortname'
1655                                                           ORDER BY courseid ASC, id ASC")) {
1656                              $grade_outcome = reset($candidates);
1657                              $outcomes[$rec->old_id] = $grade_outcome;
1658                              continue;
1659                          }
1660  
1661                          $dbrec = new object();
1662  
1663                          if (has_capability('moodle/grade:manageoutcomes', get_context_instance(CONTEXT_SYSTEM))) {
1664                              $oldoutcome = backup_todb($info['GRADE_OUTCOME']['#']['COURSEID']['0']['#']);
1665                              if (empty($oldoutcome)) {
1666                                  //site wide
1667                                  $dbrec->courseid = null;
1668                              } else {
1669                                  //course only
1670                                  $dbrec->courseid = $restore->course_id;
1671                              }
1672                          } else {
1673                              // no permission to add site outcomes
1674                              $dbrec->courseid = $restore->course_id;
1675                          }
1676  
1677                          //Get the fields
1678                          $dbrec->shortname    = backup_todb($info['GRADE_OUTCOME']['#']['SHORTNAME']['0']['#'], false);
1679                          $dbrec->fullname     = backup_todb($info['GRADE_OUTCOME']['#']['FULLNAME']['0']['#'], false);
1680                          $dbrec->scaleid      = backup_todb($info['GRADE_OUTCOME']['#']['SCALEID']['0']['#'], false);
1681                          $dbrec->description  = backup_todb($info['GRADE_OUTCOME']['#']['DESCRIPTION']['0']['#'], false);
1682                          $dbrec->timecreated  = backup_todb($info['GRADE_OUTCOME']['#']['TIMECREATED']['0']['#'], false);
1683                          $dbrec->timemodified = backup_todb($info['GRADE_OUTCOME']['#']['TIMEMODIFIED']['0']['#'], false);
1684                          $dbrec->usermodified = backup_todb($info['GRADE_OUTCOME']['#']['USERMODIFIED']['0']['#'], false);
1685  
1686                          //Need to recode the scaleid
1687                          if ($scale = backup_getid($restore->backup_unique_code, 'scale', $dbrec->scaleid)) {
1688                              $dbrec->scaleid = $scale->new_id;
1689                          }
1690  
1691                          //Need to recode the usermodified
1692                          if ($modifier = backup_getid($restore->backup_unique_code, 'user', $dbrec->usermodified)) {
1693                              $dbrec->usermodified = $modifier->new_id;
1694                          }
1695  
1696                          $grade_outcome = new grade_outcome($dbrec, false);
1697                          $outcomes[$rec->old_id] = $grade_outcome;
1698                      }
1699                  }
1700              }
1701          }
1702  
1703      /// Process grade items and grades
1704          if ($status) {
1705              if (!defined('RESTORE_SILENTLY')) {
1706                  echo '<li>'.get_string('gradeitems','grades').'</li>';
1707              }
1708              $counter = 0;
1709  
1710              //Fetch recordset_size records in each iteration
1711              $recs = get_records_select("backup_ids","table_name = 'grade_items' AND backup_code = '$restore->backup_unique_code'",
1712                                          "id", // restore in the backup order
1713                                          "old_id");
1714  
1715              if ($recs) {
1716                  foreach ($recs as $rec) {
1717                      //Get the full record from backup_ids
1718                      $data = backup_getid($restore->backup_unique_code,'grade_items',$rec->old_id);
1719                      if ($data) {
1720                          $info = $data->info;
1721  
1722                          // first find out if category or normal item
1723                          $itemtype =  backup_todb($info['GRADE_ITEM']['#']['ITEMTYPE']['0']['#'], false);
1724                          if ($itemtype == 'course' or $itemtype == 'category') {
1725                              if (!$restoreall or $importing) {
1726                                  continue;
1727                              }
1728  
1729                              $oldcat = backup_todb($info['GRADE_ITEM']['#']['ITEMINSTANCE']['0']['#'], false);
1730                              if (!$cdata = backup_getid($restore->backup_unique_code,'grade_categories',$oldcat)) {
1731                                  continue;
1732                              }
1733                              $cinfo = $cdata->info;
1734                              unset($cdata);
1735                              if ($itemtype == 'course') {
1736  
1737                                  $course_category->fullname            = backup_todb($cinfo['GRADE_CATEGORY']['#']['FULLNAME']['0']['#'], false);
1738                                  $course_category->aggregation         = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATION']['0']['#'], false);
1739                                  $course_category->keephigh            = backup_todb($cinfo['GRADE_CATEGORY']['#']['KEEPHIGH']['0']['#'], false);
1740                                  $course_category->droplow             = backup_todb($cinfo['GRADE_CATEGORY']['#']['DROPLOW']['0']['#'], false);
1741                                  $course_category->aggregateonlygraded = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEONLYGRADED']['0']['#'], false);
1742                                  $course_category->aggregateoutcomes   = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATEOUTCOMES']['0']['#'], false);
1743                                  $course_category->aggregatesubcats    = backup_todb($cinfo['GRADE_CATEGORY']['#']['AGGREGATESUBCATS']['0']['#'], false);
1744