Completed
Push — master ( 395485...bbad3a )
by Julito
43:12
created

CourseArchiver::createBackup()   F

Complexity

Conditions 29
Paths 2048

Size

Total Lines 114
Code Lines 64

Duplication

Lines 40
Ratio 35.09 %

Importance

Changes 0
Metric Value
cc 29
eloc 64
nc 2048
nop 1
dl 40
loc 114
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
namespace Chamilo\CourseBundle\Component\CourseCopy;
5
6
use Chamilo\CourseBundle\Component\CourseCopy\Resources\Asset;
7
use Symfony\Component\Filesystem\Filesystem;
8
9
/**
10
 * Some functions to write a course-object to a zip-file and to read a course-
11
 * object from such a zip-file.
12
 * @author Bart Mollet <[email protected]>
13
 * @package chamilo.backup
14
 *
15
 * @todo Use archive-folder of Chamilo?
16
 */
17
class CourseArchiver
18
{
19
    /**
20
     * @return string
21
     */
22
    public static function getBackupDir()
23
    {
24
        return api_get_path(SYS_ARCHIVE_PATH).'course_backups/';
25
    }
26
27
    /**
28
     * @return string
29
     */
30
    public static function createBackupDir()
31
    {
32
        $perms = api_get_permissions_for_new_directories();
33
        $dir = self::getBackupDir();
34
        $fs = new Filesystem();
35
        $fs->mkdir($dir, $perms);
36
37
        return $dir;
38
    }
39
40
    /**
41
     * Delete old temp-dirs
42
     */
43
    public static function cleanBackupDir()
44
    {
45
        $dir = self::getBackupDir();
46
        if (is_dir($dir)) {
47
            if ($handle = @ opendir($dir)) {
48
                while (($file = readdir($handle)) !== false) {
49
                    if ($file != "." && $file != ".." &&
50
                        strpos($file, 'CourseArchiver_') === 0 &&
51
                        is_dir($dir.'/'.$file)
52
                    ) {
53
                        rmdirr($dir.'/'.$file);
54
                    }
55
                }
56
                closedir($handle);
57
            }
58
        }
59
    }
60
61
    /**
62
     * Write a course and all its resources to a zip-file.
63
     * @return string A pointer to the zip-file
64
     */
65
    public static function createBackup($course)
66
    {
67
        CourseArchiver::cleanBackupDir();
68
        CourseArchiver::createBackupDir();
69
70
        $perm_dirs = api_get_permissions_for_new_directories();
71
        $backupDirectory = self::getBackupDir();
72
73
        // Create a temp directory
74
        $backup_dir = $backupDirectory . 'CourseArchiver_' . api_get_unique_id() . '/';
75
76
        // All course-information will be stored in course_info.dat
77
        $course_info_file = $backup_dir . 'course_info.dat';
78
79
        $user = api_get_user_info();
80
        $date = new \DateTime(api_get_local_time());
81
        $zipFileName = $user['user_id'] . '_' . $course->code . '_' . $date->format('Ymd-His') . '.zip';
82
        $zipFilePath = $backupDirectory. $zipFileName;
83
84
        $php_errormsg = '';
85
        $res = @mkdir($backup_dir, $perm_dirs);
86 View Code Duplication
        if ($res === false) {
87
            //TODO set and handle an error message telling the user to review the permissions on the archive directory
88
            error_log(__FILE__ . ' line ' . __LINE__ . ': ' . (ini_get('track_errors') != false ? $php_errormsg : 'error not recorded because track_errors is off in your php.ini') . ' - This error, occuring because your archive directory will not let this script write data into it, will prevent courses backups to be created', 0);
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing ini_get('track_errors') of type string to the boolean false. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
89
        }
90
        // Write the course-object to the file
91
        $fp = @fopen($course_info_file, 'w');
92 View Code Duplication
        if ($fp === false) {
93
            error_log(__FILE__ . ' line ' . __LINE__ . ': ' . (ini_get('track_errors') != false ? $php_errormsg : 'error not recorded because track_errors is off in your php.ini'), 0);
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing ini_get('track_errors') of type string to the boolean false. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
94
        }
95
96
        $res = @fwrite($fp, base64_encode(serialize($course)));
97 View Code Duplication
        if ($res === false) {
98
            error_log(__FILE__ . ' line ' . __LINE__ . ': ' . (ini_get('track_errors') != false ? $php_errormsg : 'error not recorded because track_errors is off in your php.ini'), 0);
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing ini_get('track_errors') of type string to the boolean false. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
99
        }
100
101
        $res = @fclose($fp);
102 View Code Duplication
        if ($res === false) {
103
            error_log(__FILE__ . ' line ' . __LINE__ . ': ' . (ini_get('track_errors') != false ? $php_errormsg : 'error not recorded because track_errors is off in your php.ini'), 0);
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing ini_get('track_errors') of type string to the boolean false. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
104
        }
105
106
        // Copy all documents to the temp-dir
107
        if (isset($course->resources[RESOURCE_DOCUMENT]) && is_array($course->resources[RESOURCE_DOCUMENT])) {
108
            foreach ($course->resources[RESOURCE_DOCUMENT] as $document) {
109
                if ($document->file_type == DOCUMENT) {
110
                    $doc_dir = $backup_dir . $document->path;
111
                    @mkdir(dirname($doc_dir), $perm_dirs, true);
112 View Code Duplication
                    if (file_exists($course->path . $document->path)) {
113
                        copy($course->path . $document->path, $doc_dir);
114
                    }
115
                } else {
116
                    @mkdir($backup_dir . $document->path, $perm_dirs, true);
117
                }
118
            }
119
        }
120
121
        // Copy all scorm documents to the temp-dir
122
        if (isset($course->resources[RESOURCE_SCORM]) && is_array($course->resources[RESOURCE_SCORM])) {
123
            foreach ($course->resources[RESOURCE_SCORM] as $document) {
124
                $doc_dir = dirname($backup_dir . $document->path);
125
                @mkdir($doc_dir, $perm_dirs, true);
126
                copyDirTo($course->path . $document->path, $doc_dir, false);
127
            }
128
        }
129
130
        // Copy calendar attachments.
131
132 View Code Duplication
        if (isset($course->resources[RESOURCE_EVENT]) && is_array($course->resources[RESOURCE_EVENT])) {
133
            $doc_dir = dirname($backup_dir . '/upload/calendar/');
134
            @mkdir($doc_dir, $perm_dirs, true);
135
            copyDirTo($course->path . 'upload/calendar/', $doc_dir, false);
136
        }
137
138
        // Copy Learning path author image.
139 View Code Duplication
        if (isset($course->resources[RESOURCE_LEARNPATH]) && is_array($course->resources[RESOURCE_LEARNPATH])) {
140
            $doc_dir = dirname($backup_dir . '/upload/learning_path/');
141
            @mkdir($doc_dir, $perm_dirs, true);
142
            copyDirTo($course->path . 'upload/learning_path/', $doc_dir, false);
143
        }
144
145
        // Copy announcements attachments.
146 View Code Duplication
        if (isset($course->resources[RESOURCE_ANNOUNCEMENT]) && is_array($course->resources[RESOURCE_ANNOUNCEMENT])) {
147
            $doc_dir = dirname($backup_dir . '/upload/announcements/');
148
            @mkdir($doc_dir, $perm_dirs, true);
149
            copyDirTo($course->path . 'upload/announcements/', $doc_dir, false);
150
        }
151
152
        // Copy work folders (only folders)
153 View Code Duplication
        if (isset($course->resources[RESOURCE_WORK]) && is_array($course->resources[RESOURCE_WORK])) {
154
            $doc_dir = dirname($backup_dir . '/upload/work/');
155
            @mkdir($doc_dir, $perm_dirs, true);
156
            // @todo: adjust to only create subdirs, but not copy files
157
            copyDirTo($course->path . 'upload/work/', $doc_dir, false);
158
        }
159
160
        if (isset($course->resources[RESOURCE_ASSET]) && is_array($course->resources[RESOURCE_ASSET])) {
161
            /** @var Asset $asset */
162
            foreach ($course->resources[RESOURCE_ASSET] as $asset) {
163
                $doc_dir = $backup_dir . $asset->path;
164
                @mkdir(dirname($doc_dir), $perm_dirs, true);
165 View Code Duplication
                if (file_exists($course->path . $asset->path)) {
166
                    copy($course->path . $asset->path, $doc_dir);
167
                }
168
            }
169
        }
170
171
        // Zip the course-contents
172
        $zip = new \PclZip($zipFilePath);
173
        $zip->create($backup_dir, PCLZIP_OPT_REMOVE_PATH, $backup_dir);
174
175
        // Remove the temp-dir.
176
        rmdirr($backup_dir);
177
        return $zipFileName;
178
    }
179
180
    /**
181
     * @param int $user_id
182
     * @return array
183
     */
184
    public static function getAvailableBackups($user_id = null)
185
    {
186
        $backup_files = array();
187
        $dirname = self::getBackupDir();
188
        if ($dir = opendir($dirname)) {
189
            while (($file = readdir($dir)) !== false) {
190
                $file_parts = explode('_', $file);
191
                if (count($file_parts) == 3) {
192
                    $owner_id = $file_parts[0];
193
                    $course_code = $file_parts[1];
194
                    $file_parts = explode('.', $file_parts[2]);
195
                    $date = $file_parts[0];
196
                    $ext = isset($file_parts[1]) ? $file_parts[1] : null;
197
                    if ($ext == 'zip' && ($user_id != null && $owner_id == $user_id || $user_id == null)) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $user_id of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison !== instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing $user_id of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
198
                        $date = substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2) . ' ' . substr($date, 9, 2) . ':' . substr($date, 11, 2) . ':' . substr($date, 13, 2);
199
                        $backup_files[] = array(
200
                            'file' => $file,
201
                            'date' => $date,
202
                            'course_code' => $course_code,
203
                        );
204
                    }
205
                }
206
            }
207
            closedir($dir);
208
        }
