polished.
[moodle.git] / backup / lib.php
CommitLineData
9704c866 1<?php //$Id$
52376d94 2 //This file contains all the general function needed (file manipulation...)
3 //not directly part of the backup/restore utility
afbe3de8 4
8930f900 5 require_once($CFG->dirroot.'/lib/uploadlib.php');
6
de4746a8 7 //Sets a name/value pair in backup_config table
8 function backup_set_config($name, $value) {
9 if (get_field("backup_config", "name", "name", $name)) {
10 return set_field("backup_config", "value", $value, "name", $name);
11 } else {
12 $config->name = $name;
13 $config->value = $value;
14 return insert_record("backup_config", $config);
15 }
16 }
17
18 //Gets all the information from backup_config table
19 function backup_get_config() {
20 $backup_config = null;
37afa39a 21 if ($configs = get_records("backup_config")) {
de4746a8 22 foreach ($configs as $config) {
23 $backup_config[$config->name] = $config->value;
24 }
25 }
49b95c30 26 return (object)$backup_config;
de4746a8 27 }
28
b0778a76 29 //Delete old data in backup tables (if exists)
dfd02290 30 //Four hours seem to be appropiate now that backup is stable
b0778a76 31 function backup_delete_old_data() {
674b30f5 32
33 global $CFG;
34
b0778a76 35 //Change this if you want !!
dfd02290 36 $hours = 4;
b0778a76 37 //End change this
dfd02290 38 $seconds = $hours * 60 * 60;
b0778a76 39 $delete_from = time()-$seconds;
40 //Now delete from tables
674b30f5 41 $status = execute_sql("DELETE FROM {$CFG->prefix}backup_ids
42 WHERE backup_code < '$delete_from'",false);
43 if ($status) {
44 $status = execute_sql("DELETE FROM {$CFG->prefix}backup_files
45 WHERE backup_code < '$delete_from'",false);
46 }
3b8bad6f 47 //Now, delete old directory (if exists)
48 if ($status) {
49 $status = backup_delete_old_dirs($delete_from);
50 }
b0778a76 51 return($status);
52 }
674b30f5 53
3b8bad6f 54 //Function to delete dirs/files into temp/backup directory
55 //older than $delete_from
56 function backup_delete_old_dirs($delete_from) {
57
58 global $CFG;
59
60 $status = true;
41bac9d0 61 //Get files and directories in the temp backup dir witout descend
62 $list = get_directory_list($CFG->dataroot."/temp/backup", "", false, true, true);
3b8bad6f 63 foreach ($list as $file) {
64 $file_path = $CFG->dataroot."/temp/backup/".$file;
65 $moddate = filemtime($file_path);
af9cd955 66 if ($status && $moddate < $delete_from) {
cfb9c525 67 //If directory, recurse
68 if (is_dir($file_path)) {
69 $status = delete_dir_contents($file_path);
70 //There is nothing, delete the directory itself
71 if ($status) {
72 $status = rmdir($file_path);
73 }
74 //If file
75 } else {
76 unlink("$file_path");
3b8bad6f 77 }
78 }
79 }
80
81 return $status;
82 }
83
674b30f5 84 //Function to check if a directory exists
85 //and, optionally, create it
86 function check_dir_exists($dir,$create=false) {
87
88 global $CFG;
89
90 $status = true;
91 if(!is_dir($dir)) {
92 if (!$create) {
93 $status = false;
94 } else {
1bdeb2ca 95 umask(0000);
674b30f5 96 $status = mkdir ($dir,$CFG->directorypermissions);
97 }
98 }
99 return $status;
100 }
101
102 //Function to check and create the needed dir to
103 //save all the backup
104 function check_and_create_backup_dir($backup_unique_code) {
105
106 global $CFG;
107
108 $status = check_dir_exists($CFG->dataroot."/temp",true);
109 if ($status) {
110 $status = check_dir_exists($CFG->dataroot."/temp/backup",true);
111 }
112 if ($status) {
113 $status = check_dir_exists($CFG->dataroot."/temp/backup/".$backup_unique_code,true);
114 }
115
116 return $status;
117 }
118
119 //Function to delete all the directory contents recursively
35ea1594 120 //it supports a excluded dit too
af9cd955 121 //Copied from the web !!
35ea1594 122 function delete_dir_contents ($dir,$excludeddir="") {
674b30f5 123
af9cd955 124 $slash = "/";
674b30f5 125
af9cd955 126 // Create arrays to store files and directories
127 $dir_files = array();
128 $dir_subdirs = array();
674b30f5 129
af9cd955 130 // Make sure we can delete it
131 chmod($dir, 0777);
132
133 if ((($handle = opendir($dir))) == FALSE) {
134 // The directory could not be opened
135 return false;
136 }
137
138 // Loop through all directory entries, and construct two temporary arrays containing files and sub directories
139 while($entry = readdir($handle)) {
35ea1594 140 if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != "." && $entry != $excludeddir) {
af9cd955 141 $dir_subdirs[] = $dir. $slash .$entry;
142 }
35ea1594 143 else if ($entry != ".." && $entry != "." && $entry != $excludeddir) {
af9cd955 144 $dir_files[] = $dir. $slash .$entry;
145 }
146 }
147
148 // Delete all files in the curent directory return false and halt if a file cannot be removed
149 for($i=0; $i<count($dir_files); $i++) {
150 chmod($dir_files[$i], 0777);
151 if (((unlink($dir_files[$i]))) == FALSE) {
152 return false;
153 }
154 }
155
156 // Empty sub directories and then remove the directory
157 for($i=0; $i<count($dir_subdirs); $i++) {
158 chmod($dir_subdirs[$i], 0777);
159 if (delete_dir_contents($dir_subdirs[$i]) == FALSE) {
160 return false;
161 }
162 else {
163 if (rmdir($dir_subdirs[$i]) == FALSE) {
164 return false;
674b30f5 165 }
166 }
167 }
674b30f5 168
af9cd955 169 // Close directory
170 closedir($handle);
171
172 // Success, every thing is gone return true
173 return true;
674b30f5 174 }
175
176 //Function to clear (empty) the contents of the backup_dir
674b30f5 177 function clear_backup_dir($backup_unique_code) {
178
179 global $CFG;
180
181 $rootdir = $CFG->dataroot."/temp/backup/".$backup_unique_code;
182
183 //Delete recursively
184 $status = delete_dir_contents($rootdir);
185
186 return $status;
187 }
3b8bad6f 188
cfb9c525 189 //Returns the module type of a course_module's id in a course
190 function get_module_type ($courseid,$moduleid) {
191
192 global $CFG;
193
194 $results = get_records_sql ("SELECT cm.id, m.name
195 FROM {$CFG->prefix}course_modules cm,
196 {$CFG->prefix}modules m
197 WHERE cm.course = '$courseid' AND
198 cm.id = '$moduleid' AND
199 m.id = cm.module");
200
201 if ($results) {
202 $name = $results[$moduleid]->name;
203 } else {
204 $name = false;
205 }
52376d94 206 return $name;
667d2f2a 207 }
208
209 //This function return the names of all directories under a give directory
210 //Not recursive
211 function list_directories ($rootdir) {
97a49e63 212
213 $results = null;
667d2f2a 214
215 $dir = opendir($rootdir);
216 while ($file=readdir($dir)) {
217 if ($file=="." || $file=="..") {
218 continue;
219 }
220 if (is_dir($rootdir."/".$file)) {
221 $results[$file] = $file;
222 }
223 }
224 closedir($dir);
225 return $results;
226 }
227
228 //This function return the names of all directories and files under a give directory
229 //Not recursive
230 function list_directories_and_files ($rootdir) {
3a4b33c3 231
232 $results = "";
667d2f2a 233
234 $dir = opendir($rootdir);
235 while ($file=readdir($dir)) {
236 if ($file=="." || $file=="..") {
237 continue;
238 }
239 $results[$file] = $file;
240 }
241 closedir($dir);
242 return $results;
243 }
244
47846965 245 //This function clean data from backup tables and
246 //delete all temp files used
247 function clean_temp_data ($preferences) {
248
47846965 249 global $CFG;
250
251 $status = true;
252
253 //true->do it, false->don't do it. To debug if necessary.
254 if (true) {
255 //Now delete from tables
256 $status = execute_sql("DELETE FROM {$CFG->prefix}backup_ids
af478c0b 257 WHERE backup_code = '$preferences->backup_unique_code'",false);
47846965 258 if ($status) {
259 $status = execute_sql("DELETE FROM {$CFG->prefix}backup_files
af478c0b 260 WHERE backup_code = '$preferences->backup_unique_code'",false);
47846965 261 }
262 //Now, delete temp directory (if exists)
263 $file_path = $CFG->dataroot."/temp/backup/".$preferences->backup_unique_code;
264 if (is_dir($file_path)) {
265 $status = delete_dir_contents($file_path);
266 //There is nothing, delete the directory itself
267 if ($status) {
268 $status = rmdir($file_path);
269 }
270 }
271 }
272 return $status;
273 }
274
efead3b9 275 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
276 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
277 //This functions are used to copy any file or directory ($from_file)
278 //to a new file or directory ($to_file). It works recursively and
279 //mantains file perms.
280 //I've copied it from: http://www.php.net/manual/en/function.copy.php
281 //Little modifications done
282
d27920b9 283 function backup_copy_file ($from_file,$to_file,$log_clam=false) {
f654deea 284
285 global $CFG;
286
efead3b9 287 if (is_file($from_file)) {
7ef0797d 288 //echo "<br />Copying ".$from_file." to ".$to_file; //Debug
f654deea 289 //$perms=fileperms($from_file);
290 //return copy($from_file,$to_file) && chmod($to_file,$perms);
291 umask(0000);
9704c866 292 if (copy($from_file,$to_file)) {
293 chmod($to_file,$CFG->directorypermissions);
d27920b9 294 if (!empty($log_clam)) {
295 clam_log_upload($to_file,null,true);
296 }
8930f900 297 return true;
298 }
299 return false;
efead3b9 300 }
301 else if (is_dir($from_file)) {
302 return backup_copy_dir($from_file,$to_file);
303 }
304 else{
7ef0797d 305 //echo "<br />Error: not file or dir ".$from_file; //Debug
efead3b9 306 return false;
307 }
cfb9c525 308 }
efead3b9 309
310 function backup_copy_dir($from_file,$to_file) {
93808667 311
312 global $CFG;
313
efead3b9 314 if (!is_dir($to_file)) {
7ef0797d 315 //echo "<br />Creating ".$to_file; //Debug
f654deea 316 umask(0000);
41923e75 317 $status = mkdir($to_file,$CFG->directorypermissions);
efead3b9 318 }
319 $dir = opendir($from_file);
320 while ($file=readdir($dir)) {
321 if ($file=="." || $file=="..") {
322 continue;
323 }
4f6ae69e 324 $status = backup_copy_file ("$from_file/$file","$to_file/$file");
efead3b9 325 }
4f6ae69e 326 closedir($dir);
327 return $status;
efead3b9 328 }
329 ///Ends copy file/dirs functions
330 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
331 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7641819d 332
10dcde40 333
334 function upgrade_backup_db($continueto) {
335 /// This function upgrades the backup tables, if necessary
336 /// It's called from admin/index.php, also backup.php and restore.php
7641819d 337
10dcde40 338 global $CFG, $db;
339
340 require_once ("$CFG->dirroot/backup/version.php"); // Get code versions
341
342 if (empty($CFG->backup_version)) { // Backup has never been installed.
343 $strdatabaseupgrades = get_string("databaseupgrades");
81d3268d 344 print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades,
345 "", "", false, "&nbsp;", "&nbsp;");
10dcde40 346
347 $db->debug=true;
348 if (modify_database("$CFG->dirroot/backup/db/$CFG->dbtype.sql")) {
349 $db->debug = false;
e9346b95 350 if (set_config("backup_version", $backup_version) and set_config("backup_release", $backup_release)) {
10dcde40 351 notify(get_string("databasesuccess"), "green");
0f3fe4b6 352 notify(get_string("databaseupgradebackups", "", $backup_version));
10dcde40 353 print_continue($continueto);
354 exit;
7641819d 355 } else {
10dcde40 356 error("Upgrade of backup system failed! (Could not update version in config table)");
7641819d 357 }
10dcde40 358 } else {
359 error("Backup tables could NOT be set up successfully!");
7641819d 360 }
10dcde40 361 }
362
363
364 if ($backup_version > $CFG->backup_version) { // Upgrade tables
7641819d 365 $strdatabaseupgrades = get_string("databaseupgrades");
366 print_header($strdatabaseupgrades, $strdatabaseupgrades, $strdatabaseupgrades);
10dcde40 367
368 require_once ("$CFG->dirroot/backup/db/$CFG->dbtype.php");
369
370 $db->debug=true;
371 if (backup_upgrade($CFG->backup_version)) {
372 $db->debug=false;
e9346b95 373 if (set_config("backup_version", $backup_version) and set_config("backup_release", $backup_release)) {
10dcde40 374 notify(get_string("databasesuccess"), "green");
0f3fe4b6 375 notify(get_string("databaseupgradebackups", "", $backup_version));
10dcde40 376 print_continue($continueto);
377 exit;
378 } else {
379 error("Upgrade of backup system failed! (Could not update version in config table)");
380 }
381 } else {
382 $db->debug=false;
383 error("Upgrade failed! See backup/version.php");
7641819d 384 }
10dcde40 385
386 } else if ($backup_version < $CFG->backup_version) {
387 notify("WARNING!!! The code you are using is OLDER than the version that made these databases!");
7641819d 388 }
389 }
10dcde40 390
7ba74615 391
392 //This function is used to insert records in the backup_ids table
af9cd955 393 //If the info field is greater than max_db_storage, then its info
394 //is saved to filesystem
7ba74615 395 function backup_putid ($backup_unique_code, $table, $old_id, $new_id, $info="") {
396
397 global $CFG;
af9cd955 398
399 $max_db_storage = 128; //Max bytes to save to db, else save to file
7ba74615 400
401 $status = true;
402
403 //First delete to avoid PK duplicates
404 $status = backup_delid($backup_unique_code, $table, $old_id);
405
af9cd955 406 //Now, serialize info
407 $info_ser = serialize($info);
408
409 //Now, if the size of $info_ser > $max_db_storage, save it to filesystem and
410 //insert a "infile" in the info field
411
412 if (strlen($info_ser) > $max_db_storage) {
413 //Calculate filename (in current_backup_dir, $backup_unique_code_$table_$old_id.info)
414 $filename = $CFG->dataroot."/temp/backup/".$backup_unique_code."/".$backup_unique_code."_".$table."_".$old_id.".info";
415 //Save data to file
416 $status = backup_data2file($filename,$info_ser);
417 //Set info_to save
418 $info_to_save = "infile";
419 } else {
420 //Saving to db, addslashes
421 $info_to_save = addslashes($info_ser);
422 }
423
424 //Now, insert the record
425 if ($status) {
d8e24b78 426 //Build the record
427 $rec->backup_code = $backup_unique_code;
428 $rec->table_name = $table;
429 $rec->old_id = $old_id;
430 $rec->new_id =$new_id;
431 $rec->info = $info_to_save;
432
29856bcb 433 $status = insert_record ("backup_ids", $rec, false,"backup_code");
af9cd955 434 }
7ba74615 435 return $status;
436 }
437
438 //This function is used to delete recods from the backup_ids table
af9cd955 439 //If the info field is "infile" then the file is deleted too
7ba74615 440 function backup_delid ($backup_unique_code, $table, $old_id) {
441
442 global $CFG;
443
444 $status = true;
445
446 $status = execute_sql("DELETE FROM {$CFG->prefix}backup_ids
447 WHERE backup_code = $backup_unique_code AND
448 table_name = '$table' AND
449 old_id = '$old_id'",false);
450 return $status;
451 }
a2c7397c 452
453 //This function is used to get a record from the backup_ids table
af9cd955 454 //If the info field is "infile" then its info
455 //is read from filesystem
a2c7397c 456 function backup_getid ($backup_unique_code, $table, $old_id) {
457
458 global $CFG;
459
460 $status = true;
af9cd955 461 $status2 = true;
a2c7397c 462
463 $status = get_record ("backup_ids","backup_code",$backup_unique_code,
464 "table_name",$table,
465 "old_id", $old_id);
466
af9cd955 467 //If info field = "infile", get file contents
468 if ($status->info == "infile") {
469 $filename = $CFG->dataroot."/temp/backup/".$backup_unique_code."/".$backup_unique_code."_".$table."_".$old_id.".info";
470 //Read data from file
471 $status2 = backup_file2data($filename,$info);
472 if ($status2) {
473 //unserialize data
474 $status->info = unserialize($info);
475 } else {
476 $status = false;
477 }
478 } else {
783ab2b0 479 //Only if status (record exists)
480 if ($status) {
481 ////First strip slashes
482 $temp = stripslashes($status->info);
483 //Now unserialize
484 $status->info = unserialize($temp);
485 }
af9cd955 486 }
487
a2c7397c 488 return $status;
489 }
6d18c5a2 490
491 //This function is used to add slashes and decode from UTF-8
492 //It's used intensivelly when restoring modules and saving them in db
493 function backup_todb ($data) {
01f50e06 494 return restore_decode_absolute_links(addslashes(utf8_decode($data)));
6d18c5a2 495 }
496
fe3c84ab 497 //This function is used to check that every necessary function to
498 //backup/restore exists in the current php installation. Thanks to
499 //gregb@crowncollege.edu by the idea.
500 function backup_required_functions() {
501
d2c94f4b 502 if(!function_exists('utf8_encode')) {
6a0e7baf 503 error('You need to add XML support to your PHP installation');
fe3c84ab 504 }
505
506 }
60b420af 507
508 //This function send n white characters to the browser and flush the
509 //output buffer. Used to avoid browser timeouts and to show the progress.
510 function backup_flush($n=0,$time=false) {
511 if ($time) {
512 $ti = strftime("%X",time());
513 } else {
514 $ti = "";
515 }
516 echo str_repeat(" ", $n) . $ti . "\n";
517 flush();
518 }
fe3c84ab 519
af9cd955 520 //This function creates the filename and write data to it
521 //returning status as result
522 function backup_data2file ($file,&$data) {
523
524 $status = true;
525 $status2 = true;
526
527 $f = fopen($file,"w");
528 $status = fwrite($f,$data);
529 $status2 = fclose($f);
530
531 return ($status && $status2);
532 }
fe3c84ab 533
af9cd955 534 //This function read the filename and read data from it
535 function backup_file2data ($file,&$data) {
536
537 $status = true;
538 $status2 = true;
539
540 $f = fopen($file,"r");
541 $data = fread ($f,filesize($file));
542 $status2 = fclose($f);
543
544 return ($status && $status2);
545 }
afbe3de8 546?>