Commit | Line | Data |
---|---|---|
795b6945 | 1 | <?php |
52376d94 | 2 | //This file contains all the general function needed (file manipulation...) |
64acc5a5 | 3 | //not directly part of the backup/restore utility plus some constants |
4 | ||
5 | // Define "restoreto" options | |
6 | define('RESTORETO_CURRENT_DELETING', 0); | |
7 | define('RESTORETO_CURRENT_ADDING', 1); | |
8 | define('RESTORETO_NEW_COURSE', 2); | |
9 | define('RESTORETO_EXISTING_DELETING', 3); | |
10 | define('RESTORETO_EXISTING_ADDING', 4); | |
afbe3de8 | 11 | |
4e1132a8 | 12 | require_once($CFG->libdir.'/uploadlib.php'); |
13 | require_once($CFG->libdir . '/completionlib.php'); | |
8930f900 | 14 | |
eb6a973c | 15 | //Sets a name/value pair in config_plugin table |
de4746a8 | 16 | function backup_set_config($name, $value) { |
eb6a973c | 17 | return set_config($name, $value, 'backup'); |
de4746a8 | 18 | } |
19 | ||
eb6a973c | 20 | //Gets all the information from config_plugin table |
de4746a8 | 21 | function backup_get_config() { |
eb6a973c | 22 | $backup_config = get_config('backup'); |
49b95c30 | 23 | return (object)$backup_config; |
de4746a8 | 24 | } |
25 | ||
b0778a76 | 26 | //Delete old data in backup tables (if exists) |
dfd02290 | 27 | //Four hours seem to be appropiate now that backup is stable |
b0778a76 | 28 | function backup_delete_old_data() { |
ad4375ac | 29 | global $CFG, $DB; |
674b30f5 | 30 | |
b0778a76 | 31 | //Change this if you want !! |
dfd02290 | 32 | $hours = 4; |
b0778a76 | 33 | //End change this |
dfd02290 | 34 | $seconds = $hours * 60 * 60; |
b0778a76 | 35 | $delete_from = time()-$seconds; |
36 | //Now delete from tables | |
ad4375ac | 37 | $status = $DB->execute("DELETE FROM {backup_ids} |
38 | WHERE backup_code < ?", array($delete_from)); | |
674b30f5 | 39 | if ($status) { |
ad4375ac | 40 | $status = $DB->execute("DELETE FROM {backup_files} |
41 | WHERE backup_code < ?", array($delete_from)); | |
674b30f5 | 42 | } |
3b8bad6f | 43 | //Now, delete old directory (if exists) |
44 | if ($status) { | |
45 | $status = backup_delete_old_dirs($delete_from); | |
46 | } | |
b0778a76 | 47 | return($status); |
48 | } | |
674b30f5 | 49 | |
3b8bad6f | 50 | //Function to delete dirs/files into temp/backup directory |
51 | //older than $delete_from | |
52 | function backup_delete_old_dirs($delete_from) { | |
53 | ||
54 | global $CFG; | |
55 | ||
56 | $status = true; | |
41bac9d0 | 57 | //Get files and directories in the temp backup dir witout descend |
58 | $list = get_directory_list($CFG->dataroot."/temp/backup", "", false, true, true); | |
3b8bad6f | 59 | foreach ($list as $file) { |
60 | $file_path = $CFG->dataroot."/temp/backup/".$file; | |
61 | $moddate = filemtime($file_path); | |
af9cd955 | 62 | if ($status && $moddate < $delete_from) { |
cfb9c525 | 63 | //If directory, recurse |
64 | if (is_dir($file_path)) { | |
65 | $status = delete_dir_contents($file_path); | |
66 | //There is nothing, delete the directory itself | |
67 | if ($status) { | |
68 | $status = rmdir($file_path); | |
69 | } | |
70 | //If file | |
71 | } else { | |
72 | unlink("$file_path"); | |
3b8bad6f | 73 | } |
74 | } | |
75 | } | |
76 | ||
77 | return $status; | |
78 | } | |
79 | ||
3bee1ead | 80 | //Function to check and create the needed dir to |
674b30f5 | 81 | //save all the backup |
82 | function check_and_create_backup_dir($backup_unique_code) { | |
3bee1ead | 83 | global $CFG; |
674b30f5 | 84 | |
85 | $status = check_dir_exists($CFG->dataroot."/temp",true); | |
86 | if ($status) { | |
87 | $status = check_dir_exists($CFG->dataroot."/temp/backup",true); | |
88 | } | |
89 | if ($status) { | |
90 | $status = check_dir_exists($CFG->dataroot."/temp/backup/".$backup_unique_code,true); | |
91 | } | |
3bee1ead | 92 | |
674b30f5 | 93 | return $status; |
94 | } | |
95 | ||
96 | //Function to delete all the directory contents recursively | |
35ea1594 | 97 | //it supports a excluded dit too |
af9cd955 | 98 | //Copied from the web !! |
35ea1594 | 99 | function delete_dir_contents ($dir,$excludeddir="") { |
674b30f5 | 100 | |
3bee1ead | 101 | if (!is_dir($dir)) { |
9e3775db | 102 | // if we've been given a directory that doesn't exist yet, return true. |
103 | // this happens when we're trying to clear out a course that has only just | |
104 | // been created. | |
105 | return true; | |
106 | } | |
af9cd955 | 107 | $slash = "/"; |
674b30f5 | 108 | |
af9cd955 | 109 | // Create arrays to store files and directories |
110 | $dir_files = array(); | |
111 | $dir_subdirs = array(); | |
674b30f5 | 112 | |
af9cd955 | 113 | // Make sure we can delete it |
114 | chmod($dir, 0777); | |
115 | ||
116 | if ((($handle = opendir($dir))) == FALSE) { | |
117 | // The directory could not be opened | |
118 | return false; | |
119 | } | |
120 | ||
121 | // Loop through all directory entries, and construct two temporary arrays containing files and sub directories | |
ed818bbd | 122 | while(false !== ($entry = readdir($handle))) { |
35ea1594 | 123 | if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != "." && $entry != $excludeddir) { |
af9cd955 | 124 | $dir_subdirs[] = $dir. $slash .$entry; |
125 | } | |
35ea1594 | 126 | else if ($entry != ".." && $entry != "." && $entry != $excludeddir) { |
af9cd955 | 127 | $dir_files[] = $dir. $slash .$entry; |
128 | } | |
129 | } | |
130 | ||
131 | // Delete all files in the curent directory return false and halt if a file cannot be removed | |
132 | for($i=0; $i<count($dir_files); $i++) { | |
133 | chmod($dir_files[$i], 0777); | |
134 | if (((unlink($dir_files[$i]))) == FALSE) { | |
135 | return false; | |
136 | } | |
137 | } | |
138 | ||
139 | // Empty sub directories and then remove the directory | |
140 | for($i=0; $i<count($dir_subdirs); $i++) { | |
141 | chmod($dir_subdirs[$i], 0777); | |
142 | if (delete_dir_contents($dir_subdirs[$i]) == FALSE) { | |
143 | return false; | |
144 | } | |
145 | else { | |
907ef7f8 | 146 | if (remove_dir($dir_subdirs[$i]) == FALSE) { |
af9cd955 | 147 | return false; |
674b30f5 | 148 | } |
149 | } | |
150 | } | |
674b30f5 | 151 | |
af9cd955 | 152 | // Close directory |
153 | closedir($handle); | |
154 | ||
155 | // Success, every thing is gone return true | |
156 | return true; | |
674b30f5 | 157 | } |
158 | ||
159 | //Function to clear (empty) the contents of the backup_dir | |
674b30f5 | 160 | function clear_backup_dir($backup_unique_code) { |
3bee1ead | 161 | global $CFG; |
674b30f5 | 162 | |
163 | $rootdir = $CFG->dataroot."/temp/backup/".$backup_unique_code; | |
3bee1ead | 164 | |
674b30f5 | 165 | //Delete recursively |
166 | $status = delete_dir_contents($rootdir); | |
167 | ||
168 | return $status; | |
169 | } | |
3b8bad6f | 170 | |
3bee1ead | 171 | //Returns the module type of a course_module's id in a course |
cfb9c525 | 172 | function get_module_type ($courseid,$moduleid) { |
ad4375ac | 173 | global $DB; |
cfb9c525 | 174 | |
ad4375ac | 175 | $results = $DB->get_records_sql("SELECT cm.id, m.name |
176 | FROM {course_modules} cm, {modules} m | |
177 | WHERE cm.course = ? AND cm.id = ? AND | |
178 | m.id = cm.module", array($courseid, $moduleid)); | |
cfb9c525 | 179 | |
180 | if ($results) { | |
181 | $name = $results[$moduleid]->name; | |
182 | } else { | |
183 | $name = false; | |
184 | } | |
52376d94 | 185 | return $name; |
667d2f2a | 186 | } |
187 | ||
188 | //This function return the names of all directories under a give directory | |
189 | //Not recursive | |
190 | function list_directories ($rootdir) { | |
97a49e63 | 191 | |
192 | $results = null; | |
3bee1ead | 193 | |
667d2f2a | 194 | $dir = opendir($rootdir); |
ed818bbd | 195 | while (false !== ($file=readdir($dir))) { |
667d2f2a | 196 | if ($file=="." || $file=="..") { |
197 | continue; | |
198 | } | |
199 | if (is_dir($rootdir."/".$file)) { | |
200 | $results[$file] = $file; | |
201 | } | |
202 | } | |
3bee1ead | 203 | closedir($dir); |
204 | return $results; | |
667d2f2a | 205 | } |
206 | ||
207 | //This function return the names of all directories and files under a give directory | |
208 | //Not recursive | |
209 | function list_directories_and_files ($rootdir) { | |
3a4b33c3 | 210 | |
211 | $results = ""; | |
3bee1ead | 212 | |
667d2f2a | 213 | $dir = opendir($rootdir); |
ed818bbd | 214 | while (false !== ($file=readdir($dir))) { |
667d2f2a | 215 | if ($file=="." || $file=="..") { |
216 | continue; | |
217 | } | |
218 | $results[$file] = $file; | |
219 | } | |
3bee1ead | 220 | closedir($dir); |
667d2f2a | 221 | return $results; |
222 | } | |
223 | ||
47846965 | 224 | //This function clean data from backup tables and |
225 | //delete all temp files used | |
226 | function clean_temp_data ($preferences) { | |
ad4375ac | 227 | global $CFG, $DB; |
47846965 | 228 | |
229 | $status = true; | |
230 | ||
231 | //true->do it, false->don't do it. To debug if necessary. | |
232 | if (true) { | |
233 | //Now delete from tables | |
ad4375ac | 234 | $status = $DB->delete_records('backup_ids', array('backup_code'=>$preferences->backup_unique_code)) |
235 | && $DB->delete_records('backup_files', array('backup_code'=>$preferences->backup_unique_code)); | |
236 | ||
47846965 | 237 | //Now, delete temp directory (if exists) |
238 | $file_path = $CFG->dataroot."/temp/backup/".$preferences->backup_unique_code; | |
239 | if (is_dir($file_path)) { | |
240 | $status = delete_dir_contents($file_path); | |
241 | //There is nothing, delete the directory itself | |
242 | if ($status) { | |
243 | $status = rmdir($file_path); | |
244 | } | |
245 | } | |
246 | } | |
247 | return $status; | |
248 | } | |
249 | ||
efead3b9 | 250 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
251 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
252 | //This functions are used to copy any file or directory ($from_file) | |
253 | //to a new file or directory ($to_file). It works recursively and | |
254 | //mantains file perms. | |
255 | //I've copied it from: http://www.php.net/manual/en/function.copy.php | |
256 | //Little modifications done | |
3bee1ead | 257 | |
d27920b9 | 258 | function backup_copy_file ($from_file,$to_file,$log_clam=false) { |
f654deea | 259 | global $CFG; |
260 | ||
efead3b9 | 261 | if (is_file($from_file)) { |
7ef0797d | 262 | //echo "<br />Copying ".$from_file." to ".$to_file; //Debug |
f654deea | 263 | //$perms=fileperms($from_file); |
264 | //return copy($from_file,$to_file) && chmod($to_file,$perms); | |
265 | umask(0000); | |
9704c866 | 266 | if (copy($from_file,$to_file)) { |
267 | chmod($to_file,$CFG->directorypermissions); | |
d27920b9 | 268 | if (!empty($log_clam)) { |
269 | clam_log_upload($to_file,null,true); | |
270 | } | |
8930f900 | 271 | return true; |
272 | } | |
273 | return false; | |
efead3b9 | 274 | } |
275 | else if (is_dir($from_file)) { | |
276 | return backup_copy_dir($from_file,$to_file); | |
277 | } | |
278 | else{ | |
7ef0797d | 279 | //echo "<br />Error: not file or dir ".$from_file; //Debug |
efead3b9 | 280 | return false; |
281 | } | |
cfb9c525 | 282 | } |
efead3b9 | 283 | |
284 | function backup_copy_dir($from_file,$to_file) { | |
93808667 | 285 | global $CFG; |
286 | ||
615b4a13 | 287 | $status = true; // Initialize this, next code will change its value if needed |
288 | ||
efead3b9 | 289 | if (!is_dir($to_file)) { |
7ef0797d | 290 | //echo "<br />Creating ".$to_file; //Debug |
f654deea | 291 | umask(0000); |
795b6945 | 292 | $status = mkdir($to_file,$CFG->directorypermissions); |
efead3b9 | 293 | } |
294 | $dir = opendir($from_file); | |
ed818bbd | 295 | while (false !== ($file=readdir($dir))) { |
efead3b9 | 296 | if ($file=="." || $file=="..") { |
297 | continue; | |
298 | } | |
4f6ae69e | 299 | $status = backup_copy_file ("$from_file/$file","$to_file/$file"); |
efead3b9 | 300 | } |
4f6ae69e | 301 | closedir($dir); |
302 | return $status; | |
efead3b9 | 303 | } |
304 | ///Ends copy file/dirs functions | |
305 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
306 | // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
7641819d | 307 | |
d61f7b76 | 308 | /** |
309 | * Are we restoring a backup that was made on the same site that we are restoring to? | |
310 | * This relies on some information that was only added to backup files in January 2009. | |
311 | * For older backup files, fall back to guessing based on wwwroot. MDL-16614 explains | |
312 | * when this guess could give the wrong answer. | |
313 | * @return boolean true if the backup was made on the same site we are restoring to. | |
314 | */ | |
315 | function backup_is_same_site(&$restore) { | |
316 | global $CFG; | |
317 | static $hashedsiteid = null; | |
318 | if (is_null($hashedsiteid)) { | |
319 | $hashedsiteid = md5(get_site_identifier()); | |
320 | } | |
321 | if (!empty($restore->original_siteidentifier)) { | |
322 | return $restore->original_siteidentifier == $hashedsiteid; | |
323 | } else { | |
324 | return $restore->original_wwwroot == $CFG->wwwroot; | |
325 | } | |
326 | } | |
10dcde40 | 327 | |
7ba74615 | 328 | //This function is used to insert records in the backup_ids table |
af9cd955 | 329 | //If the info field is greater than max_db_storage, then its info |
330 | //is saved to filesystem | |
ad4375ac | 331 | function backup_putid($backup_unique_code, $table, $old_id, $new_id, $info="") { |
332 | global $CFG, $DB; | |
af9cd955 | 333 | |
334 | $max_db_storage = 128; //Max bytes to save to db, else save to file | |
3bee1ead | 335 | |
7ba74615 | 336 | $status = true; |
3bee1ead | 337 | |
7ba74615 | 338 | //First delete to avoid PK duplicates |
339 | $status = backup_delid($backup_unique_code, $table, $old_id); | |
340 | ||
af9cd955 | 341 | //Now, serialize info |
342 | $info_ser = serialize($info); | |
343 | ||
3bee1ead | 344 | //Now, if the size of $info_ser > $max_db_storage, save it to filesystem and |
af9cd955 | 345 | //insert a "infile" in the info field |
346 | ||
347 | if (strlen($info_ser) > $max_db_storage) { | |
348 | //Calculate filename (in current_backup_dir, $backup_unique_code_$table_$old_id.info) | |
349 | $filename = $CFG->dataroot."/temp/backup/".$backup_unique_code."/".$backup_unique_code."_".$table."_".$old_id.".info"; | |
350 | //Save data to file | |
3bee1ead | 351 | $status = backup_data2file($filename,$info_ser); |
af9cd955 | 352 | //Set info_to save |
353 | $info_to_save = "infile"; | |
354 | } else { | |
294ce987 | 355 | //Saving to db |
ad4375ac | 356 | $info_to_save = $info_ser; |
af9cd955 | 357 | } |
358 | ||
359 | //Now, insert the record | |
360 | if ($status) { | |
d8e24b78 | 361 | //Build the record |
e0aac7f3 | 362 | $rec = new object(); |
d8e24b78 | 363 | $rec->backup_code = $backup_unique_code; |
364 | $rec->table_name = $table; | |
365 | $rec->old_id = $old_id; | |
062a84a6 | 366 | $rec->new_id = ($new_id === null? 0 : $new_id); |
d8e24b78 | 367 | $rec->info = $info_to_save; |
15a6cf33 | 368 | |
fc29e51b | 369 | $DB->insert_record('backup_ids', $rec, false); |
af9cd955 | 370 | } |
7ba74615 | 371 | return $status; |
372 | } | |
373 | ||
374 | //This function is used to delete recods from the backup_ids table | |
af9cd955 | 375 | //If the info field is "infile" then the file is deleted too |
7ba74615 | 376 | function backup_delid ($backup_unique_code, $table, $old_id) { |
ad4375ac | 377 | global $DB; |
a4e315c6 | 378 | return $DB->delete_records('backup_ids', array('backup_code'=>$backup_unique_code, 'table_name'=>$table, 'old_id'=>$old_id)); |
7ba74615 | 379 | } |
a2c7397c | 380 | |
381 | //This function is used to get a record from the backup_ids table | |
af9cd955 | 382 | //If the info field is "infile" then its info |
383 | //is read from filesystem | |
a2c7397c | 384 | function backup_getid ($backup_unique_code, $table, $old_id) { |
ad4375ac | 385 | global $CFG, $DB; |
a2c7397c | 386 | |
387 | $status = true; | |
af9cd955 | 388 | $status2 = true; |
a2c7397c | 389 | |
795b6945 | 390 | $status = $DB->get_record("backup_ids", array("backup_code"=>$backup_unique_code, |
ad4375ac | 391 | "table_name"=>$table, "old_id"=>$old_id)); |
a2c7397c | 392 | |
af9cd955 | 393 | //If info field = "infile", get file contents |
9a7538a3 | 394 | if (!empty($status->info) && $status->info == "infile") { |
af9cd955 | 395 | $filename = $CFG->dataroot."/temp/backup/".$backup_unique_code."/".$backup_unique_code."_".$table."_".$old_id.".info"; |
396 | //Read data from file | |
397 | $status2 = backup_file2data($filename,$info); | |
398 | if ($status2) { | |
399 | //unserialize data | |
400 | $status->info = unserialize($info); | |
401 | } else { | |
402 | $status = false; | |
403 | } | |
404 | } else { | |
783ab2b0 | 405 | //Only if status (record exists) |
7f9bd149 | 406 | if (!empty($status->info)) { |
795b6945 PS |
407 | if ($status->info === 'needed') { |
408 | // TODO: ugly hack - fix before 1.9.1 | |
7f9bd149 | 409 | debugging('Incorrect string "needed" in $status->info, please fix the code (table:'.$table.'; old_id:'.$old_id.').', DEBUG_DEVELOPER); |
410 | } else { | |
411 | ////First strip slashes | |
ad4375ac | 412 | $temp = $status->info; |
7f9bd149 | 413 | //Now unserialize |
414 | $status->info = unserialize($temp); | |
415 | } | |
783ab2b0 | 416 | } |
af9cd955 | 417 | } |
418 | ||
a2c7397c | 419 | return $status; |
420 | } | |
6d18c5a2 | 421 | |
fd5ca378 | 422 | //This function is used to add slashes (and decode from UTF-8 if needed) |
6d18c5a2 | 423 | //It's used intensivelly when restoring modules and saving them in db |
9db7dab2 | 424 | function backup_todb ($data) { |
e814e7d7 | 425 | // MDL-10770 |
f23dea66 | 426 | if ($data === '$@NULL@$') { |
e295df44 | 427 | return null; |
e814e7d7 | 428 | } else { |
7f9bd149 | 429 | return restore_decode_absolute_links($data); |
e814e7d7 | 430 | } |
6d18c5a2 | 431 | } |
432 | ||
3bee1ead | 433 | //This function is used to check that every necessary function to |
fe3c84ab | 434 | //backup/restore exists in the current php installation. Thanks to |
435 | //gregb@crowncollege.edu by the idea. | |
f90666aa | 436 | function backup_required_functions($justcheck=false) { |
fe3c84ab | 437 | |
d2c94f4b | 438 | if(!function_exists('utf8_encode')) { |
f90666aa | 439 | if (empty($justcheck)) { |
5832a6f3 | 440 | print_error('needphpext', '', '', 'XML'); |
f90666aa | 441 | } else { |
442 | return false; | |
443 | } | |
fe3c84ab | 444 | } |
445 | ||
f90666aa | 446 | return true; |
fe3c84ab | 447 | } |
60b420af | 448 | |
449 | //This function send n white characters to the browser and flush the | |
450 | //output buffer. Used to avoid browser timeouts and to show the progress. | |
451 | function backup_flush($n=0,$time=false) { | |
f90666aa | 452 | if (defined('RESTORE_SILENTLY_NOFLUSH')) { |
453 | return; | |
454 | } | |
60b420af | 455 | if ($time) { |
456 | $ti = strftime("%X",time()); | |
457 | } else { | |
458 | $ti = ""; | |
459 | } | |
460 | echo str_repeat(" ", $n) . $ti . "\n"; | |
461 | flush(); | |
462 | } | |
3bee1ead | 463 | |
af9cd955 | 464 | //This function creates the filename and write data to it |
465 | //returning status as result | |
466 | function backup_data2file ($file,&$data) { | |
467 | ||
468 | $status = true; | |
469 | $status2 = true; | |
3bee1ead | 470 | |
af9cd955 | 471 | $f = fopen($file,"w"); |
472 | $status = fwrite($f,$data); | |
473 | $status2 = fclose($f); | |
474 | ||
475 | return ($status && $status2); | |
476 | } | |
fe3c84ab | 477 | |
af9cd955 | 478 | //This function read the filename and read data from it |
479 | function backup_file2data ($file,&$data) { | |
480 | ||
481 | $status = true; | |
482 | $status2 = true; | |
483 | ||
484 | $f = fopen($file,"r"); | |
485 | $data = fread ($f,filesize($file)); | |
486 | $status2 = fclose($f); | |
487 | ||
488 | return ($status && $status2); | |
489 | } | |
f90666aa | 490 | |
491 | /** this function will restore an entire backup.zip into the specified course | |
492 | * using standard moodle backup/restore functions, but silently. | |
493 | * @param string $pathtofile the absolute path to the backup file. | |
494 | * @param int $destinationcourse the course id to restore to. | |
495 | * @param boolean $emptyfirst whether to delete all coursedata first. | |
496 | * @param boolean $userdata whether to include any userdata that may be in the backup file. | |
9e3775db | 497 | * @param array $preferences optional, 0 will be used. Can contain: |
498 | * metacourse | |
499 | * logs | |
500 | * course_files | |
501 | * messages | |
f90666aa | 502 | */ |
9e3775db | 503 | function import_backup_file_silently($pathtofile,$destinationcourse,$emptyfirst=false,$userdata=false, $preferences=array()) { |
ad4375ac | 504 | global $CFG,$SESSION,$USER, $DB; // is there such a thing on cron? I guess so.. |
9e3775db | 505 | global $restore; // ick |
f90666aa | 506 | |
062173b0 | 507 | if (!defined('RESTORE_SILENTLY')) { |
508 | define('RESTORE_SILENTLY',true); // don't output all the stuff to us. | |
509 | } | |
3bee1ead | 510 | |
f90666aa | 511 | $debuginfo = 'import_backup_file_silently: '; |
512 | $cleanupafter = false; | |
513 | $errorstr = ''; // passed by reference to restore_precheck to get errors from. | |
514 | ||
ad4375ac | 515 | if (!$course = $DB->get_record('course', array('id'=>$destinationcourse))) { |
f90666aa | 516 | mtrace($debuginfo.'Course with id $destinationcourse was not a valid course!'); |
517 | return false; | |
518 | } | |
519 | ||
520 | // first check we have a valid file. | |
521 | if (!file_exists($pathtofile) || !is_readable($pathtofile)) { | |
522 | mtrace($debuginfo.'File '.$pathtofile.' either didn\'t exist or wasn\'t readable'); | |
523 | return false; | |
524 | } | |
525 | ||
526 | // now make sure it's a zip file | |
527 | require_once($CFG->dirroot.'/lib/filelib.php'); | |
528 | $filename = substr($pathtofile,strrpos($pathtofile,'/')+1); | |
529 | $mimetype = mimeinfo("type", $filename); | |
530 | if ($mimetype != 'application/zip') { | |
531 | mtrace($debuginfo.'File '.$pathtofile.' was of wrong mimetype ('.$mimetype.')' ); | |
532 | return false; | |
533 | } | |
534 | ||
535 | // restore_precheck wants this within dataroot, so lets put it there if it's not already.. | |
536 | if (strstr($pathtofile,$CFG->dataroot) === false) { | |
537 | // first try and actually move it.. | |
538 | if (!check_dir_exists($CFG->dataroot.'/temp/backup/',true)) { | |
539 | mtrace($debuginfo.'File '.$pathtofile.' outside of dataroot and couldn\'t move it! '); | |
540 | return false; | |
541 | } | |
542 | if (!copy($pathtofile,$CFG->dataroot.'/temp/backup/'.$filename)) { | |
543 | mtrace($debuginfo.'File '.$pathtofile.' outside of dataroot and couldn\'t move it! '); | |
544 | return false; | |
545 | } else { | |
546 | $pathtofile = 'temp/backup/'.$filename; | |
547 | $cleanupafter = true; | |
548 | } | |
549 | } else { | |
550 | // it is within dataroot, so take it off the path for restore_precheck. | |
551 | $pathtofile = substr($pathtofile,strlen($CFG->dataroot.'/')); | |
552 | } | |
553 | ||
554 | if (!backup_required_functions()) { | |
555 | mtrace($debuginfo.'Required function check failed (see backup_required_functions)'); | |
556 | return false; | |
557 | } | |
f90666aa | 558 | @ini_set("max_execution_time","3000"); |
1ed8e660 | 559 | if (empty($CFG->extramemorylimit)) { |
7022dd39 | 560 | raise_memory_limit('128M'); |
561 | } else { | |
1ed8e660 | 562 | raise_memory_limit($CFG->extramemorylimit); |
7022dd39 | 563 | } |
3bee1ead | 564 | |
f90666aa | 565 | if (!$backup_unique_code = restore_precheck($destinationcourse,$pathtofile,$errorstr,true)) { |
566 | mtrace($debuginfo.'Failed restore_precheck (error was '.$errorstr.')'); | |
567 | return false; | |
568 | } | |
3bee1ead | 569 | |
9e3775db | 570 | $SESSION->restore = new StdClass; |
f90666aa | 571 | |
572 | // add on some extra stuff we need... | |
9e3775db | 573 | $SESSION->restore->metacourse = $restore->metacourse = (isset($preferences['restore_metacourse']) ? $preferences['restore_metacourse'] : 0); |
64acc5a5 | 574 | $SESSION->restore->restoreto = $restore->restoreto = RESTORETO_CURRENT_ADDING; |
9e3775db | 575 | $SESSION->restore->users = $restore->users = $userdata; |
0130c489 | 576 | $SESSION->restore->groups = $restore->groups = (isset($preferences['restore_groups']) ? $preferences['restore_groups'] : RESTORE_GROUPS_NONE); |
9e3775db | 577 | $SESSION->restore->logs = $restore->logs = (isset($preferences['restore_logs']) ? $preferences['restore_logs'] : 0); |
578 | $SESSION->restore->user_files = $restore->user_files = $userdata; | |
579 | $SESSION->restore->messages = $restore->messages = (isset($preferences['restore_messages']) ? $preferences['restore_messages'] : 0); | |
0130c489 | 580 | $SESSION->restore->blogs = $restore->blogs = (isset($preferences['restore_blogs']) ? $preferences['restore_blogs'] : 0); |
9e3775db | 581 | $SESSION->restore->course_id = $restore->course_id = $destinationcourse; |
9e3775db | 582 | $SESSION->restore->deleting = $emptyfirst; |
583 | $SESSION->restore->restore_course_files = $restore->course_files = (isset($preferences['restore_course_files']) ? $preferences['restore_course_files'] : 0); | |
0130c489 | 584 | $SESSION->restore->restore_site_files = $restore->site_files = (isset($preferences['restore_site_files']) ? $preferences['restore_site_files'] : 0); |
9e3775db | 585 | $SESSION->restore->backup_version = $SESSION->info->backup_backup_version; |
586 | $SESSION->restore->course_startdateoffset = $course->startdate - $SESSION->course_header->course_startdate; | |
587 | ||
588 | restore_setup_for_check($SESSION->restore,$backup_unique_code); | |
f90666aa | 589 | |
590 | // maybe we need users (defaults to 2 in restore_setup_for_check) | |
591 | if (!empty($userdata)) { | |
592 | $SESSION->restore->users = 1; | |
593 | } | |
594 | ||
595 | // we also need modules... | |
ad4375ac | 596 | if ($allmods = $DB->get_records("modules")) { |
f90666aa | 597 | foreach ($allmods as $mod) { |
598 | $modname = $mod->name; | |
599 | //Now check that we have that module info in the backup file | |
600 | if (isset($SESSION->info->mods[$modname]) && $SESSION->info->mods[$modname]->backup == "true") { | |
601 | $SESSION->restore->mods[$modname]->restore = true; | |
602 | $SESSION->restore->mods[$modname]->userinfo = $userdata; | |
603 | } | |
9e3775db | 604 | else { |
605 | // avoid warnings | |
606 | $SESSION->restore->mods[$modname]->restore = false; | |
607 | $SESSION->restore->mods[$modname]->userinfo = false; | |
608 | } | |
f90666aa | 609 | } |
610 | } | |
9e3775db | 611 | $restore = clone($SESSION->restore); |
f90666aa | 612 | if (!restore_execute($SESSION->restore,$SESSION->info,$SESSION->course_header,$errorstr)) { |
613 | mtrace($debuginfo.'Failed restore_execute (error was '.$errorstr.')'); | |
614 | return false; | |
615 | } | |
616 | return true; | |
617 | } | |
618 | ||
3bee1ead | 619 | /** |
9e3775db | 620 | * Function to backup an entire course silently and create a zipfile. |
3bee1ead | 621 | * |
622 | * @param int $courseid the id of the course | |
9e3775db | 623 | * @param array $prefs see {@link backup_generate_preferences_artificially} |
624 | */ | |
625 | function backup_course_silently($courseid, $prefs, &$errorstring) { | |
ad4375ac | 626 | global $CFG, $preferences, $DB; // global preferences here because something else wants it :( |
062173b0 | 627 | if (!defined('BACKUP_SILENTLY')) { |
628 | define('BACKUP_SILENTLY', 1); | |
629 | } | |
ad4375ac | 630 | if (!$course = $DB->get_record('course', array('id'=>$courseid))) { |
9e3775db | 631 | debugging("Couldn't find course with id $courseid in backup_course_silently"); |
632 | return false; | |
633 | } | |
3bee1ead | 634 | $preferences = backup_generate_preferences_artificially($course, $prefs); |
9e3775db | 635 | if (backup_execute($preferences, $errorstring)) { |
636 | return $CFG->dataroot . '/' . $course->id . '/backupdata/' . $preferences->backup_name; | |
637 | } | |
638 | else { | |
639 | return false; | |
640 | } | |
641 | } | |
642 | ||
643 | /** | |
3bee1ead | 644 | * Function to generate the $preferences variable that |
9e3775db | 645 | * backup uses. This will back up all modules and instances in a course. |
3bee1ead | 646 | * |
9e3775db | 647 | * @param object $course course object |
648 | * @param array $prefs can contain: | |
649 | backup_metacourse | |
650 | backup_users | |
651 | backup_logs | |
652 | backup_user_files | |
653 | backup_course_files | |
3bee1ead | 654 | backup_site_files |
9e3775db | 655 | backup_messages |
656 | * and if not provided, they will not be included. | |
657 | */ | |
658 | ||
659 | function backup_generate_preferences_artificially($course, $prefs) { | |
ad4375ac | 660 | global $CFG, $DB; |
9e3775db | 661 | $preferences = new StdClass; |
662 | $preferences->backup_unique_code = time(); | |
73ac87a4 | 663 | $preferences->backup_users = (isset($prefs['backup_users']) ? $prefs['backup_users'] : 0); |
9e3775db | 664 | $preferences->backup_name = backup_get_zipfile_name($course, $preferences->backup_unique_code); |
665 | $count = 0; | |
666 | ||
ad4375ac | 667 | if ($allmods = $DB->get_records("modules") ) { |
9e3775db | 668 | foreach ($allmods as $mod) { |
669 | $modname = $mod->name; | |
670 | $modfile = "$CFG->dirroot/mod/$modname/backuplib.php"; | |
671 | $modbackup = $modname."_backup_mods"; | |
672 | $modbackupone = $modname."_backup_one_mod"; | |
673 | $modcheckbackup = $modname."_check_backup_mods"; | |
674 | if (!file_exists($modfile)) { | |
675 | continue; | |
676 | } | |
677 | include_once($modfile); | |
678 | if (!function_exists($modbackup) || !function_exists($modcheckbackup)) { | |
679 | continue; | |
680 | } | |
73ac87a4 | 681 | $modcheckbackup($course->id, $preferences->backup_users, $preferences->backup_unique_code); |
9e3775db | 682 | $var = "exists_".$modname; |
683 | $preferences->$var = true; | |
684 | $count++; | |
685 | // check that there are instances and we can back them up individually | |
ad4375ac | 686 | if (!$DB->count_records('course_modules', array('course'=>$course->id), array('module'=>$mod->id)) || !function_exists($modbackupone)) { |
9e3775db | 687 | continue; |
688 | } | |
689 | $var = 'exists_one_'.$modname; | |
690 | $preferences->$var = true; | |
691 | $varname = $modname.'_instances'; | |
f8f95b45 | 692 | $preferences->$varname = get_all_instances_in_course($modname, $course, NULL, true); |
9e3775db | 693 | foreach ($preferences->$varname as $instance) { |
694 | $preferences->mods[$modname]->instances[$instance->id]->name = $instance->name; | |
695 | $var = 'backup_'.$modname.'_instance_'.$instance->id; | |
696 | $preferences->$var = true; | |
697 | $preferences->mods[$modname]->instances[$instance->id]->backup = true; | |
698 | $var = 'backup_user_info_'.$modname.'_instance_'.$instance->id; | |
699 | $preferences->$var = true; | |
700 | $preferences->mods[$modname]->instances[$instance->id]->userinfo = true; | |
701 | $var = 'backup_'.$modname.'_instances'; | |
702 | $preferences->$var = 1; // we need this later to determine what to display in modcheckbackup. | |
703 | } | |
704 | ||
705 | //Check data | |
706 | //Check module info | |
707 | $preferences->mods[$modname]->name = $modname; | |
708 | ||
709 | $var = "backup_".$modname; | |
710 | $preferences->$var = true; | |
711 | $preferences->mods[$modname]->backup = true; | |
712 | ||
713 | //Check include user info | |
714 | $var = "backup_user_info_".$modname; | |
715 | $preferences->$var = true; | |
716 | $preferences->mods[$modname]->userinfo = true; | |
717 | ||
718 | } | |
719 | } | |
3bee1ead | 720 | |
9e3775db | 721 | //Check other parameters |
722 | $preferences->backup_metacourse = (isset($prefs['backup_metacourse']) ? $prefs['backup_metacourse'] : 0); | |
9e3775db | 723 | $preferences->backup_logs = (isset($prefs['backup_logs']) ? $prefs['backup_logs'] : 0); |
724 | $preferences->backup_user_files = (isset($prefs['backup_user_files']) ? $prefs['backup_user_files'] : 0); | |
725 | $preferences->backup_course_files = (isset($prefs['backup_course_files']) ? $prefs['backup_course_files'] : 0); | |
3bee1ead | 726 | $preferences->backup_site_files = (isset($prefs['backup_site_files']) ? $prefs['backup_site_files'] : 0); |
9e3775db | 727 | $preferences->backup_messages = (isset($prefs['backup_messages']) ? $prefs['backup_messages'] : 0); |
68e3ffbb | 728 | $preferences->backup_gradebook_history = (isset($prefs['backup_gradebook_history']) ? $prefs['backup_gradebook_history'] : 0); |
eb7687ea | 729 | $preferences->backup_blogs = (isset($prefs['backup_blogs']) ? $prefs['backup_blogs'] : 0); |
9e3775db | 730 | $preferences->backup_course = $course->id; |
73ac87a4 | 731 | |
732 | //Check users | |
733 | user_check_backup($course->id,$preferences->backup_unique_code,$preferences->backup_users,$preferences->backup_messages, $preferences->backup_blogs); | |
734 | ||
735 | //Check logs | |
736 | log_check_backup($course->id); | |
737 | ||
738 | //Check user files | |
739 | user_files_check_backup($course->id,$preferences->backup_unique_code); | |
740 | ||
741 | //Check course files | |
742 | course_files_check_backup($course->id,$preferences->backup_unique_code); | |
743 | ||
744 | //Check site files | |
745 | site_files_check_backup($course->id,$preferences->backup_unique_code); | |
746 | ||
747 | //Role assignments | |
0990f7aa | 748 | $roles = $DB->get_records('role', null, 'sortorder'); |
73ac87a4 | 749 | foreach ($roles as $role) { |
750 | $preferences->backuproleassignments[$role->id] = $role; | |
751 | } | |
752 | ||
9e3775db | 753 | backup_add_static_preferences($preferences); |
754 | return $preferences; | |
755 | } | |
795b6945 | 756 | function add_to_backup_log($starttime,$courseid,$message, $backuptype) { |
bc7ec91a | 757 | global $DB; |
758 | $log = new object(); | |
759 | $log->courseid = $courseid; | |
760 | $log->time = time(); | |
761 | $log->laststarttime = $starttime; | |
762 | $log->info = $message; | |
763 | $log->backuptype = $backuptype; | |
764 | $DB->insert_record('backup_log', $log); | |
765 | } | |
9e3775db | 766 |