backup_scheduled.php 34.1 KB
Newer Older
1
<?php //$Id$
stronk7's avatar
Wow !!  
stronk7 committed
2
3
    //This file contains all the code needed to execute scheduled backups

4
5
6
7
8
//This function is executed via moodle cron
//It prepares all the info and execute backups as necessary
function schedule_backup_cron() {

    global $CFG;
9

10
11
    $status = true;

12
13
    $emailpending = false;

14
15
    //Check for required functions...
    if(!function_exists('utf8_encode')) {
moodler's avatar
moodler committed
16
        mtrace("        ERROR: You need to add XML support to your PHP installation!");
17
18
19
        return true;
    }

20
21
22
23
24
    //Get now
    $now = time();

    //First of all, we have to see if the scheduled is active and detect
    //that there isn't another cron running
moodler's avatar
moodler committed
25
    mtrace("    Checking backup status",'...');
26
27
    $backup_config = backup_get_config();
    if(!isset($backup_config->backup_sche_active) || !$backup_config->backup_sche_active) {
moodler's avatar
moodler committed
28
        mtrace("INACTIVE");
29
30
        return true;
    } else if (isset($backup_config->backup_sche_running) && $backup_config->backup_sche_running) {
moodler's avatar
moodler committed
31
        mtrace("RUNNING");
32
        //Now check if it's a really running task or something very old looking
33
34
35
36
37
38
        //for info in backup_logs to unlock status as necessary
        $timetosee = 1800;   //Half an hour looking for activity
        $timeafter = time() - $timetosee;
        $numofrec = count_records_select ("backup_log","time > $timeafter");
        if (!$numofrec) {
            $timetoseemin = $timetosee/60;
moodler's avatar
moodler committed
39
            mtrace("    No activity in last ".$timetoseemin." minutes. Unlocking status");
40
        } else {
moodler's avatar
moodler committed
41
            mtrace("    Scheduled backup seems to be running. Execution delayed");
42
43
            return true;
        }
44
    } else {
moodler's avatar
moodler committed
45
        mtrace("OK");
46
47
48
49
50
        //Mark backup_sche_running
        backup_set_config("backup_sche_running","1");
    }

    //Now we get the main admin user (we'll use his timezone, mail...)
moodler's avatar
moodler committed
51
    mtrace("    Getting admin info");
52
53
54
55
56
    $admin = get_admin();
    if (!$admin) {
        $status = false;
    }

stronk7's avatar
stronk7 committed
57
58
59
60
61
62
    //Delete old_entries from backup tables
    if ($status) {
        mtrace("    Deleting old data");
        $status = backup_delete_old_data();
    }

63
64
    //Now we get a list of courses in the server
    if ($status) {
moodler's avatar
moodler committed
65
        mtrace("    Checking courses");
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
        //First of all, we delete everything from backup tables related to deleted courses
        mtrace("        Skipping deleted courses");
        $skipped = 0;
        if ($bckcourses = get_records('backup_courses')) {
            foreach($bckcourses as $bckcourse) {
                //Search if it exists
                if (!$exists = get_record('course', 'id', "$bckcourse->courseid")) {
                    //Doesn't exist, so delete from backup tables
                    delete_records('backup_courses', 'courseid', "$bckcourse->courseid");
                    delete_records('backup_log', 'courseid', "$bckcourse->courseid");
                    $skipped++;
                }
            }
        }
        mtrace("            $skipped courses");
        //Now process existing courses
82
83
84
85
86
        $courses = get_records("course");
        //For each course, we check (insert, update) the backup_course table
        //with needed data
        foreach ($courses as $course) {
            if ($status) {
moodler's avatar
moodler committed
87
                mtrace("        $course->fullname");
88
89
90
91
92
93
94
95
96
97
98
                //We check if the course exists in backup_course
                $backup_course = get_record("backup_courses","courseid",$course->id);
                //If it doesn't exist, create
                if (!$backup_course) {
                    $temp_backup_course->courseid = $course->id;
                    $newid = insert_record("backup_courses",$temp_backup_course);
                    //And get it from db
                    $backup_course = get_record("backup_courses","id",$newid);
                }
                //If it doesn't exist now, error
                if (!$backup_course) {
moodler's avatar
moodler committed
99
                    mtrace("            ERROR (in backup_courses detection)");
100
                    $status = false;
101
                    continue;
102
                }
103
104
105
106
107
108
                // Skip backup of unavailable courses that have remained unmodified in a month
                $skipped = false;
                if (!$course->visible && ($now - $course->timemodified) > 31*24*60*60) {  //Hidden + unmodified last month
                    mtrace("            SKIPPING - hidden+unmodified");
                    set_field("backup_courses","laststatus","3","courseid",$backup_course->courseid);
                    $skipped = true;
109
                }
110
111
                //Now we backup every non skipped course with nextstarttime < now
                if (!$skipped  && $backup_course->nextstarttime > 0 && $backup_course->nextstarttime < $now) {
112
113
                    //We have to send a email because we have included at least one backup
                    $emailpending = true;
stronk7's avatar
stronk7 committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
                    //Only make the backup if laststatus isn't 2-UNFINISHED (uncontrolled error)
                    if ($backup_course->laststatus != 2) {
                        //Set laststarttime
                        $starttime = time();
                        set_field("backup_courses","laststarttime",$starttime,"courseid",$backup_course->courseid);
                        //Set course status to unfinished, the process will reset it
                        set_field("backup_courses","laststatus","2","courseid",$backup_course->courseid);
                        //Launch backup
                        $course_status = schedule_backup_launch_backup($course,$starttime);
                        //Set lastendtime
                        set_field("backup_courses","lastendtime",time(),"courseid",$backup_course->courseid);
                        //Set laststatus
                        if ($course_status) {
                            set_field("backup_courses","laststatus","1","courseid",$backup_course->courseid);
                        } else {
                            set_field("backup_courses","laststatus","0","courseid",$backup_course->courseid);
                        }
131
132
133
134
135
136
                    }
                }

                //Now, calculate next execution of the course
                $nextstarttime = schedule_backup_next_execution ($backup_course,$backup_config,$now,$admin->timezone);
                //Save it to db
137
                set_field("backup_courses","nextstarttime",$nextstarttime,"courseid",$backup_course->courseid);
138
139
140
141
142
                //Print it to screen as necessary
                $showtime = "undefined";
                if ($nextstarttime > 0) {
                    $showtime = userdate($nextstarttime,"",$admin->timezone);
                }
moodler's avatar
moodler committed
143
                mtrace("            Next execution: $showtime");
144
145
146
147
148
149
            }
        }
    }

    //Delete old logs
    if (!empty($CFG->loglifetime)) {
moodler's avatar
moodler committed
150
        mtrace("    Deleting old logs");
151
152
153
154
        $loglifetime = $now - ($CFG->loglifetime * 86400);
        delete_records_select("backup_log", "laststarttime < '$loglifetime'");
    }

stronk7's avatar
stronk7 committed
155
    //Send email to admin if necessary
156
    if ($emailpending) {
moodler's avatar
moodler committed
157
        mtrace("    Sending email to admin");
158
        $message = "";
stronk7's avatar
stronk7 committed
159
160
161
162
163
164

        //Get info about the status of courses
        $count_all = count_records('backup_courses');
        $count_ok = count_records('backup_courses','laststatus','1');
        $count_error = count_records('backup_courses','laststatus','0');
        $count_unfinished = count_records('backup_courses','laststatus','2');
165
        $count_skipped = count_records('backup_courses','laststatus','3');
stronk7's avatar
stronk7 committed
166
167
168
169
170
171
172

        //Build the message text
        //Summary
        $message .= get_string('summary')."\n";
        $message .= "==================================================\n";
        $message .= "  ".get_string('courses').": ".$count_all."\n";
        $message .= "  ".get_string('ok').": ".$count_ok."\n";
173
        $message .= "  ".get_string('skipped').": ".$count_skipped."\n";
stronk7's avatar
stronk7 committed
174
175
176
177
178
179
        $message .= "  ".get_string('error').": ".$count_error."\n";
        $message .= "  ".get_string('unfinished').": ".$count_unfinished."\n\n";

        //Reference
        if ($count_error != 0 || $count_unfinished != 0) {
            $message .= "  ".get_string('backupfailed')."\n\n";
180
            $dest_url = "$CFG->wwwroot/$CFG->admin/report/backups/index.php";
stronk7's avatar
stronk7 committed
181
            $message .= "  ".get_string('backuptakealook','',$dest_url)."\n\n";
182
183
            //Set message priority
            $admin->priority = 1;
stronk7's avatar
stronk7 committed
184
185
186
187
            //Reset unfinished to error
            set_field('backup_courses','laststatus','0','laststatus','2');
        } else {
            $message .= "  ".get_string('backupfinished')."\n";
188
        }
stronk7's avatar
stronk7 committed
189
190

        //Build the message subject
191
        $site = get_site();
stronk7's avatar
stronk7 committed
192
193
194
        $prefix = $site->shortname.": ";
        if ($count_error != 0 || $count_unfinished != 0) {
            $prefix .= "[".strtoupper(get_string('error'))."] ";
195
        }
stronk7's avatar
stronk7 committed
196
197
198
199
        $subject = $prefix.get_string("scheduledbackupstatus");

        //Send the message
        email_to_user($admin,$admin,$subject,$message);
200
    }
201

202

203
204
205
206
207
208
209
210
    //Everything is finished stop backup_sche_running
    backup_set_config("backup_sche_running","0");

    return $status;
}