209
210
        return $backup_files;
211
    }
212
213
    /**
214
     * @param array $file
215
     * @return bool|string
216
     */
217
    public static function importUploadedFile($file)
218
    {
219
        $new_filename = uniqid('') . '.zip';
220
        $new_dir = self::getBackupDir();
221
        if (!is_dir($new_dir)) {
222
            $fs = new Filesystem();
223
            $fs->mkdir($new_dir);
224
        }
225
        if (is_dir($new_dir) && is_writable($new_dir)) {
226
            move_uploaded_file($file, $new_dir.$new_filename);
227
228
            return $new_filename;
229
        }
230
231
        return false;
232
    }
233
234
    /**
235
     * Read a course-object from a zip-file
236
     * @param string $filename
237
     * @param boolean $delete Delete the file after reading the course?
238
     *
239
     * @return course The course
240
     * @todo Check if the archive is a correct Chamilo-export
241
     */
242
    public static function readCourse($filename, $delete = false)
243
    {
244
        CourseArchiver::cleanBackupDir();
245
        // Create a temp directory
246
        $tmp_dir_name = 'CourseArchiver_'.uniqid('');
247
        $unzip_dir = self::getBackupDir().$tmp_dir_name;
248
        $filePath = self::getBackupDir().$filename;
249
250
        @mkdir($unzip_dir, api_get_permissions_for_new_directories(), true);
251
        @copy(
252
            $filePath,
253
            $unzip_dir . '/backup.zip'
254
        );
255
256
        // unzip the archive
257
        $zip = new \PclZip($unzip_dir . '/backup.zip');
258
        @chdir($unzip_dir);
259
        $zip->extract(PCLZIP_OPT_TEMP_FILE_ON);
260
        // remove the archive-file
261
        if ($delete) {
262
            @unlink($filePath);
263
        }
264
265
        // read the course
266
        if (!is_file('course_info.dat')) {
267
            return new Course();
268
        }
269
270
        $fp = @fopen('course_info.dat', "r");
271
        $contents = @fread($fp, filesize('course_info.dat'));
272
        @fclose($fp);
273
274
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Course', 'Course');
275
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Announcement', 'Announcement');
276
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Attendance', 'Attendance');
277
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\CalendarEvent', 'CalendarEvent');
278
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyLearnpath', 'CourseCopyLearnpath');
279
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyTestCategory', 'CourseCopyTestCategory');
280
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseDescription', 'CourseDescription');
281
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseSession', 'CourseSession');
282
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Document', 'Document');
283
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Forum', 'Forum');
284
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumCategory', 'ForumCategory');
285
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumPost', 'ForumPost');
286
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumTopic', 'ForumTopic');
287
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Glossary', 'Glossary');
288
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup', 'GradeBookBackup');
289
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Link', 'Link');
290
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\LinkCategory', 'LinkCategory');
291
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Quiz', 'Quiz');
292
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion', 'QuizQuestion');
293
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestionOption', 'QuizQuestionOption');
294
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\ScormDocument', 'ScormDocument');
295
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Survey', 'Survey');
296
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyInvitation', 'SurveyInvitation');
297
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyQuestion', 'SurveyQuestion');
298
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Thematic', 'Thematic');
299
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\ToolIntro', 'ToolIntro');
300
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Wiki', 'Wiki');
301
        class_alias('Chamilo\CourseBundle\Component\CourseCopy\Resources\Work', 'Work');
302
303
        $course = unserialize(base64_decode($contents));
304
305
        if (!in_array(
306
            get_class($course), ['Course', 'Chamilo\CourseBundle\Component\CourseCopy\Course'])
307
        ) {
308
            return new Course();
309
        }
310
311
        $course->backup_path = $unzip_dir;
312
313
        return $course;
314
    }
315
}
316