PageRenderTime 67ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 2ms

/moodle1917/backup/restorelib.php

https://github.com/gustavoramirezrugerio/moodle1.9.17
PHP | 9516 lines | 6546 code | 988 blank | 1982 comment | 1802 complexity | ce73768a77d9254fda3096220aa17ac7 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, BSD-3-Clause, LGPL-2.0, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php //$Id: restorelib.php,v 1.283.2.98 2011/10/19 19:39:26 moodlerobot Exp $
  2. //Functions used in restore
  3. require_once($CFG->libdir.'/gradelib.php');
  4. /**
  5. * Group backup/restore constants, 0.
  6. */
  7. define('RESTORE_GROUPS_NONE', 0);
  8. /**
  9. * Group backup/restore constants, 1.
  10. */
  11. define('RESTORE_GROUPS_ONLY', 1);
  12. /**
  13. * Group backup/restore constants, 2.
  14. */
  15. define('RESTORE_GROUPINGS_ONLY', 2);
  16. /**
  17. * Group backup/restore constants, course/all.
  18. */
  19. define('RESTORE_GROUPS_GROUPINGS', 3);
  20. //This function unzips a zip file in the same directory that it is
  21. //It automatically uses pclzip or command line unzip
  22. function restore_unzip ($file) {
  23. return unzip_file($file, '', false);
  24. }
  25. //This function checks if moodle.xml seems to be a valid xml file
  26. //(exists, has an xml header and a course main tag
  27. function restore_check_moodle_file ($file) {
  28. $status = true;
  29. //Check if it exists
  30. if ($status = is_file($file)) {
  31. //Open it and read the first 200 bytes (chars)
  32. $handle = fopen ($file, "r");
  33. $first_chars = fread($handle,200);
  34. $status = fclose ($handle);
  35. //Chek if it has the requires strings
  36. if ($status) {
  37. $status = strpos($first_chars,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  38. if ($status !== false) {
  39. $status = strpos($first_chars,"<MOODLE_BACKUP>");
  40. }
  41. }
  42. }
  43. return $status;
  44. }
  45. //This function iterates over all modules in backup file, searching for a
  46. //MODNAME_refresh_events() to execute. Perhaps it should ve moved to central Moodle...
  47. function restore_refresh_events($restore) {
  48. global $CFG;
  49. $status = true;
  50. //Take all modules in backup
  51. $modules = $restore->mods;
  52. //Iterate
  53. foreach($modules as $name => $module) {
  54. //Only if the module is being restored
  55. if (isset($module->restore) && $module->restore == 1) {
  56. //Include module library
  57. include_once("$CFG->dirroot/mod/$name/lib.php");
  58. //If module_refresh_events exists
  59. $function_name = $name."_refresh_events";
  60. if (function_exists($function_name)) {
  61. $status = $function_name($restore->course_id);
  62. }
  63. }
  64. }
  65. return $status;
  66. }
  67. //This function makes all the necessary calls to xxxx_decode_content_links_caller()
  68. //function in each module/block/course format..., passing them the desired contents to be decoded
  69. //from backup format to destination site/course in order to mantain inter-activities
  70. //working in the backup/restore process
  71. function restore_decode_content_links($restore) {
  72. global $CFG;
  73. $status = true;
  74. if (!defined('RESTORE_SILENTLY')) {
  75. echo "<ul>";
  76. }
  77. // Recode links in the course summary.
  78. if (!defined('RESTORE_SILENTLY')) {
  79. echo '<li>' . get_string('from') . ' ' . get_string('course');
  80. }
  81. $course = get_record('course', 'id', $restore->course_id, '', '', '', '', 'id,summary');
  82. $coursesummary = backup_todb($course->summary,false); // Exception: Process FILEPHP (not available when restored) MDL-18222
  83. $coursesummary = restore_decode_content_links_worker($coursesummary, $restore);
  84. if ($coursesummary != $course->summary) {
  85. $course->summary = addslashes($coursesummary);
  86. if (!update_record('course', $course)) {
  87. $status = false;
  88. }
  89. }
  90. if (!defined('RESTORE_SILENTLY')) {
  91. echo '</li>';
  92. }
  93. // Recode links in section summaries.
  94. $sections = get_records('course_sections', 'course', $restore->course_id, 'id', 'id,summary');
  95. if ($sections) {
  96. if (!defined('RESTORE_SILENTLY')) {
  97. echo '<li>' . get_string('from') . ' ' . get_string('sections');
  98. }
  99. foreach ($sections as $section) {
  100. $sectionsummary = restore_decode_content_links_worker($section->summary, $restore);
  101. if ($sectionsummary != $section->summary) {
  102. $section->summary = addslashes($sectionsummary);
  103. if (!update_record('course_sections', $section)) {
  104. $status = false;
  105. }
  106. }
  107. }
  108. if (!defined('RESTORE_SILENTLY')) {
  109. echo '</li>';
  110. }
  111. }
  112. // Restore links in modules.
  113. foreach ($restore->mods as $name => $info) {
  114. //If the module is being restored
  115. if (isset($info->restore) && $info->restore == 1) {
  116. //Check if the xxxx_decode_content_links_caller exists
  117. include_once("$CFG->dirroot/mod/$name/restorelib.php");
  118. $function_name = $name."_decode_content_links_caller";
  119. if (function_exists($function_name)) {
  120. if (!defined('RESTORE_SILENTLY')) {
  121. echo "<li>".get_string ("from")." ".get_string("modulenameplural",$name);
  122. }
  123. $status = $function_name($restore) && $status;
  124. if (!defined('RESTORE_SILENTLY')) {
  125. echo '</li>';
  126. }
  127. }
  128. }
  129. }
  130. // For the course format call its decode_content_links method (if it exists)
  131. $format = get_field('course', 'format', 'id', $restore->course_id);
  132. if (file_exists("$CFG->dirroot/course/format/$format/restorelib.php")) {
  133. include_once("$CFG->dirroot/course/format/$format/restorelib.php");
  134. $function_name = $format.'_decode_format_content_links_caller';
  135. if (function_exists($function_name)) {
  136. if (!defined('RESTORE_SILENTLY')) {
  137. echo "<li>".get_string ("from")." ".get_string("format").' '.$format;
  138. }
  139. $status = $function_name($restore);
  140. if (!defined('RESTORE_SILENTLY')) {
  141. echo '</li>';
  142. }
  143. }
  144. }
  145. // Process all html text also in blocks too
  146. if (!defined('RESTORE_SILENTLY')) {
  147. echo '<li>'.get_string ('from').' '.get_string('blocks');
  148. }
  149. if ($blocks = get_records('block', 'visible', 1)) {
  150. foreach ($blocks as $block) {
  151. if ($blockobject = block_instance($block->name)) {
  152. $blockobject->decode_content_links_caller($restore);
  153. }
  154. }
  155. }
  156. if (!defined('RESTORE_SILENTLY')) {
  157. echo '</li>';
  158. }
  159. // Restore links in questions.
  160. require_once("$CFG->dirroot/question/restorelib.php");
  161. if (!defined('RESTORE_SILENTLY')) {
  162. echo '<li>' . get_string('from') . ' ' . get_string('questions', 'quiz');
  163. }
  164. $status = question_decode_content_links_caller($restore) && $status;
  165. if (!defined('RESTORE_SILENTLY')) {
  166. echo '</li>';
  167. }
  168. if (!defined('RESTORE_SILENTLY')) {
  169. echo "</ul>";
  170. }
  171. return $status;
  172. }
  173. /**
  174. * This function decodes some well-know links to course
  175. */
  176. function course_decode_content_links($content, $restore) {
  177. global $CFG;
  178. // Links to course
  179. $searchstring = '/\$@(COURSEVIEWBYID)\*([0-9]+)@\$/';
  180. // We look for it
  181. preg_match_all($searchstring, $content, $foundset);
  182. // If found, then we are going to look for its new id (in backup tables)
  183. if ($foundset[0]) {
  184. // Iterate over foundset[2]. They are the old_ids
  185. foreach ($foundset[2] as $old_id) {
  186. // We get the needed variables here (course id)
  187. $rec = backup_getid($restore->backup_unique_code, 'course', $old_id);
  188. // Personalize the searchstring
  189. $searchstring = '/\$@(COURSEVIEWBYID)\*('.$old_id.')@\$/';
  190. // If it is a link to itself, replace it
  191. if (!empty($rec->new_id)) {
  192. $replacestring = $CFG->wwwroot . '/course/view.php?id=' . $rec->new_id;
  193. // It s a link to another course, keep it unmodified
  194. } else {
  195. $replacestring = $restore->original_wwwroot . '/course/view.php?id=' . $old_id;
  196. }
  197. // Perform the replacement
  198. $content = preg_replace($searchstring, $replacestring, $content);
  199. }
  200. }
  201. return $content;
  202. }
  203. //This function is called from all xxxx_decode_content_links_caller(),
  204. //its task is to ask all modules (maybe other linkable objects) to restore
  205. //links to them.
  206. function restore_decode_content_links_worker($content,$restore) {
  207. global $CFG;
  208. // Course links decoder
  209. $content = course_decode_content_links($content, $restore);
  210. // Module links decoders
  211. foreach($restore->mods as $name => $info) {
  212. $function_name = $name."_decode_content_links";
  213. if (function_exists($function_name)) {
  214. $content = $function_name($content,$restore);
  215. }
  216. }
  217. // For the current format, call decode_format_content_links if it exists
  218. static $format_function_name;
  219. if (!isset($format_function_name)) {
  220. $format_function_name = false;
  221. if ($format = get_field('course', 'format', 'id', $restore->course_id)) {
  222. if (file_exists("$CFG->dirroot/course/format/$format/restorelib.php")) {
  223. include_once("$CFG->dirroot/course/format/$format/restorelib.php");
  224. $function_name = $format.'_decode_format_content_links';
  225. if (function_exists($function_name)) {
  226. $format_function_name = $function_name;
  227. }
  228. }
  229. }
  230. }
  231. // If the above worked - then we have a function to call
  232. if ($format_function_name) {
  233. $content = $format_function_name($content, $restore);
  234. }
  235. // For each block, call its encode_content_links method
  236. static $blockobjects = null;
  237. if (!isset($blockobjects)) {
  238. $blockobjects = array();
  239. if ($blocks = get_records('block', 'visible', 1)) {
  240. foreach ($blocks as $block) {
  241. if ($blockobject = block_instance($block->name)) {
  242. $blockobjects[] = $blockobject;
  243. }
  244. }
  245. }
  246. }
  247. foreach ($blockobjects as $blockobject) {
  248. $content = $blockobject->decode_content_links($content,$restore);
  249. }
  250. return $content;
  251. }
  252. //This function converts all the wiki texts in the restored course
  253. //to the Markdown format. Used only for backup files prior 2005041100.
  254. //It calls every module xxxx_convert_wiki2markdown function
  255. function restore_convert_wiki2markdown($restore) {
  256. $status = true;
  257. if (!defined('RESTORE_SILENTLY')) {
  258. echo "<ul>";
  259. }
  260. foreach ($restore->mods as $name => $info) {
  261. //If the module is being restored
  262. if ($info->restore == 1) {
  263. //Check if the xxxx_restore_wiki2markdown exists
  264. $function_name = $name."_restore_wiki2markdown";
  265. if (function_exists($function_name)) {
  266. $status = $function_name($restore);
  267. if (!defined('RESTORE_SILENTLY')) {
  268. echo "<li>".get_string("modulenameplural",$name);
  269. echo '</li>';
  270. }
  271. }
  272. }
  273. }
  274. if (!defined('RESTORE_SILENTLY')) {
  275. echo "</ul>";
  276. }
  277. return $status;
  278. }
  279. //This function receives a wiki text in the restore process and
  280. //return it with every link to modules " modulename:moduleid"
  281. //converted if possible. See the space before modulename!!
  282. function restore_decode_wiki_content($content,$restore) {
  283. global $CFG;
  284. $result = $content;
  285. $searchstring='/ ([a-zA-Z]+):([0-9]+)\(([^)]+)\)/';
  286. //We look for it
  287. preg_match_all($searchstring,$content,$foundset);
  288. //If found, then we are going to look for its new id (in backup tables)
  289. if ($foundset[0]) {
  290. //print_object($foundset); //Debug
  291. //Iterate over foundset[2]. They are the old_ids
  292. foreach($foundset[2] as $old_id) {
  293. //We get the needed variables here (course id)
  294. $rec = backup_getid($restore->backup_unique_code,"course_modules",$old_id);
  295. //Personalize the searchstring
  296. $searchstring='/ ([a-zA-Z]+):'.$old_id.'\(([^)]+)\)/';
  297. //If it is a link to this course, update the link to its new location
  298. if($rec->new_id) {
  299. //Now replace it
  300. $result= preg_replace($searchstring,' $1:'.$rec->new_id.'($2)',$result);
  301. } else {
  302. //It's a foreign link so redirect it to its original URL
  303. $result= preg_replace($searchstring,$restore->original_wwwroot.'/mod/$1/view.php?id='.$old_id.'($2)',$result);
  304. }
  305. }
  306. }
  307. return $result;
  308. }
  309. //This function read the xml file and store it data from the info zone in an object
  310. function restore_read_xml_info ($xml_file) {
  311. //We call the main read_xml function, with todo = INFO
  312. $info = restore_read_xml ($xml_file,"INFO",false);
  313. return $info;
  314. }
  315. //This function read the xml file and store it data from the course header zone in an object
  316. function restore_read_xml_course_header ($xml_file) {
  317. //We call the main read_xml function, with todo = COURSE_HEADER
  318. $info = restore_read_xml ($xml_file,"COURSE_HEADER",false);
  319. return $info;
  320. }
  321. //This function read the xml file and store its data from the blocks in a object
  322. function restore_read_xml_blocks ($restore, $xml_file) {
  323. //We call the main read_xml function, with todo = BLOCKS
  324. $info = restore_read_xml ($xml_file,'BLOCKS',$restore);
  325. return $info;
  326. }
  327. //This function read the xml file and store its data from the sections in a object
  328. function restore_read_xml_sections ($xml_file) {
  329. //We call the main read_xml function, with todo = SECTIONS
  330. $info = restore_read_xml ($xml_file,"SECTIONS",false);
  331. return $info;
  332. }
  333. //This function read the xml file and store its data from the course format in an object
  334. function restore_read_xml_formatdata ($xml_file) {
  335. //We call the main read_xml function, with todo = FORMATDATA
  336. $info = restore_read_xml ($xml_file,'FORMATDATA',false);
  337. return $info;
  338. }
  339. //This function read the xml file and store its data from the metacourse in a object
  340. function restore_read_xml_metacourse ($xml_file) {
  341. //We call the main read_xml function, with todo = METACOURSE
  342. $info = restore_read_xml ($xml_file,"METACOURSE",false);
  343. return $info;
  344. }
  345. //This function read the xml file and store its data from the gradebook in a object
  346. function restore_read_xml_gradebook ($restore, $xml_file) {
  347. //We call the main read_xml function, with todo = GRADEBOOK
  348. $info = restore_read_xml ($xml_file,"GRADEBOOK",$restore);
  349. return $info;
  350. }
  351. //This function read the xml file and store its data from the users in
  352. //backup_ids->info db (and user's id in $info)
  353. function restore_read_xml_users ($restore,$xml_file) {
  354. //We call the main read_xml function, with todo = USERS
  355. $info = restore_read_xml ($xml_file,"USERS",$restore);
  356. return $info;
  357. }
  358. //This function read the xml file and store its data from the messages in
  359. //backup_ids->message backup_ids->message_read and backup_ids->contact and db (and their counters in info)
  360. function restore_read_xml_messages ($restore,$xml_file) {
  361. //We call the main read_xml function, with todo = MESSAGES
  362. $info = restore_read_xml ($xml_file,"MESSAGES",$restore);
  363. return $info;
  364. }
  365. //This function read the xml file and store its data from the blogs in
  366. //backup_ids->blog and backup_ids->blog_tag and db (and their counters in info)
  367. function restore_read_xml_blogs ($restore,$xml_file) {
  368. //We call the main read_xml function, with todo = BLOGS
  369. $info = restore_read_xml ($xml_file,"BLOGS",$restore);
  370. return $info;
  371. }
  372. //This function read the xml file and store its data from the questions in
  373. //backup_ids->info db (and category's id in $info)
  374. function restore_read_xml_questions ($restore,$xml_file) {
  375. //We call the main read_xml function, with todo = QUESTIONS
  376. $info = restore_read_xml ($xml_file,"QUESTIONS",$restore);
  377. return $info;
  378. }
  379. //This function read the xml file and store its data from the scales in
  380. //backup_ids->info db (and scale's id in $info)
  381. function restore_read_xml_scales ($restore,$xml_file) {
  382. //We call the main read_xml function, with todo = SCALES
  383. $info = restore_read_xml ($xml_file,"SCALES",$restore);
  384. return $info;
  385. }
  386. //This function read the xml file and store its data from the groups in
  387. //backup_ids->info db (and group's id in $info)
  388. function restore_read_xml_groups ($restore,$xml_file) {
  389. //We call the main read_xml function, with todo = GROUPS
  390. $info = restore_read_xml ($xml_file,"GROUPS",$restore);
  391. return $info;
  392. }
  393. //This function read the xml file and store its data from the groupings in
  394. //backup_ids->info db (and grouping's id in $info)
  395. function restore_read_xml_groupings ($restore,$xml_file) {
  396. //We call the main read_xml function, with todo = GROUPINGS
  397. $info = restore_read_xml ($xml_file,"GROUPINGS",$restore);
  398. return $info;
  399. }
  400. //This function read the xml file and store its data from the groupings in
  401. //backup_ids->info db (and grouping's id in $info)
  402. function restore_read_xml_groupings_groups ($restore,$xml_file) {
  403. //We call the main read_xml function, with todo = GROUPINGS
  404. $info = restore_read_xml ($xml_file,"GROUPINGSGROUPS",$restore);
  405. return $info;
  406. }
  407. //This function read the xml file and store its data from the events (course) in
  408. //backup_ids->info db (and event's id in $info)
  409. function restore_read_xml_events ($restore,$xml_file) {
  410. //We call the main read_xml function, with todo = EVENTS
  411. $info = restore_read_xml ($xml_file,"EVENTS",$restore);
  412. return $info;
  413. }
  414. //This function read the xml file and store its data from the modules in
  415. //backup_ids->info
  416. function restore_read_xml_modules ($restore,$xml_file) {
  417. //We call the main read_xml function, with todo = MODULES
  418. $info = restore_read_xml ($xml_file,"MODULES",$restore);
  419. return $info;
  420. }
  421. //This function read the xml file and store its data from the logs in
  422. //backup_ids->info
  423. function restore_read_xml_logs ($restore,$xml_file) {
  424. //We call the main read_xml function, with todo = LOGS
  425. $info = restore_read_xml ($xml_file,"LOGS",$restore);
  426. return $info;
  427. }
  428. function restore_read_xml_roles ($xml_file) {
  429. //We call the main read_xml function, with todo = ROLES
  430. $info = restore_read_xml ($xml_file,"ROLES",false);
  431. return $info;
  432. }
  433. //This function prints the contents from the info parammeter passed
  434. function restore_print_info ($info) {
  435. global $CFG;
  436. $status = true;
  437. if ($info) {
  438. $table = new object();
  439. //This is tha align to every ingo table
  440. $table->align = array ("right","left");
  441. //This is the nowrap clause
  442. $table->wrap = array ("","nowrap");
  443. //The width
  444. $table->width = "70%";
  445. //Put interesting info in table
  446. //The backup original name
  447. $tab[0][0] = "<b>".get_string("backuporiginalname").":</b>";
  448. $tab[0][1] = $info->backup_name;
  449. //The moodle version
  450. $tab[1][0] = "<b>".get_string("moodleversion").":</b>";
  451. $tab[1][1] = $info->backup_moodle_release." (".$info->backup_moodle_version.")";
  452. //The backup version
  453. $tab[2][0] = "<b>".get_string("backupversion").":</b>";
  454. $tab[2][1] = $info->backup_backup_release." (".$info->backup_backup_version.")";
  455. //The backup date
  456. $tab[3][0] = "<b>".get_string("backupdate").":</b>";
  457. $tab[3][1] = userdate($info->backup_date);
  458. //Is this the same Moodle install?
  459. if (!empty($info->original_siteidentifier)) {
  460. $tab[4][0] = "<b>".get_string("backupfromthissite").":</b>";
  461. if (backup_is_same_site($info)) {
  462. $tab[4][1] = get_string('yes');
  463. } else {
  464. $tab[4][1] = get_string('no');
  465. }
  466. }
  467. //Print title
  468. print_heading(get_string("backup").":");
  469. $table->data = $tab;
  470. //Print backup general info
  471. print_table($table);
  472. if ($info->backup_backup_version <= 2005070500) {
  473. notify(get_string('backupnonisowarning')); // Message informing that this backup may not work!
  474. }
  475. //Now backup contents in another table
  476. $tab = array();
  477. //First mods info
  478. $mods = $info->mods;
  479. $elem = 0;
  480. foreach ($mods as $key => $mod) {
  481. $tab[$elem][0] = "<b>".get_string("modulenameplural",$key).":</b>";
  482. if ($mod->backup == "false") {
  483. $tab[$elem][1] = get_string("notincluded");
  484. } else {
  485. if ($mod->userinfo == "true") {
  486. $tab[$elem][1] = get_string("included")." ".get_string("withuserdata");
  487. } else {
  488. $tab[$elem][1] = get_string("included")." ".get_string("withoutuserdata");
  489. }
  490. if (isset($mod->instances) && is_array($mod->instances) && count($mod->instances)) {
  491. foreach ($mod->instances as $instance) {
  492. if ($instance->backup) {
  493. $elem++;
  494. $tab[$elem][0] = $instance->name;
  495. if ($instance->userinfo == 'true') {
  496. $tab[$elem][1] = get_string("included")." ".get_string("withuserdata");
  497. } else {
  498. $tab[$elem][1] = get_string("included")." ".get_string("withoutuserdata");
  499. }
  500. }
  501. }
  502. }
  503. }
  504. $elem++;
  505. }
  506. //Metacourse info
  507. $tab[$elem][0] = "<b>".get_string("metacourse").":</b>";
  508. if ($info->backup_metacourse == "true") {
  509. $tab[$elem][1] = get_string("yes");
  510. } else {
  511. $tab[$elem][1] = get_string("no");
  512. }
  513. $elem++;
  514. //Users info
  515. $tab[$elem][0] = "<b>".get_string("users").":</b>";
  516. $tab[$elem][1] = get_string($info->backup_users);
  517. $elem++;
  518. //Logs info
  519. $tab[$elem][0] = "<b>".get_string("logs").":</b>";
  520. if ($info->backup_logs == "true") {
  521. $tab[$elem][1] = get_string("yes");
  522. } else {
  523. $tab[$elem][1] = get_string("no");
  524. }
  525. $elem++;
  526. //User Files info
  527. $tab[$elem][0] = "<b>".get_string("userfiles").":</b>";
  528. if ($info->backup_user_files == "true") {
  529. $tab[$elem][1] = get_string("yes");
  530. } else {
  531. $tab[$elem][1] = get_string("no");
  532. }
  533. $elem++;
  534. //Course Files info
  535. $tab[$elem][0] = "<b>".get_string("coursefiles").":</b>";
  536. if ($info->backup_course_files == "true") {
  537. $tab[$elem][1] = get_string("yes");
  538. } else {
  539. $tab[$elem][1] = get_string("no");
  540. }
  541. $elem++;
  542. //site Files info
  543. $tab[$elem][0] = "<b>".get_string("sitefiles").":</b>";
  544. if (isset($info->backup_site_files) && $info->backup_site_files == "true") {
  545. $tab[$elem][1] = get_string("yes");
  546. } else {
  547. $tab[$elem][1] = get_string("no");
  548. }
  549. $elem++;
  550. //gradebook history info
  551. $tab[$elem][0] = "<b>".get_string('gradebookhistories', 'grades').":</b>";
  552. if (isset($info->gradebook_histories) && $info->gradebook_histories == "true") {
  553. $tab[$elem][1] = get_string("yes");
  554. } else {
  555. $tab[$elem][1] = get_string("no");
  556. }
  557. $elem++;
  558. //Messages info (only showed if present)
  559. if ($info->backup_messages == 'true') {
  560. $tab[$elem][0] = "<b>".get_string('messages','message').":</b>";
  561. $tab[$elem][1] = get_string('yes');
  562. $elem++;
  563. } else {
  564. //Do nothing
  565. }
  566. $elem++;
  567. //Blogs info (only showed if present)
  568. if (isset($info->backup_blogs) && $info->backup_blogs == 'true') {
  569. $tab[$elem][0] = "<b>".get_string('blogs','blog').":</b>";
  570. $tab[$elem][1] = get_string('yes');
  571. $elem++;
  572. } else {
  573. //Do nothing
  574. }
  575. $table->data = $tab;
  576. //Print title
  577. print_heading(get_string("backupdetails").":");
  578. //Print backup general info
  579. print_table($table);
  580. } else {
  581. $status = false;
  582. }
  583. return $status;
  584. }
  585. //This function prints the contents from the course_header parammeter passed
  586. function restore_print_course_header ($course_header) {
  587. $status = true;
  588. if ($course_header) {
  589. $table = new object();
  590. //This is tha align to every ingo table
  591. $table->align = array ("right","left");
  592. //The width
  593. $table->width = "70%";
  594. //Put interesting course header in table
  595. //The course name
  596. $tab[0][0] = "<b>".get_string("name").":</b>";
  597. $tab[0][1] = $course_header->course_fullname." (".$course_header->course_shortname.")";
  598. //The course summary
  599. $tab[1][0] = "<b>".get_string("summary").":</b>";
  600. $tab[1][1] = $course_header->course_summary;
  601. $table->data = $tab;
  602. //Print title
  603. print_heading(get_string("course").":");
  604. //Print backup course header info
  605. print_table($table);
  606. } else {
  607. $status = false;
  608. }
  609. return $status;
  610. }
  611. /**
  612. * Given one user object (from backup file), perform all the neccesary
  613. * checks is order to decide how that user will be handled on restore.
  614. *
  615. * Note the function requires $user->mnethostid to be already calculated
  616. * so it's caller responsibility to set it
  617. *
  618. * This function is used both by @restore_precheck_users() and
  619. * @restore_create_users() to get consistent results in both places
  620. *
  621. * It returns:
  622. * - one user object (from DB), if match has been found and user will be remapped
  623. * - boolean true if the user needs to be created
  624. * - boolean false if some conflict happened and the user cannot be handled
  625. *
  626. * Each test is responsible for returning its results and interrupt
  627. * execution. At the end, boolean true (user needs to be created) will be
  628. * returned if no test has interrupted that.
  629. *
  630. * Here it's the logic applied, keep it updated:
  631. *
  632. * If restoring users from same site backup:
  633. * 1A - Normal check: If match by id and username and mnethost => ok, return target user
  634. * 1B - Handle users deleted in DB and "alive" in backup file:
  635. * If match by id and mnethost and user is deleted in DB and
  636. * (match by username LIKE 'backup_email.%' or by non empty email = md5(username)) => ok, return target user
  637. * 1C - Handle users deleted in backup file and "alive" in DB:
  638. * If match by id and mnethost and user is deleted in backup file
  639. * and match by email = email_without_time(backup_email) => ok, return target user
  640. * 1D - Conflict: If match by username and mnethost and doesn't match by id => conflict, return false
  641. * 1E - None of the above, return true => User needs to be created
  642. *
  643. * if restoring from another site backup (cannot match by id here, replace it by email/firstaccess combination):
  644. * 2A - Normal check: If match by username and mnethost and (email or non-zero firstaccess) => ok, return target user
  645. * 2B - Handle users deleted in DB and "alive" in backup file:
  646. * 2B1 - If match by mnethost and user is deleted in DB and not empty email = md5(username) and
  647. * (username LIKE 'backup_email.%' or non-zero firstaccess) => ok, return target user
  648. * 2B2 - If match by mnethost and user is deleted in DB and
  649. * username LIKE 'backup_email.%' and non-zero firstaccess) => ok, return target user
  650. * (to cover situations were md5(username) wasn't implemented on delete we requiere both)
  651. * 2C - Handle users deleted in backup file and "alive" in DB:
  652. * If match mnethost and user is deleted in backup file
  653. * and by email = email_without_time(backup_email) and non-zero firstaccess=> ok, return target user
  654. * 2D - Conflict: If match by username and mnethost and not by (email or non-zero firstaccess) => conflict, return false
  655. * 2E - None of the above, return true => User needs to be created
  656. *
  657. * Note: for DB deleted users email is stored in username field, hence we
  658. * are looking there for emails. See delete_user()
  659. * Note: for DB deleted users md5(username) is stored *sometimes* in the email field,
  660. * hence we are looking there for usernames if not empty. See delete_user()
  661. */
  662. function restore_check_user($restore, $user) {
  663. global $CFG;
  664. // Verify mnethostid is set, return error if not
  665. // it's parent responsibility to define that before
  666. // arriving here
  667. if (empty($user->mnethostid)) {
  668. debugging("restore_check_user() wrong use, mnethostid not set for user $user->username", DEBUG_DEVELOPER);
  669. return false;
  670. }
  671. // Handle checks from same site backups
  672. if (backup_is_same_site($restore) && empty($CFG->forcedifferentsitecheckingusersonrestore)) {
  673. // 1A - If match by id and username and mnethost => ok, return target user
  674. if ($rec = get_record('user', 'id', $user->id, 'username', addslashes($user->username), 'mnethostid', $user->mnethostid)) {
  675. return $rec; // Matching user found, return it
  676. }
  677. // 1B - Handle users deleted in DB and "alive" in backup file
  678. // Note: for DB deleted users email is stored in username field, hence we
  679. // are looking there for emails. See delete_user()
  680. // Note: for DB deleted users md5(username) is stored *sometimes* in the email field,
  681. // hence we are looking there for usernames if not empty. See delete_user()
  682. // If match by id and mnethost and user is deleted in DB and
  683. // match by username LIKE 'backup_email.%' or by non empty email = md5(username) => ok, return target user
  684. if ($rec = get_record_sql("SELECT *
  685. FROM {$CFG->prefix}user u
  686. WHERE id = $user->id
  687. AND mnethostid = $user->mnethostid
  688. AND deleted = 1
  689. AND (
  690. username LIKE '".addslashes($user->email).".%'
  691. OR (
  692. ".sql_isnotempty('user', 'email', false, false)."
  693. AND email = '".md5($user->username)."'
  694. )
  695. )")) {
  696. return $rec; // Matching user, deleted in DB found, return it
  697. }
  698. // 1C - Handle users deleted in backup file and "alive" in DB
  699. // If match by id and mnethost and user is deleted in backup file
  700. // and match by email = email_without_time(backup_email) => ok, return target user
  701. if ($user->deleted) {
  702. // Note: for DB deleted users email is stored in username field, hence we
  703. // are looking there for emails. See delete_user()
  704. // Trim time() from email
  705. $trimemail = preg_replace('/(.*?)\.[0-9]+.?$/', '\\1', $user->username);
  706. if ($rec = get_record_sql("SELECT *
  707. FROM {$CFG->prefix}user u
  708. WHERE id = $user->id
  709. AND mnethostid = $user->mnethostid
  710. AND email = '".addslashes($trimemail)."'")) {
  711. return $rec; // Matching user, deleted in backup file found, return it
  712. }
  713. }
  714. // 1D - If match by username and mnethost and doesn't match by id => conflict, return false
  715. if ($rec = get_record('user', 'username', addslashes($user->username), 'mnethostid', $user->mnethostid)) {
  716. if ($user->id != $rec->id) {
  717. return false; // Conflict, username already exists and belongs to another id
  718. }
  719. }
  720. // Handle checks from different site backups
  721. } else {
  722. // 2A - If match by username and mnethost and
  723. // (email or non-zero firstaccess) => ok, return target user
  724. if ($rec = get_record_sql("SELECT *
  725. FROM {$CFG->prefix}user u
  726. WHERE username = '".addslashes($user->username)."'
  727. AND mnethostid = $user->mnethostid
  728. AND (
  729. email = '".addslashes($user->email)."'
  730. OR (
  731. firstaccess != 0
  732. AND firstaccess = $user->firstaccess
  733. )
  734. )")) {
  735. return $rec; // Matching user found, return it
  736. }
  737. // 2B - Handle users deleted in DB and "alive" in backup file
  738. // Note: for DB deleted users email is stored in username field, hence we
  739. // are looking there for emails. See delete_user()
  740. // Note: for DB deleted users md5(username) is stored *sometimes* in the email field,
  741. // hence we are looking there for usernames if not empty. See delete_user()
  742. // 2B1 - If match by mnethost and user is deleted in DB and not empty email = md5(username) and
  743. // (by username LIKE 'backup_email.%' or non-zero firstaccess) => ok, return target user
  744. if ($rec = get_record_sql("SELECT *
  745. FROM {$CFG->prefix}user u
  746. WHERE mnethostid = $user->mnethostid
  747. AND deleted = 1
  748. AND ".sql_isnotempty('user', 'email', false, false)."
  749. AND email = '".md5($user->username)."'
  750. AND (
  751. username LIKE '".addslashes($user->email).".%'
  752. OR (
  753. firstaccess != 0
  754. AND firstaccess = $user->firstaccess
  755. )
  756. )")) {
  757. return $rec; // Matching user found, return it
  758. }
  759. // 2B2 - If match by mnethost and user is deleted in DB and
  760. // username LIKE 'backup_email.%' and non-zero firstaccess) => ok, return target user
  761. // (this covers situations where md5(username) wasn't being stored so we require both
  762. // the email & non-zero firstaccess to match)
  763. if ($rec = get_record_sql("SELECT *
  764. FROM {$CFG->prefix}user u
  765. WHERE mnethostid = $user->mnethostid
  766. AND deleted = 1
  767. AND username LIKE '".addslashes($user->email).".%'
  768. AND firstaccess != 0
  769. AND firstaccess = $user->firstaccess")) {
  770. return $rec; // Matching user found, return it
  771. }
  772. // 2C - Handle users deleted in backup file and "alive" in DB
  773. // If match mnethost and user is deleted in backup file
  774. // and match by email = email_without_time(backup_email) and non-zero firstaccess=> ok, return target user
  775. if ($user->deleted) {
  776. // Note: for DB deleted users email is stored in username field, hence we
  777. // are looking there for emails. See delete_user()
  778. // Trim time() from email
  779. $trimemail = preg_replace('/(.*?)\.[0-9]+.?$/', '\\1', $user->username);
  780. if ($rec = get_record_sql("SELECT *
  781. FROM {$CFG->prefix}user u
  782. WHERE mnethostid = $user->mnethostid
  783. AND email = '".addslashes($trimemail)."'
  784. AND firstaccess != 0
  785. AND firstaccess = $user->firstaccess")) {
  786. return $rec; // Matching user, deleted in backup file found, return it
  787. }
  788. }
  789. // 2D - If match by username and mnethost and not by (email or non-zero firstaccess) => conflict, return false
  790. if ($rec = get_record_sql("SELECT *
  791. FROM {$CFG->prefix}user u
  792. WHERE username = '".addslashes($user->username)."'
  793. AND mnethostid = $user->mnethostid
  794. AND NOT (
  795. email = '".addslashes($user->email)."'
  796. OR (
  797. firstaccess != 0
  798. AND firstaccess = $user->firstaccess
  799. )
  800. )")) {
  801. return false; // Conflict, username/mnethostid already exist and belong to another user (by email/firstaccess)
  802. }
  803. }
  804. // Arrived here, return true as the user will need to be created and no
  805. // conflicts have been found in the logic above. This covers:
  806. // 1E - else => user needs to be created, return true
  807. // 2E - else => user needs to be created, return true
  808. return true;
  809. }
  810. /**
  811. * For all the users being restored, check if they are going to cause problems
  812. * before executing the restore process itself, detecting situations like:
  813. * - conflicts preventing restore to continue - provided by @restore_check_user()
  814. * - prevent creation of users if not allowed - check some global settings/caps
  815. */
  816. function restore_precheck_users($xml_file, $restore, &$problems) {
  817. global $CFG;
  818. $status = true; // Init $status
  819. // We aren't restoring users, nothing to check, allow continue
  820. if ($restore->users == 2) {
  821. return true;
  822. }
  823. // Get array of users from xml file and load them in backup_ids table
  824. if (!$info = restore_read_xml_users($restore,$xml_file)) {
  825. return true; // No users, nothing to check, allow continue
  826. }
  827. // We are going to map mnethostid, so load all the available ones
  828. $mnethosts = get_records('mnet_host', '', '', 'wwwroot', 'wwwroot, id');
  829. // Calculate the context we are going to use for capability checking
  830. if (!empty($restore->course_id)) { // Know the target (existing) course, check capabilities there
  831. $context = get_context_instance(CONTEXT_COURSE, $restore->course_id);
  832. } else if (!empty($restore->restore_restorecatto)) { // Know the category, check capabilities there
  833. $context = get_context_instance(CONTEXT_COURSECAT, $restore->restore_restorecatto);
  834. } else { // Last resort, check capabilities at system level
  835. $context = get_context_instance(CONTEXT_SYSTEM);
  836. }
  837. // Calculate if we have perms to create users, by checking:
  838. // to 'moodle/restore:createuser' and 'moodle/restore:userinfo'
  839. // and also observe $CFG->disableusercreationonrestore
  840. $cancreateuser = false;
  841. if (has_capability('moodle/restore:createuser', $context) and
  842. has_capability('moodle/restore:userinfo', $context) and
  843. empty($CFG->disableusercreationonrestore)) { // Can create users
  844. $cancreateuser = true;
  845. }
  846. // Iterate over all users, checking if they are likely to cause problems on restore
  847. $counter = 0;
  848. foreach ($info->users as $userid) {
  849. $rec = backup_getid($restore->backup_unique_code, 'user', $userid);
  850. $user = $rec->info;
  851. // Find the correct mnethostid for user before performing any further check
  852. if (empty($user->mnethosturl) || $user->mnethosturl === $CFG->wwwroot) {
  853. $user->mnethostid = $CFG->mnet_localhost_id;
  854. } else {
  855. // fast url-to-id lookups
  856. if (isset($mnethosts[$user->mnethosturl])) {
  857. $user->mnethostid = $mnethosts[$user->mnethosturl]->id;
  858. } else {
  859. $user->mnethostid = $CFG->mnet_localhost_id;
  860. }
  861. }
  862. // Calculate the best way to handle this user from backup file
  863. $usercheck = restore_check_user($restore, $user);
  864. if (is_object($usercheck)) { // No problem, we have found one user in DB to be mapped to
  865. // Annotate it, for later process by restore_create_users(). Set new_id to mapping user->id
  866. backup_putid($restore->backup_unique_code, 'user', $userid, $usercheck->id, $user);
  867. } else if ($usercheck === false) { // Found conflict, report it as problem
  868. $problems[] = get_string('restoreuserconflict', '', $user->username);
  869. $status = false;
  870. } else if ($usercheck === true) { // User needs to be created, check if we are able
  871. if ($cancreateuser) { // Can create user, annotate it, for later process by restore_create_users(). Set new_id to 0
  872. backup_putid($restore->backup_unique_code, 'user', $userid, 0, $user);
  873. } else { // Cannot create user, report it as problem
  874. $problems[] = get_string('restorecannotcreateuser', '', $user->username);
  875. $status = false;
  876. }
  877. } else { // Shouldn't arrive here ever, something is for sure wrong in restore_check_user()
  878. if (!defined('RESTORE_SILENTLY')) {
  879. notify('Unexpected error pre-checking user ' . s($user->username) . ' from backup file');
  880. return false;
  881. }
  882. }
  883. // Do some output
  884. $counter++;
  885. if ($counter % 10 == 0) {
  886. if (!defined('RESTORE_SILENTLY')) {
  887. echo ".";
  888. if ($counter % 200 == 0) {
  889. echo "<br />";
  890. }
  891. }
  892. backup_flush(300);
  893. }
  894. }
  895. return $status;
  896. }
  897. //This function create a new course record.
  898. //When finished, course_header contains the id of the new course
  899. function restore_create_new_course($restore,&$course_header) {
  900. global $CFG, $SESSION;
  901. $status = true;
  902. $fullname = $course_header->course_fullname;
  903. $shortname = $course_header->course_shortname;
  904. $currentfullname = "";
  905. $currentshortname = "";
  906. $counter = 0;
  907. //Iteratere while the name exists
  908. do {
  909. if ($counter) {
  910. $suffixfull = " ".get_string("copyasnoun")." ".$counter;
  911. $suffixshort = "_".$counter;
  912. } else {
  913. $suffixfull = "";
  914. $suffixshort = "";
  915. }
  916. $currentfullname = $fullname.$suffixfull;
  917. // Limit the size of shortname - database column accepts <= 100 chars
  918. $currentshortname = substr($shortname, 0, 100 - strlen($suffixshort)).$suffixshort;
  919. $coursefull = get_record("course","fullname",addslashes($currentfullname));
  920. $courseshort = get_record("course","shortname",addslashes($currentshortname));
  921. $counter++;
  922. } while ($coursefull || $courseshort);
  923. //New name = currentname
  924. $course_header->course_fullname = $currentfullname;
  925. $course_header->course_shortname = $currentshortname;
  926. // first try to get it from restore
  927. if ($restore->restore_restorecatto) {
  928. $category = get_record('course_categories', 'id', $restore->restore_restorecatto);
  929. }
  930. // else we try to get it from the xml file
  931. //Now calculate the category
  932. if (empty($category)) {
  933. $category = get_record("course_categories","id",$course_header->category->id,
  934. "name",addslashes($course_header->category->name));
  935. }
  936. //If no exists, try by name only
  937. if (!$category) {
  938. $category = get_record("course_categories","name",addslashes($course_header->category->name));
  939. }
  940. //If no exists, get category id 1
  941. if (!$category) {
  942. $category = get_record("course_categories","id","1");
  943. }
  944. //If category 1 doesn'exists, lets create the course category (get it from backup file)
  945. if (!$category) {
  946. $ins_category = new object();
  947. $ins_category->name = addslashes($course_header->category->name);
  948. $ins_category->parent = 0;
  949. $ins_category->sortorder = 0;
  950. $ins_category->coursecount = 0;
  951. $ins_category->visible = 0; //To avoid interferences with the rest of the site
  952. $ins_category->timemodified = time();
  953. $newid = insert_record("course_categories",$ins_category);
  954. $category->id = $newid;
  955. $category->name = $course_header->category->name;
  956. }
  957. //If exists, put new category id
  958. if ($category) {
  959. $course_header->category->id = $category->id;
  960. $course_header->category->name = $category->name;
  961. //Error, cannot locate category
  962. } else {
  963. $course_header->category->id = 0;
  964. $course_header->category->name = get_string("unknowncategory");
  965. $status = false;
  966. }
  967. //Create the course_object
  968. if ($status) {
  969. $course = new object();
  970. $course->category = addslashes($course_header->category->id);
  971. $course->password = addslashes($course_header->course_password);
  972. $course->fullname = addslashes($course_header->course_fullname);
  973. $course->shortname = addslashes($course_header->course_shortname);
  974. $course->idnumber = addslashes($course_header->course_idnumber);
  975. $course->idnumber = ''; //addslashes($course_header->course_idnumber); // we don't want this at all.
  976. $course->summary = addslashes($course_header->course_summary);
  977. $course->format = addslashes($course_header->course_format);
  978. $course->showgrades = addslashes($course_header->course_showgrades);
  979. $course->newsitems = addslashes($course_header->course_newsitems);
  980. $course->teacher = addslashes($course_hea

Large files files are truncated, but you can click here to view the full file