//This function executes the ENTIRE backup of a course (passed as parameter)
//using all the scheduled backup preferences
211
function schedule_backup_launch_backup($course,$starttime = 0) {
212
213
214
215

    $preferences = false;
    $status = false;

moodler's avatar
moodler committed
216
    mtrace("            Executing backup");
217
218
219
    schedule_backup_log($starttime,$course->id,"Start backup course $course->fullname");
    schedule_backup_log($starttime,$course->id,"  Phase 1: Checking and counting:");
    $preferences = schedule_backup_course_configure($course,$starttime);
220

221
    if ($preferences) {
222
223
        schedule_backup_log($starttime,$course->id,"  Phase 2: Executing and copying:");
        $status = schedule_backup_course_execute($preferences,$starttime);
224
    }
stronk7's avatar
stronk7 committed
225

226
227
228
229
230
231
232
    if ($status && $preferences) {
        //Only if the backup_sche_keep is set
        if ($preferences->backup_keep) {
            schedule_backup_log($starttime,$course->id,"  Phase 3: Deleting old backup files:");
            $status = schedule_backup_course_delete_old_files($preferences,$starttime);
        }
    }
stronk7's avatar
stronk7 committed
233

234
    if ($status && $preferences) {
moodler's avatar
moodler committed
235
        mtrace("            End backup OK");
236
        schedule_backup_log($starttime,$course->id,"End backup course $course->fullname - OK");
237
    } else {
moodler's avatar
moodler committed
238
        mtrace("            End backup with ERROR");
239
        schedule_backup_log($starttime,$course->id,"End backup course $course->fullname - ERROR!!");
240
241
242
243
244
    }

    return $status && $preferences;
}

