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, " ", " "); |
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 | ?> |