Polished.
[moodle.git] / backup / restorelib.php
blob5049a92b1a8a72b1942bdb2f450f1245446a95d8
1 <?PHP //$Id$
2 //Functions used in restore
4 //This function unzips a zip file in the same directory that it is
5 //It automatically uses pclzip or command line unzip
6 function restore_unzip ($file,$moodle_home) {
8 global $CFG;
10 $status = true;
12 if (empty($CFG->unzip)) { // Use built-in php-based unzip function
13 include_once($moodle_home."/lib/pclzip/pclzip.lib.php");
14 $archive = new PclZip($file);
15 if (!$list = $archive->extract(dirname($file))) {
16 $status = false;
18 } else { // Use external unzip program
19 $command = "cd ".dirname($file)."; $CFG->unzip -o ".basename($file);
20 Exec($command);
23 return $status;
26 //This function checks if moodle.xml seems to be a valid xml file
27 //(exists, has an xml header and a course main tag
28 function restore_check_moodle_file ($file) {
30 $status = true;
32 //Check if it exists
33 if ($status = is_file($file)) {
34 //Open it and read the first 200 bytes (chars)
35 $handle = fopen ($file, "r");
36 $first_chars = fread($handle,200);
37 $status = fclose ($handle);
38 //Chek if it has the requires strings
39 if ($status) {
40 $status = strpos($first_chars,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
41 if ($status !== false) {
42 $status = strpos($first_chars,"<MOODLE_BACKUP>");
47 return $status;
50 //This function read the xml file and store it data from the info zone in an object
51 function restore_read_xml_info ($xml_file) {
53 //We call the main read_xml function, with todo = INFO
54 $info = restore_read_xml ($xml_file,"INFO",false);
56 return $info;
59 //This function read the xml file and store it data from the course header zone in an object
60 function restore_read_xml_course_header ($xml_file) {
62 //We call the main read_xml function, with todo = COURSE_HEADER
63 $info = restore_read_xml ($xml_file,"COURSE_HEADER",false);
65 return $info;
68 //This function read the xml file and store its data from the sections in a object
69 function restore_read_xml_sections ($xml_file) {
71 //We call the main read_xml function, with todo = SECTIONS
72 $info = restore_read_xml ($xml_file,"SECTIONS",false);
74 return $info;
77 //This function read the xml file and store its data from the users in
78 //backup_ids->info db (and user's id in $info)
79 function restore_read_xml_users ($restore,$xml_file) {
81 //We call the main read_xml function, with todo = USERS
82 $info = restore_read_xml ($xml_file,"USERS",$restore);
84 return $info;
87 //This function read the xml file and store its data from the modules in
88 //backup_ids->info
89 function restore_read_xml_modules ($restore,$xml_file) {
91 //We call the main read_xml function, with todo = MODULES
92 $info = restore_read_xml ($xml_file,"MODULES",$restore);
94 return $info;
97 //This function prints the contents from the info parammeter passed
98 function restore_print_info ($info) {
100 $status = true;
101 if ($info) {
102 //This is tha align to every ingo table
103 $table->align = array ("RIGHT","LEFT");
104 //This is the nowrap clause
105 $table->wrap = array ("","NOWRAP");
106 //The width
107 $table->width = "70%";
108 //Put interesting info in table
109 //The backup original name
110 $tab[0][0] = "<b>".get_string("backuporiginalname").":</b>";
111 $tab[0][1] = $info->backup_name;
112 //The moodle version
113 $tab[1][0] = "<b>".get_string("moodleversion").":</b>";
114 $tab[1][1] = $info->backup_moodle_release." (".$info->backup_moodle_version.")";
115 //The backup version
116 $tab[2][0] = "<b>".get_string("backupversion").":</b>";
117 $tab[2][1] = $info->backup_backup_release." (".$info->backup_backup_version.")";
118 //The backup date
119 $tab[3][0] = "<b>".get_string("backupdate").":</b>";
120 $tab[3][1] = userdate($info->backup_date);
121 //Print title
122 print_heading(get_string("backup").":");
123 $table->data = $tab;
124 //Print backup general info
125 print_table($table);
126 //Now backup contents in another table
127 $tab = array();
128 //First mods info
129 $mods = $info->mods;
130 $elem = 0;
131 foreach ($mods as $key => $mod) {
132 $tab[$elem][0] = "<b>".get_string("modulenameplural",$key).":</b>";
133 if ($mod->backup == "false") {
134 $tab[$elem][1] = get_string("notincluded");
135 } else {
136 if ($mod->userinfo == "true") {
137 $tab[$elem][1] = get_string("included")." ".get_string("withuserdata");
138 } else {
139 $tab[$elem][1] = get_string("included")." ".get_string("withoutuserdata");
142 $elem++;
144 //Users info
145 $tab[$elem][0] = "<b>".get_string("users").":</b>";
146 $tab[$elem][1] = get_string($info->backup_users);
147 $elem++;
148 //Logs info
149 $tab[$elem][0] = "<b>".get_string("logs").":</b>";
150 if ($info->backup_logs == "true") {
151 $tab[$elem][1] = get_string("yes");
152 } else {
153 $tab[$elem][1] = get_string("no");
155 $elem++;
156 //User Files info
157 $tab[$elem][0] = "<b>".get_string("userfiles").":</b>";
158 if ($info->backup_user_files == "true") {
159 $tab[$elem][1] = get_string("yes");
160 } else {
161 $tab[$elem][1] = get_string("no");
163 $elem++;
164 //Course Files info
165 $tab[$elem][0] = "<b>".get_string("coursefiles").":</b>";
166 if ($info->backup_course_files == "true") {
167 $tab[$elem][1] = get_string("yes");
168 } else {
169 $tab[$elem][1] = get_string("no");
171 $elem++;
172 $table->data = $tab;
173 //Print title
174 print_heading(get_string("backupdetails").":");
175 //Print backup general info
176 print_table($table);
177 } else {
178 $status = false;
181 return $status;
184 //This function prints the contents from the course_header parammeter passed
185 function restore_print_course_header ($course_header) {
187 $status = true;
188 if ($course_header) {
189 //This is tha align to every ingo table
190 $table->align = array ("RIGHT","LEFT");
191 //The width
192 $table->width = "70%";
193 //Put interesting course header in table
194 //The course name
195 $tab[0][0] = "<b>".get_string("name").":</b>";
196 $tab[0][1] = $course_header->course_fullname." (".$course_header->course_shortname.")";
197 //The course summary
198 $tab[1][0] = "<b>".get_string("summary").":</b>";
199 $tab[1][1] = $course_header->course_summary;
200 $table->data = $tab;
201 //Print title
202 print_heading(get_string("course").":");
203 //Print backup course header info
204 print_table($table);
205 } else {
206 $status = false;
208 return $status;
211 //This function create a new course record.
212 //When finished, course_header contains the id of the new course
213 function restore_create_new_course($restore,&$course_header) {
215 global $CFG;
217 $status = true;
219 $fullname = $course_header->course_fullname;
220 $shortname = $course_header->course_shortname;
221 $currentfullname = "";
222 $currentshortname = "";
223 $counter = 0;
224 //Iteratere while the name exists
225 do {
226 if ($counter) {
227 $suffixfull = " ".get_string("copy")." ".$counter;
228 $suffixshort = "-".$counter;
229 } else {
230 $suffixfull = "";
231 $suffixshort = "";
233 $currentfullname = $fullname.$suffixfull;
234 $currentshortname = $shortname.$suffixshort;
235 $course = get_record("course","fullname",addslashes($currentfullname));
236 $counter++;
237 } while ($course);
239 //New name = currentname
240 $course_header->course_fullname = $currentfullname;
241 $course_header->course_shortname = $currentshortname;
243 //Now calculate the category
244 $category = get_record("course_categories","id",$course_header->category->id,
245 "name",addslashes($course_header->category->name));
246 //If no exists, try by name only
247 if (!$category) {
248 $category = get_record("course_categories","name",addslashes($course_header->category->name));
250 //If no exists, get category id 1
251 if (!$category) {
252 $category = get_record("course_categories","id","1");
254 //If exists, put new category id
255 if ($category) {
256 $course_header->category->id = $category->id;
257 $course_header->category->name = $category->name;
258 //Error, cannot locate category
259 } else {
260 $course_header->category->id = 0;
261 $course_header->category->name = getstring("unknowcategory");
262 $status = false;
265 //Create the course_object
266 if ($status) {
267 $course->category = addslashes($course_header->category->id);
268 $course->password = addslashes($course_header->course_password);
269 $course->fullname = addslashes($course_header->course_fullname);
270 $course->shortname = addslashes($course_header->course_shortname);
271 $course->summary = addslashes($course_header->course_summary);
272 $course->format = addslashes($course_header->course_format);
273 $course->newsitems = addslashes($course_header->course_newsitems);
274 $course->teacher = addslashes($course_header->course_teacher);
275 $course->teachers = addslashes($course_header->course_teachers);
276 $course->student = addslashes($course_header->course_student);
277 $course->students = addslashes($course_header->course_students);
278 $course->guest = addslashes($course_header->course_guest);
279 $course->startdate = addslashes($course_header->course_startdate);
280 $course->numsections = addslashes($course_header->course_numsections);
281 $course->showrecent = addslashes($course_header->course_showrecent);
282 $course->marker = addslashes($course_header->course_marker);
283 $course->timecreated = addslashes($course_header->course_timecreated);
284 $course->timemodified = addslashes($course_header->course_timemodified);
285 //Now insert the record
286 $newid = insert_record("course",$course);
287 if ($newid) {
288 //save old and new course id
289 backup_putid ($restore->backup_unique_code,"course",$course_header->course_id,$newid);
290 //Replace old course_id in course_header
291 $course_header->course_id = $newid;
292 } else {
293 $status = false;
297 return $status;
300 //This function creates all the course_sections and course_modules from xml
301 //when restoring in a new course or simply checks sections and create records
302 //in backup_ids when restoring in a existing course
303 function restore_create_sections($restore,$xml_file) {
305 global $CFG,$db;
307 $status = true;
308 //Check it exists
309 if (!file_exists($xml_file)) {
310 $status = false;
312 //Get info from xml
313 if ($status) {
314 $info = restore_read_xml_sections($xml_file);
316 //Put the info in the DB, recoding ids and saving the in backup tables
318 $sequence = "";
320 if ($info) {
321 //For each, section, save it to db
322 foreach ($info->sections as $key => $sect) {
323 $sequence = "";
324 $section->course = $restore->course_id;
325 $section->section = $sect->number;
326 $section->summary = $sect->summary;
327 $section->visible = $sect->visible;
328 $section->sequence = "";
329 //Now calculate the section's newid
330 $newid = 0;
331 if ($restore->restoreto == 1) {
332 //Save it to db (only if restoring to new course)
333 $newid = insert_record("course_sections",$section);
334 } else {
335 //Get section id when restoring in existing course
336 $rec = get_record("course_sections","course",$restore->course_id,
337 "section",$section->section);
338 //If that section doesn't exist, get section 0 (every mod will be
339 //asigned there
340 if(!$rec) {
341 $rec = get_record("course_sections","course",$restore->course_id,
342 "section","0");
344 $newid = $rec->id;
345 $sequence = $rec->sequence;
347 if ($newid) {
348 //save old and new section id
349 backup_putid ($restore->backup_unique_code,"course_sections",$key,$newid);
350 } else {
351 $status = false;
353 //If all is OK, go with associated mods
354 if ($status) {
355 //If we have mods in the section
356 if ($sect->mods) {
357 //For each mod inside section
358 foreach ($sect->mods as $keym => $mod) {
359 //Check if we've to restore this module
360 if ($restore->mods[$mod->type]->restore) {
361 //Get the module id from modules
362 $module = get_record("modules","name",$mod->type);
363 if ($module) {
364 $course_module->course = $restore->course_id;
365 $course_module->module = $module->id;
366 $course_module->section = $newid;
367 $course_module->added = $mod->added;
368 $course_module->deleted = $mod->deleted;
369 $course_module->score = $mod->score;
370 $course_module->visible = $mod->visible;
371 $course_module->instance = null;
372 //NOTE: The instance (new) is calculated and updated in db in the
373 // final step of the restore. We don't know it yet.
374 //print_object($course_module); //Debug
375 //Save it to db
376 $newidmod = insert_record("course_modules",$course_module);
377 if ($newidmod) {
378 //save old and new module id
379 //In the info field, we save the original instance of the module
380 //to use it later
381 backup_putid ($restore->backup_unique_code,"course_modules",
382 $keym,$newidmod,$mod->instance);
383 } else {
384 $status = false;
386 //Now, calculate the sequence field
387 if ($status) {
388 if ($sequence) {
389 $sequence .= ",".$newidmod;
390 } else {
391 $sequence = $newidmod;
394 } else {
395 $status = false;
401 //If all is OK, update sequence field in course_sections
402 if ($status) {
403 $rec->id = $newid;
404 $rec->sequence = $sequence;
405 $status = update_record("course_sections",$rec);
408 } else {
409 $status = false;
411 return $status;
414 //This function creates all the user, user_students, user_teachers
415 //user_course_creators and user_admins from xml
416 function restore_create_users($restore,$xml_file) {
418 global $CFG;
420 $status = true;
421 //Check it exists
422 if (!file_exists($xml_file)) {
423 $status = false;
425 //Get info from xml
426 if ($status) {
427 //info will contain the old_id of every user
428 //in backup_ids->info will be the real info (serialized)
429 $info = restore_read_xml_users($restore,$xml_file);
432 //Now, get evey user_id from $info and user data from $backup_ids
433 //and create the necessary records (users, user_students, user_teachers
434 //user_course_creators and user_admins
435 if ($info) {
436 //For each, user, take its info from backup_ids
437 foreach ($info->users as $userid) {
438 $rec = backup_getid($restore->backup_unique_code,"user",$userid);
439 //First strip slashes
440 $temp = stripslashes($rec->info);
441 //Now unserialize
442 $user = unserialize($temp);
443 //Calculate if it is a course user
444 //Has role teacher or student or admin or coursecreator
445 $is_course_user = ($user->roles[teacher] or $user->roles[student] or
446 $user->roles[admin] or $user->roles[coursecreator]);
447 //Check if it's admin and coursecreator
448 $is_admin = ($user->roles[admin]);
449 $is_coursecreator = ($user->roles[coursecreator]);
450 //Check if it's teacher and student
451 $is_teacher = ($user->roles[teacher]);
452 $is_student = ($user->roles[student]);
453 //To store new ids created
454 $newid=null;
455 //check if it exists (by username) and get its id
456 $user_exists = true;
457 $user_data = get_record("user","username",$user->username);
458 if (!$user_data) {
459 $user_exists = false;
460 } else {
461 $newid = $user_data->id;
463 //Flags to see if we have to create the user and roles
464 $create_user = true;
465 $create_roles = true;
467 //If we are restoring course users and it isn't a course user
468 if ($restore->users == 1 and !$is_course_user) {
469 //If only restoring course_users and user isn't a course_user, inform to $backup_ids
470 $status = backup_putid($restore->backup_unique_code,"user",$userid,null,'notincourse');
471 $create_user = false;
472 $create_roles = false;
475 if ($user_exists and $create_user) {
476 //If user exists mark its newid in backup_ids (the same than old)
477 $status = backup_putid($restore->backup_unique_code,"user",$userid,$newid,'exists');
478 $create_user = false;
481 //Here, if create_user, do it
482 if ($create_user) {
483 //We are going to create the user
484 //The structure is exactly as we need
485 $newid = insert_record ("user",$user);
486 //Put the new id
487 $status = backup_putid($restore->backup_unique_code,"user",$userid,$newid,"new");
490 //Here, if create_roles, do it as necessary
491 if ($create_roles) {
492 //Get the newid and currecnt info from backup_ids
493 $data = backup_getid($restore->backup_unique_code,"user",$userid);
494 $newid = $data->new_id;
495 $currinfo = $data->info.",";
496 //Now, depending of the role, create records in user_studentes and user_teacher
497 //and/or mark it in backup_ids
498 if ($is_admin) {
499 //If the record (user_admins) doesn't exists
500 if (!record_exists("user_admins","userid",$newid)) {
501 //Only put status in backup_ids
502 $currinfo = $currinfo."admin,";
503 $status = backup_putid($restore->backup_unique_code,"user",$userid,$newid,$currinfo);
506 if ($is_coursecreator) {
507 //If the record (user_coursecreators) doesn't exists
508 if (!record_exists("user_coursecreators","userid",$newid)) {
509 //Only put status in backup_ids
510 $currinfo = $currinfo."coursecreator,";
511 $status = backup_putid($restore->backup_unique_code,"user",$userid,$newid,$currinfo);
514 if ($is_teacher) {
515 //If the record (teacher) doesn't exists
516 if (!record_exists("user_teachers","userid",$newid,"course", $restore->course_id)) {
517 //Put status in backup_ids
518 $currinfo = $currinfo."teacher,";
519 $status = backup_putid($restore->backup_unique_code,"user",$userid,$newid,$currinfo);
520 //Set course and user
521 $user->roles[teacher]->course = $restore->course_id;
522 $user->roles[teacher]->userid = $newid;
523 //Insert data in user_teachers
524 //The structure is exactly as we need
525 $status = insert_record("user_teachers",$user->roles[teacher]);
528 if ($is_student) {
529 //If the record (student) doesn't exists
530 if (!record_exists("user_students","userid",$newid,"course", $restore->course_id)) {
531 //Put status in backup_ids
532 $currinfo = $currinfo."student,";
533 $status = backup_putid($restore->backup_unique_code,"user",$userid,$newid,$currinfo);
534 //Set course and user
535 $user->roles[student]->course = $restore->course_id;
536 $user->roles[student]->userid = $newid;
537 //Insert data in user_students
538 //The structure is exactly as we need
539 $status = insert_record("user_students",$user->roles[student]);
542 if (!$is_course_user) {
543 //If the record (user) doesn't exists
544 if (!record_exists("user","id",$newid)) {
545 //Put status in backup_ids
546 $currinfo = $currinfo."user,";
547 $status = backup_putid($restore->backup_unique_code,"user",$userid,$newid,$currinfo);
552 } else {
553 $status = false;
556 return $status;
559 //This function restores the userfiles from the temp (user_files) directory to the
560 //dataroot/users directory
561 function restore_user_files($restore) {
563 global $CFG;
565 $status = true;
567 //First, we check to "users" exists and create is as necessary
568 //in CFG->dataroot
569 $dest_dir = $CFG->dataroot."/users";
570 $status = check_dir_exists($dest_dir,true);
572 //Now, we iterate over "user_files" records to check if that user dir must be
573 //copied (and renamed) to the "users" dir.
574 $rootdir = $CFG->dataroot."/temp/backup/".$restore->backup_unique_code."/user_files";
575 //Check if directory exists
576 if (is_dir($rootdir)) {
577 $list = list_directories ($rootdir);
578 if ($list) {
579 //Iterate
580 $counter = 0;
581 foreach ($list as $dir) {
582 //Look for dir like username in backup_ids
583 $data = get_record ("backup_ids","backup_code",$restore->backup_unique_code,
584 "table_name","user",
585 "old_id",$dir);
586 //If thar user exists in backup_ids
587 if ($data) {
588 //Only it user has been created now
589 if (strpos($data->info,"new") !== false) {
590 //Copy the old_dir to its new location (and name) !!
591 //Only if destination doesn't exists
592 if (!file_exists($dest_dir."/".$data->new_id)) {
593 $status = backup_copy_file($rootdir."/".$dir,
594 $dest_dir."/".$data->new_id);
595 $counter ++;
602 //If status is ok and whe have dirs created, returns counter to inform
603 if ($status and $counter) {
604 return $counter;
605 } else {
606 return $status;
610 //This function restores the course files from the temp (course_files) directory to the
611 //dataroot/course_id directory
612 function restore_course_files($restore) {
614 global $CFG;
616 $status = true;
618 //First, we check to "course_id" exists and create is as necessary
619 //in CFG->dataroot
620 $dest_dir = $CFG->dataroot."/".$restore->course_id;
621 $status = check_dir_exists($dest_dir,true);
623 //Now, we iterate over "course_files" records to check if that file/dir must be
624 //copied to the "dest_dir" dir.
625 $rootdir = $CFG->dataroot."/temp/backup/".$restore->backup_unique_code."/course_files";
626 //Check if directory exists
627 if (is_dir($rootdir)) {
628 $list = list_directories_and_files ($rootdir);
629 if ($list) {
630 //Iterate
631 $counter = 0;
632 foreach ($list as $dir) {
633 //Copy the dir to its new location
634 //Only if destination file/dir doesn exists
635 if (!file_exists($dest_dir."/".$dir)) {
636 $status = backup_copy_file($rootdir."/".$dir,
637 $dest_dir."/".$dir);
638 $counter ++;
643 //If status is ok and whe have dirs created, returns counter to inform
644 if ($status and $counter) {
645 return $counter;
646 } else {
647 return $status;
652 //This function creates all the structures for every module in backup file
653 //Depending what has been selected.
654 function restore_create_modules($restore,$xml_file) {
656 global $CFG;
658 $status = true;
659 //Check it exists
660 if (!file_exists($xml_file)) {
661 $status = false;
663 //Get info from xml
664 if ($status) {
665 //info will contain the id and modtype of every module
666 //in backup_ids->info will be the real info (serialized)
667 $info = restore_read_xml_modules($restore,$xml_file);
670 //Now, if we have anything in info, we have to restore that mods
671 //from backup_ids (calling every mod restore function)
672 if ($info) {
673 //Iterate over each module
674 foreach ($info as $mod) {
675 $modrestore = $mod->modtype."_restore_mods";
676 if (function_exists($modrestore)) {
677 $status = $modrestore($mod,$restore);
678 } else {
679 //Something was wrong. Function should exist.
680 $status = false;
683 } else {
684 $status = false;
686 return $status;
689 //This function adjusts the instance field into course_modules. It's executed after
690 //modules restore. There, we KNOW the new instance id !!
691 function restore_check_instances($restore) {
693 global $CFG;
695 $status = true;
697 //We are going to iterate over each course_module saved in backup_ids
698 $course_modules = get_records_sql("SELECT new_id,info as instance
699 FROM {$CFG->prefix}backup_ids
700 WHERE backup_code = '$restore->backup_unique_code' AND
701 table_name = 'course_modules'");
702 if ($course_modules) {
703 foreach($course_modules as $cm) {
704 //Now we are going to the REAL course_modules to get its type (field module)
705 $module = get_record("course_modules","id",$cm->new_id);
706 if ($module) {
707 //We know the module type id. Get the name from modules
708 $type = get_record("modules","id",$module->module);
709 if ($type) {
710 //We know the type name and the old_id. Get its new_id
711 //from backup_ids. It's the instance !!!
712 $instance = get_record("backup_ids","backup_code",$restore->backup_unique_code,
713 "table_name",$type->name,
714 "old_id",$cm->instance);
715 if ($instance) {
716 //We have the new instance, so update the record in course_modules
717 $module->instance = $instance->new_id;
718 //print_object ($module); //Debug
719 $status = update_record("course_modules",$module);
720 } else {
721 $status = false;
723 } else {
724 $status = false;
726 } else {
727 $status = false;
730 } else {
731 $status = false;
735 return $status;
738 //=====================================================================================
739 //== ==
740 //== XML Functions (SAX) ==
741 //== ==
742 //=====================================================================================
744 //This is the class used to do all the xml parse
745 class MoodleParser {
747 var $level = 0; //Level we are
748 var $tree = array(); //Array of levels we are
749 var $content = ""; //Content under current level
750 var $todo = ""; //What we hav to do when parsing
751 var $info = ""; //Information collected. Temp storage. Used to return data after parsing.
752 var $temp = ""; //Temp storage.
753 var $preferences = ""; //Preferences about what to load !!
754 var $finished = false; //Flag to say xml_parse to stop
756 //This function is used to get the current contents property value
757 //They are trimed and converted from utf8
758 function getContents() {
759 return trim(utf8_decode($this->content));
762 //This is the startTag handler we use where we are reading the info zone (todo="INFO")
763 function startElementInfo($parser, $tagName, $attrs) {
764 //Refresh properties
765 $this->level++;
766 $this->tree[$this->level] = $tagName;
768 //Check if we are into INFO zone
769 //if ($this->tree[2] == "INFO") //Debug
770 // echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;".$tagName."&gt;<br>\n"; //Debug
773 //This is the startTag handler we use where we are reading the course header zone (todo="COURSE_HEADER")
774 function startElementCourseHeader($parser, $tagName, $attrs) {
775 //Refresh properties
776 $this->level++;
777 $this->tree[$this->level] = $tagName;
779 //Check if we are into COURSE_HEADER zone
780 //if ($this->tree[3] == "HEADER") //Debug
781 // echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;".$tagName."&gt;<br>\n"; //Debug
784 //This is the startTag handler we use where we are reading the sections zone (todo="SECTIONS")
785 function startElementSections($parser, $tagName, $attrs) {
786 //Refresh properties
787 $this->level++;
788 $this->tree[$this->level] = $tagName;
790 //Check if we are into SECTIONS zone
791 //if ($this->tree[3] == "SECTIONS") //Debug
792 // echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;".$tagName."&gt;<br>\n"; //Debug
795 //This is the startTag handler we use where we are reading the user zone (todo="USERS")
796 function startElementUsers($parser, $tagName, $attrs) {
797 //Refresh properties
798 $this->level++;
799 $this->tree[$this->level] = $tagName;
800 //Check if we are into USERS zone
801 //if ($this->tree[3] == "USERS") //Debug
802 // echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;".$tagName."&gt;<br>\n"; //Debug
805 //This is the startTag handler we use where we are reading the modules zone (todo="MODULES")
806 function startElementModules($parser, $tagName, $attrs) {
807 //Refresh properties
808 $this->level++;
809 $this->tree[$this->level] = $tagName;
810 //Check if we are into MODULES zone
811 //if ($this->tree[3] == "MODULES") //Debug
812 // echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;".$tagName."&gt;<br>\n"; //Debug
813 //If we are under a MOD tag under a MODULES zone, accumule it
814 if (($this->tree[4] == "MOD") and ($this->tree[3] == "MODULES")) {
815 $this->temp .= "<".$tagName.">";
819 //This is the startTag default handler we use when todo is undefined
820 function startElement($parser, $tagName, $attrs) {
821 $this->level++;
822 $this->tree[$this->level] = $tagName;
823 echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;".$tagName."&gt;<br>\n"; //Debug
826 //This is the endTag handler we use where we are reading the info zone (todo="INFO")
827 function endElementInfo($parser, $tagName) {
828 //Check if we are into INFO zone
829 if ($this->tree[2] == "INFO") {
830 //if (trim($this->content)) //Debug
831 // echo "C".str_repeat("&nbsp;",($this->level+2)*2).$this->getContents()."<br>\n"; //Debug
832 //echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;/".$tagName."&gt;<br>\n"; //Debug
833 //Dependig of different combinations, do different things
834 if ($this->level == 3) {
835 switch ($tagName) {
836 case "NAME":
837 $this->info->backup_name = $this->getContents();
838 break;
839 case "MOODLE_VERSION":
840 $this->info->backup_moodle_version = $this->getContents();
841 break;
842 case "MOODLE_RELEASE":
843 $this->info->backup_moodle_release = $this->getContents();
844 break;
845 case "BACKUP_VERSION":
846 $this->info->backup_backup_version = $this->getContents();
847 break;
848 case "BACKUP_RELEASE":
849 $this->info->backup_backup_release = $this->getContents();
850 break;
851 case "DATE":
852 $this->info->backup_date = $this->getContents();
853 break;
856 if ($this->tree[3] == "DETAILS") {
857 if ($this->level == 4) {
858 switch ($tagName) {
859 case "USERS":
860 $this->info->backup_users = $this->getContents();
861 break;
862 case "LOGS":
863 $this->info->backup_logs = $this->getContents();
864 break;
865 case "USERFILES":
866 $this->info->backup_user_files = $this->getContents();
867 break;
868 case "COURSEFILES":
869 $this->info->backup_course_files = $this->getContents();
870 break;
873 if ($this->level == 5) {
874 switch ($tagName) {
875 case "NAME":
876 $this->info->tempName = $this->getContents();
877 break;
878 case "INCLUDED":
879 $this->info->mods[$this->info->tempName]->backup = $this->getContents();
880 break;
881 case "USERINFO":
882 $this->info->mods[$this->info->tempName]->userinfo = $this->getContents();
883 break;
890 //Clear things
891 $this->tree[$this->level] = "";
892 $this->level--;
893 $this->content = "";
895 //Stop parsing if todo = INFO and tagName = INFO (en of the tag, of course)
896 //Speed up a lot (avoid parse all)
897 if ($tagName == "INFO") {
898 $this->finished = true;
902 //This is the endTag handler we use where we are reading the course_header zone (todo="COURSE_HEADER")
903 function endElementCourseHeader($parser, $tagName) {
904 //Check if we are into COURSE_HEADER zone
905 if ($this->tree[3] == "HEADER") {
906 //if (trim($this->content)) //Debug
907 // echo "C".str_repeat("&nbsp;",($this->level+2)*2).$this->getContents()."<br>\n"; //Debug
908 //echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;/".$tagName."&gt;<br>\n"; //Debug
909 //Dependig of different combinations, do different things
910 if ($this->level == 4) {
911 switch ($tagName) {
912 case "ID":
913 $this->info->course_id = $this->getContents();
914 break;
915 case "PASSWORD":
916 $this->info->course_password = $this->getContents();
917 break;
918 case "FULLNAME":
919 $this->info->course_fullname = $this->getContents();
920 break;
921 case "SHORTNAME":
922 $this->info->course_shortname = $this->getContents();
923 break;
924 case "SUMMARY":
925 $this->info->course_summary = $this->getContents();
926 break;
927 case "FORMAT":
928 $this->info->course_format = $this->getContents();
929 break;
930 case "NEWSITEMS":
931 $this->info->course_newsitems = $this->getContents();
932 break;
933 case "TEACHER":
934 $this->info->course_teacher = $this->getContents();
935 break;
936 case "TEACHERS":
937 $this->info->course_teachers = $this->getContents();
938 break;
939 case "STUDENT":
940 $this->info->course_student = $this->getContents();
941 break;
942 case "STUDENTS":
943 $this->info->course_students = $this->getContents();
944 break;
945 case "GUEST":
946 $this->info->course_guest = $this->getContents();
947 break;
948 case "STARDATE":
949 $this->info->course_stardate = $this->getContents();
950 break;
951 case "NUMSECTIONS":
952 $this->info->course_numsections = $this->getContents();
953 break;
954 case "SHOWRECENT":
955 $this->info->course_showrecent = $this->getContents();
956 break;
957 case "MARKER":
958 $this->info->course_marker = $this->getContents();
959 break;
960 case "TIMECREATED":
961 $this->info->course_timecreated = $this->getContents();
962 break;
963 case "TIMEMODIFIED":
964 $this->info->course_timemodified = $this->getContents();
965 break;
968 if ($this->tree[4] == "CATEGORY") {
969 if ($this->level == 5) {
970 switch ($tagName) {
971 case "ID":
972 $this->info->category->id = $this->getContents();
973 break;
974 case "NAME":
975 $this->info->category->name = $this->getContents();
976 break;
982 //Clear things
983 $this->tree[$this->level] = "";
984 $this->level--;
985 $this->content = "";
987 //Stop parsing if todo = COURSE_HEADER and tagName = HEADER (en of the tag, of course)
988 //Speed up a lot (avoid parse all)
989 if ($tagName == "HEADER") {
990 $this->finished = true;
994 //This is the endTag handler we use where we are reading the sections zone (todo="SECTIONS")
995 function endElementSections($parser, $tagName) {
996 //Check if we are into SECTIONS zone
997 if ($this->tree[3] == "SECTIONS") {
998 //if (trim($this->content)) //Debug
999 // echo "C".str_repeat("&nbsp;",($this->level+2)*2).$this->getContents()."<br>\n"; //Debug
1000 //echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;/".$tagName."&gt;<br>\n"; //Debug
1001 //Dependig of different combinations, do different things
1002 if ($this->level == 4) {
1003 switch ($tagName) {
1004 case "SECTION":
1005 //We've finalized a section, get it
1006 $this->info->sections[$this->info->tempsection->id]->number = $this->info->tempsection->number;
1007 $this->info->sections[$this->info->tempsection->id]->summary = $this->info->tempsection->summary;
1008 $this->info->sections[$this->info->tempsection->id]->visible = $this->info->tempsection->visible;
1009 $this->info->sections[$this->info->tempsection->id]->mods = $this->info->tempsection->mods;
1010 unset($this->info->tempsection);
1013 if ($this->level == 5) {
1014 switch ($tagName) {
1015 case "ID":
1016 $this->info->tempsection->id = $this->getContents();
1017 break;
1018 case "NUMBER":
1019 $this->info->tempsection->number = $this->getContents();
1020 break;
1021 case "SUMMARY":
1022 $this->info->tempsection->summary = $this->getContents();
1023 break;
1024 case "VISIBLE":
1025 $this->info->tempsection->visible = $this->getContents();
1026 break;
1029 if ($this->level == 6) {
1030 switch ($tagName) {
1031 case "MOD":
1032 //We've finalized a mod, get it
1033 $this->info->tempsection->mods[$this->info->tempmod->id]->type =
1034 $this->info->tempmod->type;
1035 $this->info->tempsection->mods[$this->info->tempmod->id]->instance =
1036 $this->info->tempmod->instance;
1037 $this->info->tempsection->mods[$this->info->tempmod->id]->added =
1038 $this->info->tempmod->added;
1039 $this->info->tempsection->mods[$this->info->tempmod->id]->deleted =
1040 $this->info->tempmod->deleted;
1041 $this->info->tempsection->mods[$this->info->tempmod->id]->score =
1042 $this->info->tempmod->score;
1043 $this->info->tempsection->mods[$this->info->tempmod->id]->visible =
1044 $this->info->tempmod->visible;
1045 unset($this->info->tempmod);
1048 if ($this->level == 7) {
1049 switch ($tagName) {
1050 case "ID":
1051 $this->info->tempmod->id = $this->getContents();
1052 break;
1053 case "TYPE":
1054 $this->info->tempmod->type = $this->getContents();
1055 break;
1056 case "INSTANCE":
1057 $this->info->tempmod->instance = $this->getContents();
1058 break;
1059 case "ADDED":
1060 $this->info->tempmod->added = $this->getContents();
1061 break;
1062 case "DELETED":
1063 $this->info->tempmod->deleted = $this->getContents();
1064 break;
1065 case "SCORE":
1066 $this->info->tempmod->score = $this->getContents();
1067 break;
1068 case "VISIBLE":
1069 $this->info->tempmod->visible = $this->getContents();
1070 break;
1074 //Clear things
1075 $this->tree[$this->level] = "";
1076 $this->level--;
1077 $this->content = "";
1079 //Stop parsing if todo = SECTIONS and tagName = SECTIONS (en of the tag, of course)
1080 //Speed up a lot (avoid parse all)
1081 if ($tagName == "SECTIONS") {
1082 $this->finished = true;
1086 //This is the endTag handler we use where we are reading the users zone (todo="USERS")
1087 function endElementUsers($parser, $tagName) {
1088 //Check if we are into USERS zone
1089 if ($this->tree[3] == "USERS") {
1090 //if (trim($this->content)) //Debug
1091 // echo "C".str_repeat("&nbsp;",($this->level+2)*2).$this->getContents()."<br>\n"; //Debug
1092 //echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;/".$tagName."&gt;<br>\n"; //Debug
1093 //Dependig of different combinations, do different things
1094 if ($this->level == 4) {
1095 switch ($tagName) {
1096 case "USER":
1097 //We've finalized a user, get it and save to db
1098 //First serialize
1099 $ser_temp = serialize($this->info->tempuser);
1100 //Now add slashes
1101 $sla_temp = addslashes($ser_temp);
1102 //Save to db
1103 backup_putid($this->preferences->backup_unique_code,"user",$this->info->tempuser->id,
1104 null,$sla_temp);
1105 //Delete temp obejct
1106 unset($this->info->tempuser);
1107 break;
1110 if ($this->level == 5) {
1111 switch ($tagName) {
1112 case "ID":
1113 $this->info->users[$this->getContents()] = $this->getContents();
1114 $this->info->tempuser->id = $this->getContents();
1115 break;
1116 case "CONFIRMED":
1117 $this->info->tempuser->confirmed = $this->getContents();
1118 break;
1119 case "DELETED":
1120 $this->info->tempuser->deleted = $this->getContents();
1121 break;
1122 case "USERNAME":
1123 $this->info->tempuser->username = $this->getContents();
1124 break;
1125 case "PASSWORD":
1126 $this->info->tempuser->password = $this->getContents();
1127 break;
1128 case "IDNUMBER":
1129 $this->info->tempuser->idnumber = $this->getContents();
1130 break;
1131 case "FIRSTNAME":
1132 $this->info->tempuser->firstname = $this->getContents();
1133 break;
1134 case "LASTNAME":
1135 $this->info->tempuser->lastname = $this->getContents();
1136 break;
1137 case "EMAIL":
1138 $this->info->tempuser->email = $this->getContents();
1139 break;
1140 case "ICQ":
1141 $this->info->tempuser->icq = $this->getContents();
1142 break;
1143 case "PHONE1":
1144 $this->info->tempuser->phone1 = $this->getContents();
1145 break;
1146 case "PHONE2":
1147 $this->info->tempuser->phone2 = $this->getContents();
1148 break;
1149 case "INSTITUTION":
1150 $this->info->tempuser->institution = $this->getContents();
1151 break;
1152 case "DEPARTMENT":
1153 $this->info->tempuser->department = $this->getContents();
1154 break;
1155 case "ADDRESS":
1156 $this->info->tempuser->address = $this->getContents();
1157 break;
1158 case "CITY":
1159 $this->info->tempuser->city = $this->getContents();
1160 break;
1161 case "COUNTRY":
1162 $this->info->tempuser->country = $this->getContents();
1163 break;
1164 case "LANG":
1165 $this->info->tempuser->lang = $this->getContents();
1166 break;
1167 case "TIMEZONE":
1168 $this->info->tempuser->timezone = $this->getContents();
1169 break;
1170 case "FIRSTACCESS":
1171 $this->info->tempuser->firstaccess = $this->getContents();
1172 break;
1173 case "LASTACCESS":
1174 $this->info->tempuser->lastaccess = $this->getContents();
1175 break;
1176 case "LASTLOGIN":
1177 $this->info->tempuser->lastlogin = $this->getContents();
1178 break;
1179 case "CURRENTLOGIN":
1180 $this->info->tempuser->currentlogin = $this->getContents();
1181 break;
1182 case "LASTIP":
1183 $this->info->tempuser->lastip = $this->getContents();
1184 break;
1185 case "SECRET":
1186 $this->info->tempuser->secret = $this->getContents();
1187 break;
1188 case "PICTURE":
1189 $this->info->tempuser->picture = $this->getContents();
1190 break;
1191 case "URL":
1192 $this->info->tempuser->url = $this->getContents();
1193 break;
1194 case "DESCRIPTION":
1195 $this->info->tempuser->description = $this->getContents();
1196 break;
1197 case "MAILFORMAT":
1198 $this->info->tempuser->mailformat = $this->getContents();
1199 break;
1200 case "MAILDISPLAY":
1201 $this->info->tempuser->maildisplay = $this->getContents();
1202 break;
1203 case "HTMLEDITOR":
1204 $this->info->tempuser->htmleditor = $this->getContents();
1205 break;
1206 case "AUTOSUBSCRIBE":
1207 $this->info->tempuser->autosubscribe = $this->getContents();
1208 break;
1209 case "TIMEMODIFIED":
1210 $this->info->tempuser->timemodified = $this->getContents();
1211 break;
1214 if ($this->level == 6) {
1215 switch ($tagName) {
1216 case "ROLE":
1217 //We've finalized a role, get it
1218 $this->info->tempuser->roles[$this->info->temprole->type]->authority =
1219 $this->info->temprole->authority;
1220 $this->info->tempuser->roles[$this->info->temprole->type]->tea_role =
1221 $this->info->temprole->tea_role;
1222 $this->info->tempuser->roles[$this->info->temprole->type]->timestart =
1223 $this->info->temprole->timestart;
1224 $this->info->tempuser->roles[$this->info->temprole->type]->timeend =
1225 $this->info->temprole->timeend;
1226 $this->info->tempuser->roles[$this->info->temprole->type]->time =
1227 $this->info->temprole->time;
1228 unset($this->info->temprole);
1229 break;
1232 if ($this->level == 7) {
1233 switch ($tagName) {
1234 case "TYPE":
1235 $this->info->temprole->type = $this->getContents();
1236 break;
1237 case "AUTHORITY":
1238 $this->info->temprole->authority = $this->getContents();
1239 break;
1240 case "TEA_ROLE":
1241 $this->info->temprole->tea_role = $this->getContents();
1242 break;
1243 case "TIMESTART":
1244 $this->info->temprole->timestart = $this->getContents();
1245 break;
1246 case "TIMEEND":
1247 $this->info->temprole->timeend = $this->getContents();
1248 break;
1249 case "TIME":
1250 $this->info->temprole->time = $this->getContents();
1251 break;
1256 //Stop parsing if todo = USERS and tagName = USERS (en of the tag, of course)
1257 //Speed up a lot (avoid parse all)
1258 if ($tagName == "USERS" and $this->level == 3) {
1259 $this->finished = true;
1262 //Clear things
1263 $this->tree[$this->level] = "";
1264 $this->level--;
1265 $this->content = "";
1268 //This is the endTag handler we use where we are reading the modules zone (todo="MODULES")
1269 function endElementModules($parser, $tagName) {
1270 //Check if we are into MODULES zone
1271 if ($this->tree[3] == "MODULES") {
1272 //if (trim($this->content)) //Debug
1273 // echo "C".str_repeat("&nbsp;",($this->level+2)*2).$this->getContents()."<br>\n"; //Debug
1274 //echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;/".$tagName."&gt;<br>\n"; //Debug
1275 //Acumulate data to info (content + close tag)
1276 //Reconvert: strip htmlchars again and trim to generate xml data
1277 $this->temp .= htmlspecialchars(trim($this->content))."</".$tagName.">";
1278 //If we've finished a mod, xmlize it an save to db
1279 if (($this->level == 4) and ($tagName == "MOD")) {
1280 //Prepend XML standard header to info gathered
1281 $xml_data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".$this->temp;
1282 //Call to xmlize for this portion of xml data (one MOD)
1283 $data = xmlize($xml_data);
1284 //traverse_xmlize($data); //Debug
1285 //print_object ($GLOBALS['traverse_array']); //Debug
1286 //$GLOBALS['traverse_array']=""; //Debug
1287 //Now, save data to db. We'll use it later
1288 //Get id and modtype from data
1289 $mod_id = $data["MOD"]["#"]["ID"]["0"]["#"];
1290 $mod_type = $data["MOD"]["#"]["MODTYPE"]["0"]["#"];
1291 //Only if we've selected to restore it
1292 if ($this->preferences->mods[$mod_type]->restore) {
1293 //Serialize it
1294 $mod_temp = serialize($data);
1295 //Now add slashes
1296 $sla_mod_temp = addslashes($mod_temp);
1297 //Save to db
1298 backup_putid($this->preferences->backup_unique_code,$mod_type,$mod_id,
1299 null,$sla_mod_temp);
1300 //Create returning info
1301 $ret_info->id = $mod_id;
1302 $ret_info->modtype = $mod_type;
1303 $this->info[] = $ret_info;
1305 //Reset info to empty
1306 $this->temp = "";
1310 //Stop parsing if todo = MODULES and tagName = MODULES (en of the tag, of course)
1311 //Speed up a lot (avoid parse all)
1312 if ($tagName == "MODULES" and $this->level == 3) {
1313 $this->finished = true;
1316 //Clear things
1317 $this->tree[$this->level] = "";
1318 $this->level--;
1319 $this->content = "";
1322 //This is the endTag default handler we use when todo is undefined
1323 function endElement($parser, $tagName) {
1324 if (trim($this->content)) //Debug
1325 echo "C".str_repeat("&nbsp;",($this->level+2)*2).$this->getContents()."<br>\n"; //Debug
1326 echo $this->level.str_repeat("&nbsp;",$this->level*2)."&lt;/".$tagName."&gt;<br>\n"; //Debug
1328 //Clear things
1329 $this->tree[$this->level] = "";
1330 $this->level--;
1331 $this->content = "";
1334 //This is the handler to read data contents (simple accumule it)
1335 function characterData($parser, $data) {
1336 $this->content .= $data;
1340 //This function executes the MoodleParser
1341 function restore_read_xml ($xml_file,$todo,$preferences) {
1343 $status = true;
1345 $xml_parser = xml_parser_create();
1346 $moodle_parser = new MoodleParser();
1347 $moodle_parser->todo = $todo;
1348 $moodle_parser->preferences = $preferences;
1349 xml_set_object($xml_parser,&$moodle_parser);
1350 //Depending of the todo we use some element_handler or another
1351 if ($todo == "INFO") {
1352 //Define handlers to that zone
1353 xml_set_element_handler($xml_parser, "startElementInfo", "endElementInfo");
1354 } else if ($todo == "COURSE_HEADER") {
1355 //Define handlers to that zone
1356 xml_set_element_handler($xml_parser, "startElementCourseHeader", "endElementCourseHeader");
1357 } else if ($todo == "SECTIONS") {
1358 //Define handlers to that zone
1359 xml_set_element_handler($xml_parser, "startElementSections", "endElementSections");
1360 } else if ($todo == "USERS") {
1361 //Define handlers to that zone
1362 xml_set_element_handler($xml_parser, "startElementUsers", "endElementUsers");
1363 } else if ($todo == "MODULES") {
1364 //Define handlers to that zone
1365 xml_set_element_handler($xml_parser, "startElementModules", "endElementModules");
1366 } else {
1367 //Define default handlers (must no be invoked when everything become finished)
1368 xml_set_element_handler($xml_parser, "startElementInfo", "endElementInfo");
1370 xml_set_character_data_handler($xml_parser, "characterData");
1371 $fp = fopen($xml_file,"r")
1372 or $status = false;
1373 if ($status) {
1374 while ($data = fread($fp, 4096) and !$moodle_parser->finished)
1375 xml_parse($xml_parser, $data, feof($fp))
1376 or die(sprintf("XML error: %s at line %d",
1377 xml_error_string(xml_get_error_code($xml_parser)),
1378 xml_get_current_line_number($xml_parser)));
1379 fclose($fp);
1381 //Get info from parser
1382 $info = $moodle_parser->info;
1384 //Clear parser mem
1385 xml_parser_free($xml_parser);
1387 if ($status) {
1388 return $info;
1389 } else {
1390 return $status;