245
246
247
248
249
250
251
252
//This function saves to backup_log all the needed process info
//to use it later.  NOTE: If $starttime = 0 no info in saved
function schedule_backup_log($starttime,$courseid,$message) {

    if ($starttime) {
        $log->courseid = $courseid;
        $log->time = time();
        $log->laststarttime = $starttime;
253
        $log->info = addslashes($message);
254

255
256
257
258
259
        insert_record ("backup_log",$log);
    }

}

260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
//This function returns the next future GMT time to execute the course based in the
//configuration of the scheduled backups
function schedule_backup_next_execution ($backup_course,$backup_config,$now,$timezone) {

    $result = -1;

    //Get today's midnight GMT
    $midnight = usergetmidnight($now,$timezone);

    //Get today's day of week (0=Sunday...6=Saturday)
    $date = usergetdate($now,$timezone);
    $dayofweek = $date['wday'];

    //Get number of days (from today) to execute backups
    $scheduled_days = substr($backup_config->backup_sche_weekdays,$dayofweek).
                      $backup_config->backup_sche_weekdays;
    $daysfromtoday = strpos($scheduled_days, "1");

    //If some day has been found
    if ($daysfromtoday !== false) {
        //Calculate distance
        $dist = ($daysfromtoday * 86400) +                     //Days distance
                ($backup_config->backup_sche_hour*3600) +      //Hours distance
                ($backup_config->backup_sche_minute*60);       //Minutes distance
        $result = $midnight + $dist;
285
    }
286
287
288
289
290
291
292

    //If that time is past, call the function recursively to obtain the next valid day
    if ($result > 0 && $result < time()) {
        $result = schedule_backup_next_execution ($backup_course,$backup_config,$now + 86400,$timezone);
    }

    return $result;
293
294
295
296
}



