More nav cleanups
[moodle.git] / backup / util / helper / backup_helper.class.php
CommitLineData
69dd0c8c
EL
1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * @package moodlecore
20 * @subpackage backup-helper
21 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25/**
26 * Base abstract class for all the helper classes providing various operations
27 *
28 * TODO: Finish phpdocs
29 */
30abstract class backup_helper {
31
32 /**
33 * Given one backupid, create all the needed dirs to have one backup temp dir available
34 */
35 static public function check_and_create_backup_dir($backupid) {
36 global $CFG;
37 if (!check_dir_exists($CFG->dataroot . '/temp/backup/' . $backupid, true, true)) {
38 throw new backup_helper_exception('cannot_create_backup_temp_dir');
39 }
40 }
41
42 /**
43 * Given one backupid, ensure its temp dir is completelly empty
44 */
45 static public function clear_backup_dir($backupid) {
46 global $CFG;
47 if (!self::delete_dir_contents($CFG->dataroot . '/temp/backup/' . $backupid)) {
48 throw new backup_helper_exception('cannot_empty_backup_temp_dir');
49 }
50 }
51
52 /**
53 * Given one fullpath to directory, delete its contents recursively
54 * Copied originally from somewhere in the net.
55 * TODO: Modernise this
56 */
57 static public function delete_dir_contents($dir, $excludeddir='') {
58 if (!is_dir($dir)) {
59 // if we've been given a directory that doesn't exist yet, return true.
60 // this happens when we're trying to clear out a course that has only just
61 // been created.
62 return true;
63 }
64 $slash = "/";
65
66 // Create arrays to store files and directories
67 $dir_files = array();
68 $dir_subdirs = array();
69
70 // Make sure we can delete it
71 chmod($dir, 0777);
72
73 if ((($handle = opendir($dir))) == false) {
74 // The directory could not be opened
75 return false;
76 }
77
78 // Loop through all directory entries, and construct two temporary arrays containing files and sub directories
79 while (false !== ($entry = readdir($handle))) {
80 if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != "." && $entry != $excludeddir) {
81 $dir_subdirs[] = $dir. $slash .$entry;
82
83 } else if ($entry != ".." && $entry != "." && $entry != $excludeddir) {
84 $dir_files[] = $dir. $slash .$entry;
85 }
86 }
87
88 // Delete all files in the curent directory return false and halt if a file cannot be removed
89 for ($i=0; $i<count($dir_files); $i++) {
90 chmod($dir_files[$i], 0777);
91 if (((unlink($dir_files[$i]))) == false) {
92 return false;
93 }
94 }
95
96 // Empty sub directories and then remove the directory
97 for ($i=0; $i<count($dir_subdirs); $i++) {
98 chmod($dir_subdirs[$i], 0777);
99 if (self::delete_dir_contents($dir_subdirs[$i]) == false) {
100 return false;
101 } else {
102 if (remove_dir($dir_subdirs[$i]) == false) {
103 return false;
104 }
105 }
106 }
107
108 // Close directory
109 closedir($handle);
110
111 // Success, every thing is gone return true
112 return true;
113 }
114
115 /**
116 * Delete all the temp dirs older than the time specified
117 */
118 static public function delete_old_backup_dirs($deletefrom) {
119 global $CFG;
120
121 $status = true;
122 // Get files and directories in the temp backup dir witout descend
123 $list = get_directory_list($CFG->dataroot . '/temp/backup', '', false, true, true);
124 foreach ($list as $file) {
125 $file_path = $CFG->dataroot . '/temp/backup/' . $file;
126 $moddate = filemtime($file_path);
127 if ($status && $moddate < $deletefrom) {
128 //If directory, recurse
129 if (is_dir($file_path)) {
130 $status = self::delete_dir_contents($file_path);
131 //There is nothing, delete the directory itself
132 if ($status) {
133 $status = rmdir($file_path);
134 }
135 //If file
136 } else {
137 unlink($file_path);
138 }
139 }
140 }
141 if (!$status) {
142 throw new backup_helper_exception('problem_deleting_old_backup_temp_dirs');
143 }
144 }
145
146 /**
147 * This function will be invoked by any log() method in backup/restore, acting
148 * as a simple forwarder to the standard loggers but also, if the $display
149 * parameter is true, supporting translation via get_string() and sending to
150 * standard output.
151 */
152 static public function log($message, $level, $a, $depth, $display, $logger) {
153 // Send to standard loggers
154 $logmessage = $message;
155 $options = empty($depth) ? array() : array('depth' => $depth);
156 if (!empty($a)) {
157 $logmessage = $logmessage . ' ' . implode(', ', (array)$a);
158 }
159 $logger->process($logmessage, $level, $options);
160
161 // If $display specified, send translated string to output_controller
162 if ($display) {
163 output_controller::get_instance()->output($message, 'backup', $a, $depth);
164 }
165 }
ce937f99
EL
166
167 /**
168 * Given one backupid and the (FS) final generated file, perform its final storage
169 * into Moodle file storage
170 */
171 static public function store_backup_file($backupid, $filepath) {
172
173 // First of all, get some information from the backup_controller to help us decide
174 list($dinfo, $cinfo, $sinfo) = backup_controller_dbops::get_moodle_backup_information($backupid);
175
176 // Extract useful information to decide
177 $hasusers = (bool)$sinfo['users']->value; // Backup has users
178 $isannon = (bool)$sinfo['anonymize']->value; // Backup is annonymzed
179 $backupmode= $dinfo[0]->mode; // Backup mode backup::MODE_GENERAL/IMPORT/HUB
cd0034d8 180 $backuptype= $dinfo[0]->type; // Backup type backup::TYPE_1ACTIVITY/SECTION/COURSE
ce937f99 181 $userid = $dinfo[0]->userid; // User->id executing the backup
cd0034d8
EL
182 $id = $dinfo[0]->id; // Id of activity/section/course (depends of type)
183 $courseid = $dinfo[0]->courseid; // Id of the course
ce937f99
EL
184
185 // Backups of type IMPORT aren't stored ever
186 if ($backupmode == backup::MODE_IMPORT) {
187 return true;
188 }
189
cd0034d8
EL
190 // Calculate file storage options of id being backup
191 $ctxid = 0;
192 $filearea = '';
193 $itemid = 0;
194 switch ($backuptype) {
195 case backup::TYPE_1ACTIVITY:
196 $ctxid = get_context_instance(CONTEXT_MODULE, $id)->id;
197 $filearea = 'activity_backup';
198 $itemid = 0;
199 break;
200 case backup::TYPE_1SECTION:
201 $ctxid = get_context_instance(CONTEXT_COURSE, $courseid)->id;
202 $filearea = 'section_backup';
203 $itemid = $id;
204 break;
205 case backup::TYPE_1COURSE:
206 $ctxid = get_context_instance(CONTEXT_COURSE, $courseid)->id;
207 $filearea = 'course_backup';
208 $itemid = 0;
209 break;
210 }
211
ce937f99
EL
212 // Backups of type HUB (by definition never have user info)
213 // are sent to user's "user_tohub" file area. The upload process
214 // will be responsible for cleaning that filearea once finished
215 if ($backupmode == backup::MODE_HUB) {
216 $ctxid = get_context_instance(CONTEXT_USER, $userid)->id;
cd0034d8
EL
217 $filearea = 'user_tohub';
218 $itemid = 0;
219 }
220
221 // Backups without user info are sent to user's "user_backup"
222 // file area. Maintenance of such area is responsibility of
223 // the user via corresponding file manager frontend
224 if ($backupmode == backup::MODE_GENERAL && !$hasusers) {
225 $ctxid = get_context_instance(CONTEXT_USER, $userid)->id;
226 $filearea = 'user_backup';
227 $itemid = 0;
228 }
229
230 // Let's send the file to file storage, everything already defined
231 $fs = get_file_storage();
232 $fr = array(
233 'contextid' => $ctxid,
234 'filearea' => $filearea,
235 'itemid' => $itemid,
236 'filepath' => '/',
237 'filename' => basename($filepath),
238 'userid' => $userid,
239 'timecreated' => time(),
240 'timemodified'=> time());
241 // If file already exists, delete if before
242 // creating it again. This is BC behaviour - copy()
243 // overwrites by default
244 if ($fs->file_exists($fr['contextid'], $fr['filearea'], $fr['itemid'], $fr['filepath'], $fr['filename'])) {
245 $pathnamehash = $fs->get_pathname_hash($fr['contextid'], $fr['filearea'], $fr['itemid'], $fr['filepath'], $fr['filename']);
246 $sf = $fs->get_file_by_hash($pathnamehash);
247 $sf->delete();
ce937f99 248 }
cd0034d8 249 return $fs->create_file_from_pathname($fr, $filepath);
ce937f99 250 }
69dd0c8c
EL
251}
252
253/*
254 * Exception class used by all the @helper stuff
255 */
256class backup_helper_exception extends backup_exception {
257
258 public function __construct($errorcode, $a=NULL, $debuginfo=null) {
259 parent::__construct($errorcode, $a, $debuginfo);
260 }
261}