PageRenderTime 72ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 3ms

/trunk/MoodleWebRole/backup/restorelib.php

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

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