stronk7's avatar
Wow !!  
stronk7 committed
297
298
//This function implements all the needed code to prepare a course
//to be in backup (insert temp info into backup temp tables).
299
function schedule_backup_course_configure($course,$starttime = 0) {
stronk7's avatar
Wow !!  
stronk7 committed
300
301

    global $CFG;
302

stronk7's avatar
Wow !!  
stronk7 committed
303
304
    $status = true;

305
306
    schedule_backup_log($starttime,$course->id,"    checking parameters");

stronk7's avatar
Wow !!  
stronk7 committed
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
    //Check the required variable
    if (empty($course->id)) {
        $status = false;
    }
    //Get scheduled backup preferences
    $backup_config =  backup_get_config();

    //Checks backup_config pairs exist
    if ($status) {
        if (!isset($backup_config->backup_sche_modules)) {
            $backup_config->backup_sche_modules = 1;
        }
        if (!isset($backup_config->backup_sche_withuserdata)) {
            $backup_config->backup_sche_withuserdata = 1;
        }
322
323
324
        if (!isset($backup_config->backup_sche_metacourse)) {
            $backup_config->backup_sche_metacourse = 1;
        }
stronk7's avatar
Wow !!  
stronk7 committed
325
326
327
328
329
330
331
332
333
334
335
336
        if (!isset($backup_config->backup_sche_users)) {
            $backup_config->backup_sche_users = 1;
        }
        if (!isset($backup_config->backup_sche_logs)) {
            $backup_config->backup_sche_logs = 0;
        }
        if (!isset($backup_config->backup_sche_userfiles)) {
            $backup_config->backup_sche_userfiles = 1;
        }
        if (!isset($backup_config->backup_sche_coursefiles)) {
            $backup_config->backup_sche_coursefiles = 1;
        }
337
338
339
        if (!isset($backup_config->backup_sche_sitefiles)) {
            $backup_config->backup_sche_sitefiles = 1;
        }
340
        if (!isset($backup_config->backup_sche_messages)) {
341
            $backup_config->backup_sche_messages = 0;
342
        }
343
344
345
        if (!isset($backup_config->backup_sche_blogs)) {
            $backup_config->backup_sche_blogs = 0;
        }
stronk7's avatar
Wow !!  
stronk7 committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
        if (!isset($backup_config->backup_sche_active)) {
            $backup_config->backup_sche_active = 0;
        }
        if (!isset($backup_config->backup_sche_weekdays)) {
            $backup_config->backup_sche_weekdays = "0000000";
        }
        if (!isset($backup_config->backup_sche_hour)) {
            $backup_config->backup_sche_hour = 00;
        }
        if (!isset($backup_config->backup_sche_minute)) {
            $backup_config->backup_sche_minute = 00;
        }
        if (!isset($backup_config->backup_sche_destination)) {
            $backup_config->backup_sche_destination = "";
        }
361
        if (!isset($backup_config->backup_sche_keep)) {
362
            $backup_config->backup_sche_keep = 1;
363
        }
stronk7's avatar
Wow !!  
stronk7 committed
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    }

    if ($status) {
       //Checks for the required files/functions to backup every mod
        //And check if there is data about it
        $count = 0;
        if ($allmods = get_records("modules") ) {
            foreach ($allmods as $mod) {
                $modname = $mod->name;
                $modfile = "$CFG->dirroot/mod/$modname/backuplib.php";
                $modbackup = $modname."_backup_mods";
                $modcheckbackup = $modname."_check_backup_mods";
                if (file_exists($modfile)) {
                   include_once($modfile);
                   if (function_exists($modbackup) and function_exists($modcheckbackup)) {
                       $var = "exists_".$modname;
                       $$var = true;
                       $count++;
382
383

                       // PENNY NOTES: I have moved from here to the closing brace inside
mjollnir_'s avatar
mjollnir_ committed
384
385
386
387
388
389
390
391
392
393
394
395
                       // by two sets of ifs()
                       // to avoid the backup failing on a non existant backup.
                       // If the file/function/whatever doesn't exist, we don't want to set this
                       // this module in backup preferences at all.
                       //Check data
                       //Check module info
                       $var = "backup_".$modname;
                       if (!isset($$var)) {
                           $$var = $backup_config->backup_sche_modules;
                       }
                       //Now stores all the mods preferences into an array into preferences
                       $preferences->mods[$modname]->backup = $$var;
396

mjollnir_'s avatar
mjollnir_ committed
397
398
399
400
401
402
403
404
405
                       //Check include user info
                       $var = "backup_user_info_".$modname;
                       if (!isset($$var)) {
                           $$var = $backup_config->backup_sche_withuserdata;
                       }
                       //Now stores all the mods preferences into an array into preferences
                       $preferences->mods[$modname]->userinfo = $$var;
                       //And the name of the mod
                       $preferences->mods[$modname]->name = $modname;
stronk7's avatar
Wow !!  
stronk7 committed
406
407
408
409
                   }
                }
            }
        }
410

411
412
413
414
415
416
417
        // now set instances
        if ($coursemods = get_course_mods($course->id)) {
            foreach ($coursemods as $mod) {
                if (array_key_exists($mod->modname,$preferences->mods)) { // we are to backup this module
                    if (empty($preferences->mods[$mod->modname]->instances)) {
                        $preferences->mods[$mod->modname]->instances = array(); // avoid warnings
                    }
418
419
                    $preferences->mods[$mod->modname]->instances[$mod->instance]->backup = $preferences->mods[$mod->modname]->backup;
                    $preferences->mods[$mod->modname]->instances[$mod->instance]->userinfo = $preferences->mods[$mod->modname]->userinfo;
420
421
422
423
424
                    // there isn't really a nice way to do this...
                    $preferences->mods[$mod->modname]->instances[$mod->instance]->name = get_field($mod->modname,'name','id',$mod->instance);
                }
            }
        }
425
426
427
428
429
430
431

        // finally, clean all the $preferences->mods[] not having instances. Nothing to backup about them
        foreach ($preferences->mods as $modname => $mod) {
            if (!isset($mod->instances)) {
                unset($preferences->mods[$modname]);
            }
        }
stronk7's avatar
Wow !!  
stronk7 committed
432
    }
433

stronk7's avatar
Wow !!  
stronk7 committed
434
435
    //Convert other parameters
    if ($status) {
436
        $preferences->backup_metacourse = $backup_config->backup_sche_metacourse;
stronk7's avatar
Wow !!  
stronk7 committed
437
438
439
440
        $preferences->backup_users = $backup_config->backup_sche_users;
        $preferences->backup_logs = $backup_config->backup_sche_logs;
        $preferences->backup_user_files = $backup_config->backup_sche_userfiles;
        $preferences->backup_course_files = $backup_config->backup_sche_coursefiles;
441
        $preferences->backup_site_files = $backup_config->backup_sche_sitefiles;
442
        $preferences->backup_messages = $backup_config->backup_sche_messages;
443
        $preferences->backup_blogs = $backup_config->backup_sche_blogs;
stronk7's avatar
Wow !!  
stronk7 committed
444
445
        $preferences->backup_course = $course->id;
        $preferences->backup_destination = $backup_config->backup_sche_destination;
446
        $preferences->backup_keep = $backup_config->backup_sche_keep;
stronk7's avatar
Wow !!  
stronk7 committed
447
    }
448

449
    //Calculate various backup preferences
stronk7's avatar
Wow !!  
stronk7 committed
450
    if ($status) {
451
        schedule_backup_log($starttime,$course->id,"    calculating backup name");
452

453
454
        //Calculate the backup file name
        $backup_name = backup_get_zipfile_name($course);
455
456

        //Calculate the string to match the keep preference
457
        $keep_name = backup_get_keep_name($course);
458

459
        //Set them
stronk7's avatar
Wow !!  
stronk7 committed
460
        $preferences->backup_name = $backup_name;
461
        $preferences->keep_name = $keep_name;
462
463
464
465
466
467
468
469
470

        //Roleasignments
        $roles = get_records('role', '', '', 'sortorder');
        foreach ($roles as $role) {
            $preferences->backuproleassignments[$role->id] = $role;
        }

        //Another Info
        backup_add_static_preferences($preferences);
stronk7's avatar
Wow !!  
stronk7 committed
471
472
473
474
475
476
477
478
479
480
481
    }

    //Calculate the backup unique code to allow simultaneus backups (to define
    //the temp-directory name and records in backup temp tables
    if ($status) {
        $backup_unique_code = time();
        $preferences->backup_unique_code = $backup_unique_code;
    }

    //Calculate necesary info to backup modules
    if ($status) {
482
        schedule_backup_log($starttime,$course->id,"    calculating modules data");
stronk7's avatar
Wow !!  
stronk7 committed
483
484
485
486
487
488
489
490
491
492
493
494
495
496
        if ($allmods = get_records("modules") ) {
            foreach ($allmods as $mod) {
                $modname = $mod->name;
                $modbackup = $modname."_backup_mods";
                //If exists the lib & function
                $var = "exists_".$modname;
                if (isset($$var) && $$var) {
                    //Add hidden fields
                    $var = "backup_".$modname;
                    //Only if selected
                    if ($$var == 1) {
                        $var = "backup_user_info_".$modname;
                        //Call the check function to show more info
                        $modcheckbackup = $modname."_check_backup_mods";
497
                        schedule_backup_log($starttime,$course->id,"      $modname");
stronk7's avatar
Wow !!  
stronk7 committed
498
499
500
501
502
503
504
505
506
                        $modcheckbackup($course->id,$$var,$backup_unique_code);
                    }
                }
            }
        }
    }

    //Now calculate the users
    if ($status) {
507
        schedule_backup_log($starttime,$course->id,"    calculating users");
508
509
510
511
512
513
        //Decide about include users with messages, based on SITEID
        if ($preferences->backup_messages && $preferences->backup_course == SITEID) {
            $include_message_users = true;
        } else {
            $include_message_users = false;
        }
514
515
516
517
518
519
520
        //Decide about include users with blogs, based on SITEID
        if ($preferences->backup_blogs && $preferences->backup_course == SITEID) {
            $include_blog_users = true;
        } else {
            $include_blog_users = false;
        }
        user_check_backup($course->id,$backup_unique_code,$preferences->backup_users,$include_message_users, $include_blog_users);
stronk7's avatar
Wow !!  
stronk7 committed
521
522
523
524
525
    }

    //Now calculate the logs
    if ($status) {
        if ($preferences->backup_logs) {
526
            schedule_backup_log($starttime,$course->id,"    calculating logs");
stronk7's avatar
Wow !!  
stronk7 committed
527
528
529
530
531
532
533
            log_check_backup($course->id);
        }
    }

    //Now calculate the userfiles
    if ($status) {
        if ($preferences->backup_user_files) {
534
            schedule_backup_log($starttime,$course->id,"    calculating user files");
stronk7's avatar
Wow !!  
stronk7 committed
535
536
537
            user_files_check_backup($course->id,$preferences->backup_unique_code);
        }
    }
538

stronk7's avatar
Wow !!  
stronk7 committed
539
540
541
    //Now calculate the coursefiles
    if ($status) {
       if ($preferences->backup_course_files) {
542
            schedule_backup_log($starttime,$course->id,"    calculating course files");
stronk7's avatar
Wow !!  
stronk7 committed
543
544
545
546
            course_files_check_backup($course->id,$preferences->backup_unique_code);
        }
    }

547
548
549
550
551
552
553
554
    //Now calculate the sitefiles
    if ($status) {
       if ($preferences->backup_site_files) {
            schedule_backup_log($starttime,$course->id,"    calculating site files");
            site_files_check_backup($course->id,$preferences->backup_unique_code);
        }
    }

stronk7's avatar
Wow !!  
stronk7 committed
555
556
557
558
559
560
561
562
    //If everything is ok, return calculated preferences
    if ($status) {
        $status = $preferences;
    }

    return $status;
}

563
564
//TODO: Unify this function with backup_execute() to have both backups 100% equivalent. Moodle 2.0

stronk7's avatar
Wow !!  
stronk7 committed
565
566
//This function implements all the needed code to backup a course
//copying it to the desired destination (default if not specified)
567
function schedule_backup_course_execute($preferences,$starttime = 0) {
stronk7's avatar
Wow !!  
stronk7 committed
568
569
570
571
572

    global $CFG;

    $status = true;

573
574
575
576
577
578
579
    //Some parts of the backup doesn't know about $preferences, so we
    //put a copy of it inside that CFG (always global) to be able to
    //use it. Then, when needed I search for preferences inside CFG
    //Used to avoid some problems in full_tag() when preferences isn't
    //set globally (i.e. in scheduled backups)
    $CFG->backup_preferences = $preferences;

stronk7's avatar
Wow !!  
stronk7 committed
580
581
    //Check for temp and backup and backup_unique_code directory
    //Create them as needed
582
    schedule_backup_log($starttime,$preferences->backup_course,"    checking temp structures");
stronk7's avatar
Wow !!  
stronk7 committed
583
    $status = check_and_create_backup_dir($preferences->backup_unique_code);
584
    //Empty backup dir
stronk7's avatar
Wow !!  
stronk7 committed
585
    if ($status) {
586
        schedule_backup_log($starttime,$preferences->backup_course,"    cleaning current dir");
stronk7's avatar
Wow !!  
stronk7 committed
587
588
589
590
591
        $status = clear_backup_dir($preferences->backup_unique_code);
    }

    //Create the moodle.xml file
    if ($status) {
592
        schedule_backup_log($starttime,$preferences->backup_course,"    creating backup file");
stronk7's avatar
Wow !!  
stronk7 committed
593
594
595
596
        //Obtain the xml file (create and open) and print prolog information
        $backup_file = backup_open_xml($preferences->backup_unique_code);
        //Prints general info about backup to file
        if ($backup_file) {
597
            schedule_backup_log($starttime,$preferences->backup_course,"      general info");
stronk7's avatar
Wow !!  
stronk7 committed
598
599
600
601
602
603
604
605
606
607
            $status = backup_general_info($backup_file,$preferences);
        } else {
            $status = false;
        }

        //Prints course start (tag and general info)
        if ($status) {
            $status = backup_course_start($backup_file,$preferences);
        }

608
609
610
611
612
613
        //Metacourse information
        if ($status && $preferences->backup_metacourse) {
            schedule_backup_log($starttime,$preferences->backup_course,"      metacourse info");
            $status = backup_course_metacourse($backup_file,$preferences);
        }

614
615
616
617
618
619
        //Block info
        if ($status) {
            schedule_backup_log($starttime,$preferences->backup_course,"      blocks info");
            $status = backup_course_blocks($backup_file,$preferences);
        }

stronk7's avatar
Wow !!  
stronk7 committed
620
621
        //Section info
        if ($status) {
622
            schedule_backup_log($starttime,$preferences->backup_course,"      sections info");
stronk7's avatar
Wow !!  
stronk7 committed
623
624
625
626
627
            $status = backup_course_sections($backup_file,$preferences);
        }

        //User info
        if ($status) {
628
            schedule_backup_log($starttime,$preferences->backup_course,"      user info");
stronk7's avatar
Wow !!  
stronk7 committed
629
630
631
            $status = backup_user_info($backup_file,$preferences);
        }

632
633
634
635
        //If we have selected to backup messages and we are
        //doing a SITE backup, let's do it
        if ($status && $preferences->backup_messages && $preferences->backup_course == SITEID) {
            schedule_backup_log($starttime,$preferences->backup_course,"      messages");
636
637
638
639
640
641
642
643
            $status = backup_messages($backup_file,$preferences);
        }

        //If we have selected to backup blogs and we are
        //doing a SITE backup, let's do it
        if ($status && $preferences->backup_blogs && $preferences->backup_course == SITEID) {
            schedule_backup_log($starttime,$preferences->backup_course,"      blogs");
            $status = backup_blogs($backup_file,$preferences);
644
645
        }

stronk7's avatar
Wow !!  
stronk7 committed
646
647
648
        //If we have selected to backup quizzes, backup categories and
        //questions structure (step 1). See notes on mod/quiz/backuplib.php
        if ($status and $preferences->mods['quiz']->backup) {
649
            schedule_backup_log($starttime,$preferences->backup_course,"      categories & questions");
650
            $status = backup_question_categories($backup_file,$preferences);
stronk7's avatar
Wow !!  
stronk7 committed
651
        }
652

stronk7's avatar
Wow !!  
stronk7 committed
653
654
        //Print logs if selected
        if ($status) {
655
            if ($preferences->backup_logs) {
656
                schedule_backup_log($starttime,$preferences->backup_course,"      logs");
stronk7's avatar
Wow !!  
stronk7 committed
657
658
659
660
661
662
                $status = backup_log_info($backup_file,$preferences);
            }
        }

        //Print scales info
        if ($status) {
663
            schedule_backup_log($starttime,$preferences->backup_course,"      scales");
stronk7's avatar
Wow !!  
stronk7 committed
664
665
            $status = backup_scales_info($backup_file,$preferences);
        }
666

667
668
669
670
671
672
        //Print groups info
        if ($status) {
            schedule_backup_log($starttime,$preferences->backup_course,"      groups");
            $status = backup_groups_info($backup_file,$preferences);
        }

673
674
675
676
677
678
679
680
681
682
683
684
        //Print groupings info
        if ($status) {
            schedule_backup_log($starttime,$preferences->backup_course,"      groupings");
            $status = backup_groupings_info($backup_file,$preferences);
        }

        //Print groupings_groups info
        if ($status) {
            schedule_backup_log($starttime,$preferences->backup_course,"      groupings_groups");
            $status = backup_groupings_groups_info($backup_file,$preferences);
        }

stronk7's avatar
stronk7 committed
685
686
687
688
689
690
        //Print events info
        if ($status) {
            schedule_backup_log($starttime,$preferences->backup_course,"      events");
            $status = backup_events_info($backup_file,$preferences);
        }

691
692
693
694
695
696
        //Print gradebook info
        if ($status) {
            schedule_backup_log($starttime,$preferences->backup_course,"      gradebook");
            $status = backup_gradebook_info($backup_file,$preferences);
        }

stronk7's avatar
Wow !!  
stronk7 committed
697
698
699
700
701
702
        //Module info, this unique function makes all the work!!
        //db export and module fileis copy
        if ($status) {
            $mods_to_backup = false;
            //Check if we have any mod to backup
            foreach ($preferences->mods as $module) {
703
                if ($module->backup) {
stronk7's avatar
Wow !!  
stronk7 committed
704
                    $mods_to_backup = true;
705
                }
stronk7's avatar
Wow !!  
stronk7 committed
706
707
708
            }
            //If we have to backup some module
            if ($mods_to_backup) {
709
                schedule_backup_log($starttime,$preferences->backup_course,"      modules");
stronk7's avatar
Wow !!  
stronk7 committed
710
711
712
713
714
                //Start modules tag
                $status = backup_modules_start ($backup_file,$preferences);
                //Iterate over modules and call backup
                foreach ($preferences->mods as $module) {
                    if ($module->backup and $status) {
715
                        schedule_backup_log($starttime,$preferences->backup_course,"        $module->name");
stronk7's avatar
Wow !!  
stronk7 committed
716
717
718
719
720
721
722
723
                        $status = backup_module($backup_file,$preferences,$module->name);
                    }
                }
                //Close modules tag
                $status = backup_modules_end ($backup_file,$preferences);
            }
        }

724
725
726
727
728
729
        //Backup course format data, if any.
        if ($status) {
            schedule_backup_log($starttime,$preferences->backup_course,"      course format data");
            $status = backup_format_data($backup_file,$preferences);
        }

730
        //Prints course end
stronk7's avatar
Wow !!  
stronk7 committed
731
732
733
734
735
736
737
738
739
        if ($status) {
            $status = backup_course_end($backup_file,$preferences);
        }

        //Close the xml file and xml data
        if ($backup_file) {
            backup_close_xml($backup_file);
        }
    }
740

stronk7's avatar
Wow !!  
stronk7 committed
741
742
743
    //Now, if selected, copy user files
    if ($status) {
        if ($preferences->backup_user_files) {
744
            schedule_backup_log($starttime,$preferences->backup_course,"    copying user files");
stronk7's avatar
Wow !!  
stronk7 committed
745
746
747
748
749
750
751
            $status = backup_copy_user_files ($preferences);
        }
    }

    //Now, if selected, copy course files
    if ($status) {
        if ($preferences->backup_course_files) {
752
            schedule_backup_log($starttime,$preferences->backup_course,"    copying course files");
stronk7's avatar
Wow !!  
stronk7 committed
753
754
755
756
            $status = backup_copy_course_files ($preferences);
        }
    }

757
758
759
760
761
762
763
764
    //Now, if selected, copy site files
    if ($status) {
        if ($preferences->backup_site_files) {
            schedule_backup_log($starttime,$preferences->backup_course,"    copying site files");
            $status = backup_copy_site_files ($preferences);
        }
    }

stronk7's avatar
Wow !!  
stronk7 committed
765
766
    //Now, zip all the backup directory contents
    if ($status) {
767
        schedule_backup_log($starttime,$preferences->backup_course,"    zipping files");
stronk7's avatar
Wow !!  
stronk7 committed
768
769
770
771
772
        $status = backup_zip ($preferences);
    }

    //Now, copy the zip file to course directory
    if ($status) {
773
        schedule_backup_log($starttime,$preferences->backup_course,"    copying backup");
stronk7's avatar
Wow !!  
stronk7 committed
774
775
776
777
778
        $status = copy_zip_to_course_dir ($preferences);
    }

    //Now, clean temporary data (db and filesystem)
    if ($status) {
779
        schedule_backup_log($starttime,$preferences->backup_course,"    cleaning temp data");
stronk7's avatar
Wow !!  
stronk7 committed
780
781
782
        $status = clean_temp_data ($preferences);
    }

783
784
785
    //Unset CFG->backup_preferences only needed in scheduled backups
    unset ($CFG->backup_preferences);

stronk7's avatar
Wow !!  
stronk7 committed
786
787
788
    return $status;
}

789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
//This function deletes old backup files when the "keep" limit has been reached
//in the destination directory.
function schedule_backup_course_delete_old_files($preferences,$starttime=0) {

    global $CFG;

    $status = true;

    //Calculate the directory to check
    $dirtocheck = "";
    //if $preferences->backup_destination isn't empty, then check that directory
    if (!empty($preferences->backup_destination)) {
        $dirtocheck = $preferences->backup_destination;
    //else calculate standard backup directory location
    } else {
        $dirtocheck = $CFG->dataroot."/".$preferences->backup_course."/backupdata";
    }
    schedule_backup_log($starttime,$preferences->backup_course,"    checking $dirtocheck");
807
808
809
    if ($CFG->debug > 7) {
        mtrace("            Keeping backup files in $dirtocheck");
    }
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827

    //Get all the files in $dirtocheck
    $files = get_directory_list($dirtocheck,"",false);
    //Get all matching files ($preferences->keep_name) from $files
    $matchingfiles = array();
    foreach ($files as $file) {
        if (substr($file, 0, strlen($preferences->keep_name)) == $preferences->keep_name) {
            $modifieddate = filemtime($dirtocheck."/".$file);
            $matchingfiles[$modifieddate] = $file;
        }
    }
    //Sort by key (modified date) to get the oldest first (instead of doing that by name
    //because it could give us problems in some languages with different format names).
    ksort($matchingfiles);

    //Count matching files
    $countmatching = count($matchingfiles);
    schedule_backup_log($starttime,$preferences->backup_course,"        found $countmatching backup files");
moodler's avatar
moodler committed
828
    mtrace("                found $countmatching backup files");
829
830
    if ($preferences->backup_keep < $countmatching) {
        schedule_backup_log($starttime,$preferences->backup_course,"        keep limit ($preferences->backup_keep) reached. Deleting old files");
moodler's avatar
moodler committed
831
        mtrace("                keep limit ($preferences->backup_keep) reached. Deleting old files");
832
833
834
835
836
        $filestodelete = $countmatching - $preferences->backup_keep;
        $filesdeleted = 0;
        foreach ($matchingfiles as $matchfile) {
            if ($filesdeleted < $filestodelete) {
                schedule_backup_log($starttime,$preferences->backup_course,"        $matchfile deleted");
moodler's avatar
moodler committed
837
                mtrace("                $matchfile deleted");
838
839
840
841
842
843
844
845
846
                $filetodelete = $dirtocheck."/".$matchfile;
                unlink($filetodelete);
                $filesdeleted++;
            }
        }
    }
    return $status;
}

stronk7's avatar
Wow !!  
stronk7 committed
847
?>