CourseRestorer::checkUserId()   A
last analyzed

Complexity

Conditions 5

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
nop 2
dl 0
loc 18
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
namespace Chamilo\CourseBundle\Component\CourseCopy;
6
7
use Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup;
8
use Chamilo\CourseBundle\Component\CourseCopy\Resources\LearnPathCategory;
9
use Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion;
10
use Chamilo\CourseBundle\Entity\CLpCategory;
11
use Chamilo\CourseBundle\Entity\CQuizAnswer;
12
use CourseManager;
13
use Database;
14
use DocumentManager;
15
use Question;
16
use stdClass;
17
use SurveyManager;
18
use TestCategory;
19
20
/**
21
 * Class CourseRestorer.
22
 *
23
 * Class to restore items from a course object to a Chamilo-course
24
 *
25
 * @author Bart Mollet <[email protected]>
26
 * @author Julio Montoya <[email protected]> Several fixes/improvements
27
 */
28
class CourseRestorer
29
{
30
    /**
31
     * The course-object.
32
     */
33
    public $course;
34
    public $destination_course_info;
35
36
    /**
37
     * What to do with files with same name (FILE_SKIP, FILE_RENAME or
38
     * FILE_OVERWRITE).
39
     */
40
    public $file_option;
41
    public $set_tools_invisible_by_default;
42
    public $skip_content;
43
    // Restoration is done in the order listed for $tools_to_restore
44
    public $tools_to_restore = [
45
        'documents', // first restore documents
46
        'announcements',
47
        'attendance',
48
        'course_descriptions',
49
        'events',
50
        'forum_category',
51
        'forums',
52
       // 'forum_topics',
53
        'glossary',
54
        'quizzes',
55
        'test_category',
56
        'links',
57
        'works',
58
        'xapi_tool',
59
        'h5p_tool',
60
        'surveys',
61
        'learnpath_category',
62
        'learnpaths',
63
        //'scorm_documents', ??
64
        'tool_intro',
65
        'thematic',
66
        'wiki',
67
        'gradebook',
68
        'assets',
69
    ];
70
71
    /** Setting per tool */
72
    public $tool_copy_settings = [];
73
    public $isXapiEnabled = false;
74
    public $isH5pEnabled = false;
75
76
    /**
77
     * If true adds the text "copy" in the title of an item (only for LPs right now).
78
     */
79
    public $add_text_in_items = false;
80
    public $destination_course_id;
81
82
    public $copySessionContent = false;
83
84
    /**
85
     * CourseRestorer constructor.
86
     *
87
     * @param Course $course
88
     */
89
    public function __construct($course)
90
    {
91
        $this->course = $course;
92
        $courseInfo = api_get_course_info($this->course->code);
93
        $this->course_origin_id = null;
94
        if (!empty($courseInfo)) {
95
            $this->course_origin_id = $courseInfo['real_id'];
96
        }
97
        $this->file_option = FILE_RENAME;
98
        $this->set_tools_invisible_by_default = false;
99
        $this->skip_content = [];
100
101
        $forceImport = api_get_configuration_value('allow_import_scorm_package_in_course_builder');
102
        if ($forceImport) {
103
            $this->tools_to_restore[] = 'scorm_documents';
104
        }
105
    }
106
107
    /**
108
     * Set the file-option.
109
     *
110
     * @param int $option (optional) What to do with files with same name
111
     *                    FILE_SKIP, FILE_RENAME or FILE_OVERWRITE
112
     */
113
    public function set_file_option($option = FILE_OVERWRITE)
114
    {
115
        $this->file_option = $option;
116
    }
117
118
    /**
119
     * @param bool $status
120
     */
121
    public function set_add_text_in_items($status)
122
    {
123
        $this->add_text_in_items = $status;
124
    }
125
126
    /**
127
     * @param array $array
128
     */
129
    public function set_tool_copy_settings($array)
130
    {
131
        $this->tool_copy_settings = $array;
132
    }
133
134
    /**
135
     * Restore a course.
136
     *
137
     * @param string $destination_course_code code of the Chamilo-course in
138
     * @param int    $session_id
139
     * @param bool   $update_course_settings  Course settings are going to be restore?
140
     * @param bool   $respect_base_content
141
     *
142
     * @return false|null
143
     */
144
    public function restore(
145
        $destination_course_code = '',
146
        $session_id = 0,
147
        $update_course_settings = false,
148
        $respect_base_content = false
149
    ) {
150
        if ($destination_course_code == '') {
151
            $course_info = api_get_course_info();
152
            $this->destination_course_info = $course_info;
153
            $this->course->destination_path = $course_info['path'];
154
        } else {
155
            $course_info = api_get_course_info($destination_course_code);
156
            $this->destination_course_info = $course_info;
157
            $this->course->destination_path = $course_info['path'];
158
        }
159
        $this->destination_course_id = $course_info['real_id'];
160
        // Getting first teacher (for the forums)
161
        $teacher_list = CourseManager::get_teacher_list_from_course_code($course_info['code']);
162
        $this->first_teacher_id = api_get_user_id();
163
        $this->isXapiEnabled = \XApiPlugin::create()->isEnabled();
164
        $this->isH5pEnabled = false; //\H5pImportPlugin::create()->isEnabled();
165
166
        if (!empty($teacher_list)) {
167
            foreach ($teacher_list as $teacher) {
168
                $this->first_teacher_id = $teacher['user_id'];
169
                break;
170
            }
171
        }
172
173
        if (empty($this->course)) {
174
            return false;
175
        }
176
177
        // Source platform encoding - reading/detection
178
        // The correspondent data field has been added as of version 1.8.6.1
179
        if (empty($this->course->encoding)) {
180
            // The archive has been created by a system which is prior to 1.8.6.1 version.
181
            // In this case we have to detect the encoding.
182
            $sample_text = $this->course->get_sample_text()."\n";
183
            // Let us exclude ASCII lines, probably they are English texts.
184
            $sample_text = explode("\n", $sample_text);
185
            foreach ($sample_text as $key => &$line) {
186
                if (api_is_valid_ascii($line)) {
187
                    unset($sample_text[$key]);
188
                }
189
            }
190
            $sample_text = implode("\n", $sample_text);
191
            $this->course->encoding = api_detect_encoding(
192
                $sample_text,
193
                $course_info['language']
194
            );
195
        }
196
197
        // Encoding conversion of the course, if it is needed.
198
        $this->course->to_system_encoding();
199
200
        foreach ($this->tools_to_restore as $tool) {
201
            if ('xapi_tool' == $tool && !$this->isXapiEnabled) {
202
                continue;
203
            }
204
            if ('h5p_tool' == $tool && !$this->isH5pEnabled) {
205
                continue;
206
            }
207
            $function_build = 'restore_'.$tool;
208
            $this->$function_build(
209
                $session_id,
210
                $respect_base_content,
211
                $destination_course_code
212
            );
213
        }
214
215
        if ($update_course_settings) {
216
            $this->restore_course_settings($destination_course_code);
217
        }
218
219
        // Restore the item properties
220
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
221
        foreach ($this->course->resources as $type => $resources) {
222
            if (is_array($resources)) {
223
                foreach ($resources as $id => $resource) {
224
                    if (isset($resource->item_properties)) {
225
                        foreach ($resource->item_properties as $property) {
226
                            // First check if there isn't already a record for this resource
227
                            $sql = "SELECT * FROM $table
228
                                    WHERE
229
                                        c_id = ".$this->destination_course_id." AND
230
                                        tool = '".$property['tool']."' AND
231
                                        ref = '".$resource->destination_id."'";
232
233
                            $params = [];
234
                            if (!empty($session_id)) {
235
                                $params['session_id'] = (int) $session_id;
236
                            }
237
238
                            $res = Database::query($sql);
239
                            if (Database::num_rows($res) == 0) {
240
                                /* The to_group_id and to_user_id are set to default
241
                                values as users/groups possibly not exist in
242
                                the target course*/
243
244
                                $params['c_id'] = $this->destination_course_id;
245
                                $params['tool'] = self::DBUTF8($property['tool']);
246
                                $params['insert_user_id'] = $this->checkUserId($property['insert_user_id']) ?: null;
247
                                $params['insert_date'] = self::DBUTF8($property['insert_date']);
248
                                $params['lastedit_date'] = self::DBUTF8($property['lastedit_date']);
249
                                $params['ref'] = $resource->destination_id;
250
                                $params['lastedit_type'] = self::DBUTF8($property['lastedit_type']);
251
                                $params['lastedit_user_id'] = $this->checkUserId($property['lastedit_user_id']);
252
                                $params['visibility'] = self::DBUTF8($property['visibility']);
253
                                $params['start_visible'] = self::DBUTF8($property['start_visible']);
254
                                $params['end_visible'] = self::DBUTF8($property['end_visible']);
255
                                $params['to_user_id'] = $this->checkUserId($property['to_user_id']) ?: null;
256
257
                                $id = Database::insert($table, $params);
258
                                if ($id) {
259
                                    $sql = "UPDATE $table SET id = iid WHERE iid = $id";
260
                                    Database::query($sql);
261
                                }
262
                            }
263
                        }
264
                    }
265
                }
266
            }
267
        }
268
    }
269
270
    /**
271
     * Restore only harmless course settings:
272
     * course_language, visibility, department_name,department_url,
273
     * subscribe, unsubscribe ,category_code.
274
     *
275
     * @param string $destination_course_code
276
     */
277
    public function restore_course_settings($destination_course_code)
278
    {
279
        $origin_course_info = api_get_course_info($destination_course_code);
280
        $course_info = $this->course->info;
281
        $params['course_language'] = $course_info['language'];
282
        $params['visibility'] = $course_info['visibility'];
283
        $params['department_name'] = $course_info['department_name'];
284
        $params['department_url'] = $course_info['department_url'];
285
        $params['category_code'] = $course_info['categoryCode'];
286
        $params['subscribe'] = $course_info['subscribe_allowed'];
287
        $params['unsubscribe'] = $course_info['unsubscribe'];
288
        CourseManager::update_attributes($origin_course_info['real_id'], $params);
289
    }
290
291
    /**
292
     * Restore documents.
293
     *
294
     * @param int    $session_id
295
     * @param bool   $respect_base_content
296
     * @param string $destination_course_code
297
     */
298
    public function restore_documents(
299
        $session_id = 0,
300
        $respect_base_content = false,
301
        $destination_course_code = ''
302
    ) {
303
        $course_info = api_get_course_info($destination_course_code);
304
305
        if (!$this->course->has_resources(RESOURCE_DOCUMENT)) {
306
            return;
307
        }
308
309
        $webEditorCss = api_get_path(WEB_CSS_PATH).'editor.css';
310
        $table = Database::get_course_table(TABLE_DOCUMENT);
311
        $resources = $this->course->resources;
312
        $path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/';
313
        $originalFolderNameList = [];
314
        foreach ($resources[RESOURCE_DOCUMENT] as $id => $document) {
315
            $my_session_id = empty($document->item_properties[0]['session_id']) ? 0 : $session_id;
316
317
            if (false === $respect_base_content && $session_id) {
318
                if (empty($my_session_id)) {
319
                    $my_session_id = $session_id;
320
                }
321
            }
322
323
            if ($document->file_type == FOLDER) {
324
                $visibility = isset($document->item_properties[0]['visibility']) ? $document->item_properties[0]['visibility'] : '';
325
                $new = substr($document->path, 8);
326
                $folderList = explode('/', $new);
327
                $tempFolder = '';
328
329
                // Check if the parent path exists.
330
                foreach ($folderList as $folder) {
331
                    $folderToCreate = $tempFolder.$folder;
332
                    $sysFolderPath = $path.'document'.$folderToCreate;
333
                    $tempFolder .= $folder.'/';
334
335
                    if (empty($folderToCreate)) {
336
                        continue;
337
                    }
338
                    $title = $document->title;
339
                    $originalFolderNameList[basename($document->path)] = $document->title;
340
                    if (empty($title)) {
341
                        $title = basename($sysFolderPath);
342
                    }
343
                    //error_log($title); error_log($sysFolderPath);
344
                    // File doesn't exist in file system.
345
                    if (!is_dir($sysFolderPath)) {
346
                        /*error_log('Creating directory');
347
                        error_log("Creating $folderToCreate");*/
348
                        // Creating directory
349
                        create_unexisting_directory(
350
                            $course_info,
351
                            api_get_user_id(),
352
                            $my_session_id,
353
                            0,
354
                            0,
355
                            $path.'document',
356
                            $folderToCreate,
357
                            $title,
358
                            $visibility
359
                        );
360
                        continue;
361
                    }
362
363
                    // File exist in file system.
364
                    $documentData = DocumentManager::get_document_id(
365
                        $course_info,
366
                        $folderToCreate,
367
                        $session_id
368
                    );
369
370
                    //error_log("session_id $session_id");
371
                    if (empty($documentData)) {
372
                        if (!is_dir($sysFolderPath)) {
373
                            //error_log('$documentData empty');
374
                            //error_log('$folderToCreate '.$folderToCreate);
375
                            /* This means the folder exists in the
376
                            filesystem but not in the DB, trying to fix it */
377
                            add_document(
378
                                $course_info,
379
                                $folderToCreate,
380
                                'folder',
381
                                0,
382
                                $title,
383
                                null,
384
                                null,
385
                                false,
386
                                null,
387
                                $session_id,
388
                                0,
389
                                false
390
                            );
391
                        }
392
                    } else {
393
                        $insertUserId = isset($document->item_properties[0]['insert_user_id']) ? $document->item_properties[0]['insert_user_id'] : api_get_user_id();
394
                        $insertUserId = $this->checkUserId($insertUserId);
395
                        // Check if user exists in platform
396
                        $toUserId = isset($document->item_properties[0]['to_user_id']) ? $document->item_properties[0]['to_user_id'] : null;
397
                        $toUserId = $this->checkUserId($toUserId, true);
398
                        $groupId = isset($document->item_properties[0]['to_group_id']) ? $document->item_properties[0]['to_group_id'] : null;
399
                        $groupInfo = $this->checkGroupId($groupId);
400
                        //error_log(" if folder exists then just refresh it");
401
                        // if folder exists then just refresh it
402
                        api_item_property_update(
403
                            $course_info,
404
                            TOOL_DOCUMENT,
405
                            $documentData,
406
                            'FolderUpdated',
407
                            $insertUserId,
408
                            $groupInfo,
409
                            $toUserId,
410
                            null,
411
                            null,
412
                            $my_session_id
413
                        );
414
                    }
415
                }
416
            } elseif ($document->file_type == DOCUMENT) {
417
                // Checking if folder exists in the database otherwise we created it
418
                $dir_to_create = dirname($document->path);
419
                $originalFolderNameList[basename($document->path)] = $document->title;
420
                if (!empty($dir_to_create) && $dir_to_create != 'document' && $dir_to_create != '/') {
421
                    // it creates folder images if it doesn't exist , used for hotspot pictures.
422
                    if (false !== strpos($document->path, '/images/') && !is_dir(dirname($path.$document->path))) {
423
                        $perm = api_get_permissions_for_new_directories();
424
                        mkdir(dirname($path.$document->path), $perm, true);
425
                    }
426
                    if (is_dir($path.dirname($document->path))) {
427
                        $sql = "SELECT id FROM $table
428
                                WHERE
429
                                    c_id = ".$this->destination_course_id." AND
430
                                    path = '/".self::DBUTF8escapestring(substr(dirname($document->path), 9))."'";
431
                        $res = Database::query($sql);
432
433
                        if (Database::num_rows($res) == 0) {
434
                            $new = '/'.substr(dirname($document->path), 9);
435
                            // It adds the folder name as title
436
                            $title = str_replace('/', '', $new);
437
438
                            // This code fixes the possibility for a file without a directory entry to be
439
                            $document_id = add_document(
440
                                $course_info,
441
                                $new,
442
                                'folder',
443
                                0,
444
                                $title,
445
                                null,
446
                                null,
447
                                false,
448
                                0,
449
                                0,
450
                                0,
451
                                false
452
                            );
453
454
                            $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
455
                            $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
456
                            $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
457
                            $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
458
                            $groupInfo = $this->checkGroupId($toGroupId);
459
                            $insertUserId = $this->checkUserId($insertUserId);
460
                            $toUserId = $this->checkUserId($toUserId, true);
461
462
                            api_item_property_update(
463
                                $course_info,
464
                                TOOL_DOCUMENT,
465
                                $document_id,
466
                                'FolderCreated',
467
                                $insertUserId,
468
                                $groupInfo,
469
                                $toUserId,
470
                                null,
471
                                null,
472
                                $my_session_id
473
                            );
474
                        }
475
                    }
476
                }
477
478
                //error_log(print_r($originalFolderNameList, 1));
479
                if (file_exists($path.$document->path)) {
480
                    switch ($this->file_option) {
481
                        case FILE_OVERWRITE:
482
                            $origin_path = $this->course->backup_path.'/'.$document->path;
483
                            if (file_exists($origin_path)) {
484
                                copy($origin_path, $path.$document->path);
485
                                $this->fixEditorHtmlContent($path.$document->path, $webEditorCss);
486
                                $sql = "SELECT id FROM $table
487
                                        WHERE
488
                                            c_id = ".$this->destination_course_id." AND
489
                                            path = '/".self::DBUTF8escapestring(substr($document->path, 9))."'";
490
491
                                $res = Database::query($sql);
492
                                $count = Database::num_rows($res);
493
494
                                if ($count == 0) {
495
                                    $params = [
496
                                        'path' => "/".self::DBUTF8(substr($document->path, 9)),
497
                                        'c_id' => $this->destination_course_id,
498
                                        'comment' => self::DBUTF8($document->comment),
499
                                        'title' => self::DBUTF8($document->title),
500
                                        'filetype' => self::DBUTF8($document->file_type),
501
                                        'size' => self::DBUTF8($document->size),
502
                                        'session_id' => $my_session_id,
503
                                        'readonly' => 0,
504
                                    ];
505
506
                                    $document_id = Database::insert($table, $params);
507
508
                                    if ($document_id) {
509
                                        $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
510
                                        Database::query($sql);
511
                                    }
512
                                    $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
513
514
                                    $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
515
                                    $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
516
                                    $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
517
                                    $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
518
519
                                    $insertUserId = $this->checkUserId($insertUserId);
520
                                    $toUserId = $this->checkUserId($toUserId, true);
521
                                    $groupInfo = $this->checkGroupId($toGroupId);
522
523
                                    api_item_property_update(
524
                                        $course_info,
525
                                        TOOL_DOCUMENT,
526
                                        $document_id,
527
                                        'DocumentAdded',
528
                                        $insertUserId,
529
                                        $groupInfo,
530
                                        $toUserId,
531
                                        null,
532
                                        null,
533
                                        $my_session_id
534
                                    );
535
                                } else {
536
                                    $obj = Database::fetch_object($res);
537
                                    $document_id = $obj->id;
538
                                    $params = [
539
                                        'path' => "/".self::DBUTF8(substr($document->path, 9)),
540
                                        'c_id' => $this->destination_course_id,
541
                                        'comment' => self::DBUTF8($document->comment),
542
                                        'title' => self::DBUTF8($document->title),
543
                                        'filetype' => self::DBUTF8($document->file_type),
544
                                        'size' => self::DBUTF8($document->size),
545
                                        'session_id' => $my_session_id,
546
                                    ];
547
548
                                    Database::update(
549
                                        $table,
550
                                        $params,
551
                                        [
552
                                            'c_id = ? AND path = ?' => [
553
                                                $this->destination_course_id,
554
                                                "/".self::DBUTF8escapestring(substr($document->path, 9)),
555
                                            ],
556
                                        ]
557
                                    );
558
559
                                    $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $obj->id;
560
561
                                    $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
562
                                    $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
563
                                    $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
564
                                    $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
565
566
                                    $insertUserId = $this->checkUserId($insertUserId);
567
                                    $toUserId = $this->checkUserId($toUserId, true);
568
                                    $groupInfo = $this->checkGroupId($toGroupId);
569
570
                                    api_item_property_update(
571
                                        $course_info,
572
                                        TOOL_DOCUMENT,
573
                                        $obj->id,
574
                                        'default',
575
                                        $insertUserId,
576
                                        $groupInfo,
577
                                        $toUserId,
578
                                        null,
579
                                        null,
580
                                        $my_session_id
581
                                    );
582
                                }
583
584
                                // Replace old course code with the new destination code
585
                                $file_info = pathinfo($path.$document->path);
586
587
                                if (isset($file_info['extension']) && in_array($file_info['extension'], ['html', 'htm'])) {
588
                                    $content = file_get_contents($path.$document->path);
589
                                    if (UTF8_CONVERT) {
590
                                        $content = utf8_encode($content);
591
                                    }
592
                                    $content = DocumentManager::replaceUrlWithNewCourseCode(
593
                                        $content,
594
                                        $this->course->code,
595
                                        $this->course->destination_path,
596
                                        $this->course->backup_path,
597
                                        $this->course->info['path']
598
                                    );
599
                                    file_put_contents($path.$document->path, $content);
600
                                }
601
602
                                $params = [
603
                                    'comment' => self::DBUTF8($document->comment),
604
                                    'title' => self::DBUTF8($document->title),
605
                                    'size' => self::DBUTF8($document->size),
606
                                ];
607
                                Database::update(
608
                                    $table,
609
                                    $params,
610
                                    [
611
                                        'c_id = ? AND id = ?' => [
612
                                            $this->destination_course_id,
613
                                            $document_id,
614
                                        ],
615
                                    ]
616
                                );
617
                            }
618
                            break;
619
                        case FILE_SKIP:
620
                            $sql = "SELECT id FROM $table
621
                                    WHERE
622
                                        c_id = ".$this->destination_course_id." AND
623
                                        path='/".self::DBUTF8escapestring(substr($document->path, 9))."'";
624
                            $res = Database::query($sql);
625
                            $obj = Database::fetch_object($res);
626
                            $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $obj->id;
627
                            break;
628
                        case FILE_RENAME:
629
                            //error_log("Rename: ".$path.$document->path);
630
                            $i = 1;
631
                            $ext = explode('.', basename($document->path));
632
                            if (count($ext) > 1) {
633
                                $ext = array_pop($ext);
634
                                $file_name_no_ext = substr($document->path, 0, -(strlen($ext) + 1));
635
                                $ext = '.'.$ext;
636
                            } else {
637
                                $ext = '';
638
                                $file_name_no_ext = $document->path;
639
                            }
640
                            $new_file_name = $file_name_no_ext.'_'.$i.$ext;
641
                            $file_exists = file_exists($path.$new_file_name);
642
                            while ($file_exists) {
643
                                $i++;
644
                                $new_file_name = $file_name_no_ext.'_'.$i.$ext;
645
                                $file_exists = file_exists($path.$new_file_name);
646
                            }
647
648
                            if (!empty($session_id)) {
649
                                $originalPath = $document->path;
650
                                //error_log("document->path: ".$document->path);
651
                                $document_path = explode('/', $document->path, 3);
652
                                $course_path = $path;
653
                                $orig_base_folder = $document_path[1];
654
                                $orig_base_path = $course_path.$document_path[0].'/'.$document_path[1];
655
656
                                if (is_dir($orig_base_path)) {
657
                                    $new_base_foldername = $orig_base_folder;
658
                                    $new_base_path = $orig_base_path;
659
660
                                    if (isset($_SESSION['orig_base_foldername']) &&
661
                                        $_SESSION['orig_base_foldername'] != $new_base_foldername
662
                                    ) {
663
                                        unset($_SESSION['new_base_foldername']);
664
                                        unset($_SESSION['orig_base_foldername']);
665
                                        unset($_SESSION['new_base_path']);
666
                                    }
667
668
                                    $folder_exists = file_exists($new_base_path);
669
                                    if ($folder_exists) {
670
                                        // e.g: carpeta1 in session
671
                                        $_SESSION['orig_base_foldername'] = $new_base_foldername;
672
                                        $x = 0;
673
                                        while ($folder_exists) {
674
                                            $x = $x + 1;
675
                                            $new_base_foldername = $document_path[1].'_'.$x;
676
                                            $new_base_path = $orig_base_path.'_'.$x;
677
                                            if (isset($_SESSION['new_base_foldername']) &&
678
                                                $_SESSION['new_base_foldername'] == $new_base_foldername
679
                                            ) {
680
                                                break;
681
                                            }
682
                                            $folder_exists = file_exists($new_base_path);
683
                                        }
684
                                        $_SESSION['new_base_foldername'] = $new_base_foldername;
685
                                        $_SESSION['new_base_path'] = $new_base_path;
686
                                    }
687
688
                                    if (isset($_SESSION['new_base_foldername']) && isset($_SESSION['new_base_path'])) {
689
                                        $new_base_foldername = $_SESSION['new_base_foldername'];
690
                                        $new_base_path = $_SESSION['new_base_path'];
691
                                    }
692
693
                                    $dest_document_path = $new_base_path.'/'.$document_path[2]; // e.g: "/var/www/wiener/courses/CURSO4/document/carpeta1_1/subcarpeta1/collaborative.png"
694
                                    $basedir_dest_path = dirname($dest_document_path); // e.g: "/var/www/wiener/courses/CURSO4/document/carpeta1_1/subcarpeta1"
695
                                    $base_path_document = $course_path.$document_path[0]; // e.g: "/var/www/wiener/courses/CURSO4/document"
696
                                    $path_title = '/'.$new_base_foldername.'/'.$document_path[2];
697
698
                                    /*error_log("copy_folder_course_session");
699
                                    error_log("original: $orig_base_path");
700
                                    error_log($basedir_dest_path);
701
                                    error_log($document->title);*/
702
703
                                    copy_folder_course_session(
704
                                        $basedir_dest_path,
705
                                        $base_path_document,
706
                                        $session_id,
707
                                        $course_info,
708
                                        $document,
709
                                        $this->course_origin_id,
710
                                        $originalFolderNameList,
711
                                        $originalPath
712
                                    );
713
714
                                    if (file_exists($course_path.$document->path)) {
715
                                        copy($course_path.$document->path, $dest_document_path);
716
                                    }
717
718
                                    // Replace old course code with the new destination code see BT#1985
719
                                    if (file_exists($dest_document_path)) {
720
                                        $file_info = pathinfo($dest_document_path);
721
                                        if (in_array($file_info['extension'], ['html', 'htm'])) {
722
                                            $content = file_get_contents($dest_document_path);
723
                                            if (UTF8_CONVERT) {
724
                                                $content = utf8_encode($content);
725
                                            }
726
                                            $content = DocumentManager::replaceUrlWithNewCourseCode(
727
                                                $content,
728
                                                $this->course->code,
729
                                                $this->course->destination_path,
730
                                                $this->course->backup_path,
731
                                                $this->course->info['path']
732
                                            );
733
                                            file_put_contents($dest_document_path, $content);
734
                                            $this->fixEditorHtmlContent($dest_document_path, $webEditorCss);
735
                                        }
736
                                    }
737
738
                                    $title = basename($path_title);
739
                                    if (isset($originalFolderNameList[basename($path_title)])) {
740
                                        $title = $originalFolderNameList[basename($path_title)];
741
                                    }
742
743
                                    $params = [
744
                                        'path' => self::DBUTF8($path_title),
745
                                        'c_id' => $this->destination_course_id,
746
                                        'comment' => self::DBUTF8($document->comment),
747
                                        'title' => self::DBUTF8($title),
748
                                        'filetype' => self::DBUTF8($document->file_type),
749
                                        'size' => self::DBUTF8($document->size),
750
                                        'session_id' => $my_session_id,
751
                                    ];
752
753
                                    $document_id = Database::insert($table, $params);
754
755
                                    if ($document_id) {
756
                                        $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
757
                                        Database::query($sql);
758
759
                                        $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
760
761
                                        $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
762
                                        $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
763
                                        $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
764
                                        $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
765
766
                                        $insertUserId = $this->checkUserId($insertUserId);
767
                                        $toUserId = $this->checkUserId($toUserId, true);
768
                                        $groupInfo = $this->checkGroupId($toGroupId);
769
770
                                        api_item_property_update(
771
                                            $course_info,
772
                                            TOOL_DOCUMENT,
773
                                            $document_id,
774
                                            'DocumentAdded',
775
                                            $insertUserId,
776
                                            $groupInfo,
777
                                            $toUserId,
778
                                            null,
779
                                            null,
780
                                            $my_session_id
781
                                        );
782
                                    }
783
                                } else {
784
                                    if (file_exists($path.$document->path)) {
785
                                        copy($path.$document->path, $path.$new_file_name);
786
                                    }
787
                                    // Replace old course code with the new destination code see BT#1985
788
                                    if (file_exists($path.$new_file_name)) {
789
                                        $file_info = pathinfo($path.$new_file_name);
790
                                        if (in_array($file_info['extension'], ['html', 'htm'])) {
791
                                            $content = file_get_contents($path.$new_file_name);
792
                                            if (UTF8_CONVERT) {
793
                                                $content = utf8_encode($content);
794
                                            }
795
                                            $content = DocumentManager::replaceUrlWithNewCourseCode(
796
                                                $content,
797
                                                $this->course->code,
798
                                                $this->course->destination_path,
799
                                                $this->course->backup_path,
800
                                                $this->course->info['path']
801
                                            );
802
                                            file_put_contents($path.$new_file_name, $content);
803
                                            $this->fixEditorHtmlContent($path.$new_file_name, $webEditorCss);
804
                                        }
805
                                    }
806
807
                                    $params = [
808
                                        'path' => "/".self::DBUTF8escapestring(substr($new_file_name, 9)),
809
                                        'c_id' => $this->destination_course_id,
810
                                        'comment' => self::DBUTF8($document->comment),
811
                                        'title' => self::DBUTF8($document->title),
812
                                        'filetype' => self::DBUTF8($document->file_type),
813
                                        'size' => self::DBUTF8($document->size),
814
                                        'session_id' => $my_session_id,
815
                                    ];
816
817
                                    $document_id = Database::insert($table, $params);
818
819
                                    if ($document_id) {
820
                                        $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
821
                                        Database::query($sql);
822
823
                                        $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
824
825
                                        $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
826
                                        $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
827
                                        $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
828
                                        $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
829
830
                                        $insertUserId = $this->checkUserId($insertUserId);
831
                                        $toUserId = $this->checkUserId($toUserId, true);
832
                                        $groupInfo = $this->checkGroupId($toGroupId);
833
834
                                        api_item_property_update(
835
                                            $course_info,
836
                                            TOOL_DOCUMENT,
837
                                            $document_id,
838
                                            'DocumentAdded',
839
                                            $insertUserId,
840
                                            $groupInfo,
841
                                            $toUserId,
842
                                            null,
843
                                            null,
844
                                            $my_session_id
845
                                        );
846
                                    }
847
                                }
848
                            } else {
849
                                copy(
850
                                    $this->course->backup_path.'/'.$document->path,
851
                                    $path.$new_file_name
852
                                );
853
854
                                // Replace old course code with the new destination code see BT#1985
855
                                if (file_exists($path.$new_file_name)) {
856
                                    $file_info = pathinfo($path.$new_file_name);
857
                                    if (in_array($file_info['extension'], ['html', 'htm'])) {
858
                                        $content = file_get_contents($path.$new_file_name);
859
                                        if (UTF8_CONVERT) {
860
                                            $content = utf8_encode($content);
861
                                        }
862
                                        $content = DocumentManager::replaceUrlWithNewCourseCode(
863
                                            $content,
864
                                            $this->course->code,
865
                                            $this->course->destination_path,
866
                                            $this->course->backup_path,
867
                                            $this->course->info['path']
868
                                        );
869
                                        file_put_contents($path.$new_file_name, $content);
870
                                        $this->fixEditorHtmlContent($path.$new_file_name, $webEditorCss);
871
                                    }
872
                                }
873
874
                                $params = [
875
                                    'c_id' => $this->destination_course_id,
876
                                    'path' => "/".self::DBUTF8escapestring(substr($new_file_name, 9)),
877
                                    'comment' => self::DBUTF8($document->comment),
878
                                    'title' => self::DBUTF8($document->title),
879
                                    'filetype' => self::DBUTF8($document->file_type),
880
                                    'size' => self::DBUTF8($document->size),
881
                                    'session_id' => $my_session_id,
882
                                ];
883
884
                                $document_id = Database::insert($table, $params);
885
886
                                if ($document_id) {
887
                                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
888
                                    Database::query($sql);
889
                                    $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
890
891
                                    $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
892
                                    $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
893
                                    $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
894
                                    $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
895
896
                                    $insertUserId = $this->checkUserId($insertUserId);
897
                                    $toUserId = $this->checkUserId($toUserId, true);
898
                                    $groupInfo = $this->checkGroupId($toGroupId);
899
900
                                    api_item_property_update(
901
                                        $course_info,
902
                                        TOOL_DOCUMENT,
903
                                        $document_id,
904
                                        'DocumentAdded',
905
                                        $insertUserId,
906
                                        $groupInfo,
907
                                        $toUserId,
908
                                        null,
909
                                        null,
910
                                        $my_session_id
911
                                    );
912
                                }
913
                            }
914
                            break;
915
                    } // end switch
916
                } else {
917
                    // end if file exists
918
919
                    //make sure the source file actually exists
920
                    if (is_file($this->course->backup_path.'/'.$document->path) &&
921
                        is_readable($this->course->backup_path.'/'.$document->path) &&
922
                        is_dir(dirname($path.$document->path)) &&
923
                        is_writeable(dirname($path.$document->path))
924
                    ) {
925
                        copy(
926
                            $this->course->backup_path.'/'.$document->path,
927
                            $path.$document->path
928
                        );
929
930
                        // Replace old course code with the new destination code see BT#1985
931
                        if (file_exists($path.$document->path)) {
932
                            $file_info = pathinfo($path.$document->path);
933
                            if (isset($file_info['extension']) && in_array($file_info['extension'], ['html', 'htm'])) {
934
                                $content = file_get_contents($path.$document->path);
935
                                if (UTF8_CONVERT) {
936
                                    $content = utf8_encode($content);
937
                                }
938
                                $content = DocumentManager::replaceUrlWithNewCourseCode(
939
                                    $content,
940
                                    $this->course->code,
941
                                    $this->course->destination_path,
942
                                    $this->course->backup_path,
943
                                    $this->course->info['path']
944
                                );
945
                                file_put_contents($path.$document->path, $content);
946
                                $this->fixEditorHtmlContent($path.$document->path, $webEditorCss);
947
                            }
948
                        }
949
950
                        $params = [
951
                            'c_id' => $this->destination_course_id,
952
                            'path' => "/".self::DBUTF8(substr($document->path, 9)),
953
                            'comment' => self::DBUTF8($document->comment),
954
                            'title' => self::DBUTF8($document->title),
955
                            'filetype' => self::DBUTF8($document->file_type),
956
                            'size' => self::DBUTF8($document->size),
957
                            'session_id' => $my_session_id,
958
                            'readonly' => 0,
959
                        ];
960
961
                        $document_id = Database::insert($table, $params);
962
963
                        if ($document_id) {
964
                            $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
965
                            Database::query($sql);
966
967
                            $this->course->resources[RESOURCE_DOCUMENT][$id]->destination_id = $document_id;
968
969
                            $itemProperty = isset($document->item_properties[0]) ? $document->item_properties[0] : '';
970
                            $insertUserId = isset($itemProperty['insert_user_id']) ? $itemProperty['insert_user_id'] : api_get_user_id();
971
                            $toGroupId = isset($itemProperty['to_group_id']) ? $itemProperty['to_group_id'] : 0;
972
                            $toUserId = isset($itemProperty['to_user_id']) ? $itemProperty['to_user_id'] : null;
973
974
                            $insertUserId = $this->checkUserId($insertUserId);
975
                            $toUserId = $this->checkUserId($toUserId, true);
976
                            $groupInfo = $this->checkGroupId($toGroupId);
977
978
                            api_item_property_update(
979
                                $course_info,
980
                                TOOL_DOCUMENT,
981
                                $document_id,
982
                                'DocumentAdded',
983
                                $insertUserId,
984
                                $groupInfo,
985
                                $toUserId,
986
                                null,
987
                                null,
988
                                $my_session_id
989
                            );
990
                        }
991
                    } else {
992
                        // There was an error in checking existence and
993
                        // permissions for files to copy. Try to determine
994
                        // the exact issue
995
                        // Issue with origin document?
996
                        if (!is_file($this->course->backup_path.'/'.$document->path)) {
997
                            error_log(
998
                                'Course copy generated an ignorable error while trying to copy '.
999
                                $this->course->backup_path.'/'.$document->path.': origin file not found'
1000
                            );
1001
                        } elseif (!is_readable($this->course->backup_path.'/'.$document->path)) {
1002
                            error_log(
1003
                                'Course copy generated an ignorable error while trying to copy '.
1004
                                $this->course->backup_path.'/'.$document->path.': origin file not readable'
1005
                            );
1006
                        }
1007
                        // Issue with destination directories?
1008
                        if (!is_dir(dirname($path.$document->path))) {
1009
                            error_log(
1010
                                'Course copy generated an ignorable error while trying to copy '.
1011
                                $this->course->backup_path.'/'.$document->path.' to '.
1012
                                dirname($path.$document->path).': destination directory not found'
1013
                            );
1014
                        }
1015
                        if (!is_writeable(dirname($path.$document->path))) {
1016
                            error_log(
1017
                                'Course copy generated an ignorable error while trying to copy '.
1018
                                $this->course->backup_path.'/'.$document->path.' to '.
1019
                                dirname($path.$document->path).': destination directory not writable'
1020
                            );
1021
                        }
1022
                    }
1023
                } // end file doesn't exist
1024
            }
1025
1026
            // add image information for area questions
1027
            if (preg_match('/^quiz-.*$/', $document->title) &&
1028
                preg_match('/^document\/images\/.*$/', $document->path)
1029
            ) {
1030
                $this->course->resources[RESOURCE_DOCUMENT]['image_quiz'][$document->title] = [
1031
                    'path' => $document->path,
1032
                    'title' => $document->title,
1033
                    'source_id' => $document->source_id,
1034
                    'destination_id' => $document->destination_id,
1035
                ];
1036
            }
1037
        } // end for each
1038
1039
        // Delete sessions for the copy the new folder in session
1040
        unset($_SESSION['new_base_foldername']);
1041
        unset($_SESSION['orig_base_foldername']);
1042
        unset($_SESSION['new_base_path']);
1043
    }
1044
1045
    /**
1046
     * Restore scorm documents
1047
     * TODO @TODO check that the restore function with renaming doesn't break the scorm structure!
1048
     * see #7029.
1049
     */
1050
    public function restore_scorm_documents()
1051
    {
1052
        $perm = api_get_permissions_for_new_directories();
1053
        if ($this->course->has_resources(RESOURCE_SCORM)) {
1054
            $resources = $this->course->resources;
1055
            foreach ($resources[RESOURCE_SCORM] as $document) {
1056
                $path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/';
1057
                @mkdir(dirname($path.$document->path), $perm, true);
1058
                if (file_exists($path.$document->path)) {
1059
                    switch ($this->file_option) {
1060
                        case FILE_OVERWRITE:
1061
                            rmdirr($path.$document->path);
1062
                            copyDirTo(
1063
                                $this->course->backup_path.'/'.$document->path,
1064
                                $path.$document->path,
1065
                                false
1066
                            );
1067
                            break;
1068
                        case FILE_SKIP:
1069
                            break;
1070
                        case FILE_RENAME:
1071
                            $i = 1;
1072
                            $ext = explode('.', basename($document->path));
1073
                            if (count($ext) > 1) {
1074
                                $ext = array_pop($ext);
1075
                                $file_name_no_ext = substr($document->path, 0, -(strlen($ext) + 1));
1076
                                $ext = '.'.$ext;
1077
                            } else {
1078
                                $ext = '';
1079
                                $file_name_no_ext = $document->path;
1080
                            }
1081
1082
                            $new_file_name = $file_name_no_ext.'_'.$i.$ext;
1083
                            $file_exists = file_exists($path.$new_file_name);
1084
1085
                            while ($file_exists) {
1086
                                $i++;
1087
                                $new_file_name = $file_name_no_ext.'_'.$i.$ext;
1088
                                $file_exists = file_exists($path.$new_file_name);
1089
                            }
1090
1091
                            rename(
1092
                                $this->course->backup_path.'/'.$document->path,
1093
                                $this->course->backup_path.'/'.$new_file_name
1094
                            );
1095
                            copyDirTo(
1096
                                $this->course->backup_path.'/'.$new_file_name,
1097
                                $path.dirname($new_file_name),
1098
                                false
1099
                            );
1100
                            rename(
1101
                                $this->course->backup_path.'/'.$new_file_name,
1102
                                $this->course->backup_path.'/'.$document->path
1103
                            );
1104
                            break;
1105
                    } // end switch
1106
                } else {
1107
                    // end if file exists
1108
                    copyDirTo(
1109
                        $this->course->backup_path.'/'.$document->path,
1110
                        $path.$document->path,
1111
                        false
1112
                    );
1113
                }
1114
            } // end for each
1115
        }
1116
    }
1117
1118
    /**
1119
     * Restore forums.
1120
     *
1121
     * @param int $sessionId
1122
     */
1123
    public function restore_forums($sessionId = 0)
1124
    {
1125
        if ($this->course->has_resources(RESOURCE_FORUM)) {
1126
            $sessionId = (int) $sessionId;
1127
            $table_forum = Database::get_course_table(TABLE_FORUM);
1128
            $resources = $this->course->resources;
1129
            foreach ($resources[RESOURCE_FORUM] as $id => $forum) {
1130
                $params = (array) $forum->obj;
1131
                $cat_id = '';
1132
                if (isset($this->course->resources[RESOURCE_FORUMCATEGORY]) &&
1133
                    isset($this->course->resources[RESOURCE_FORUMCATEGORY][$params['forum_category']])) {
1134
                    if ($this->course->resources[RESOURCE_FORUMCATEGORY][$params['forum_category']]->destination_id == -1) {
1135
                        $cat_id = $this->restore_forum_category($params['forum_category'], $sessionId);
1136
                    } else {
1137
                        $cat_id = $this->course->resources[RESOURCE_FORUMCATEGORY][$params['forum_category']]->destination_id;
1138
                    }
1139
                }
1140
1141
                $params = self::DBUTF8_array($params);
1142
                $params['c_id'] = $this->destination_course_id;
1143
                $params['forum_category'] = $cat_id;
1144
                $params['session_id'] = $sessionId;
1145
                $params['start_time'] = isset($params['start_time']) && $params['start_time'] === '0000-00-00 00:00:00' ? null : $params['start_time'];
1146
                $params['end_time'] = isset($params['end_time']) && $params['end_time'] === '0000-00-00 00:00:00' ? null : $params['end_time'];
1147
                $params['forum_id'] = 0;
1148
                unset($params['iid']);
1149
1150
                $params['forum_comment'] = DocumentManager::replaceUrlWithNewCourseCode(
1151
                    $params['forum_comment'],
1152
                    $this->course->code,
1153
                    $this->course->destination_path,
1154
                    $this->course->backup_path,
1155
                    $this->course->info['path']
1156
                );
1157
1158
                if (!empty($params['forum_image'])) {
1159
                    $original_forum_image = $this->course->path.'upload/forum/images/'.$params['forum_image'];
1160
                    if (file_exists($original_forum_image)) {
1161
                        $new_forum_image = api_get_path(SYS_COURSE_PATH).
1162
                            $this->destination_course_info['path'].'/upload/forum/images/'.$params['forum_image'];
1163
                        @copy($original_forum_image, $new_forum_image);
1164
                    }
1165
                }
1166
1167
                $new_id = Database::insert($table_forum, $params);
1168
1169
                if ($new_id) {
1170
                    $sql = "UPDATE $table_forum SET forum_id = iid WHERE iid = $new_id";
1171
                    Database::query($sql);
1172
1173
                    api_item_property_update(
1174
                        $this->destination_course_info,
1175
                        TOOL_FORUM,
1176
                        $new_id,
1177
                        'ForumUpdated',
1178
                        api_get_user_id(),
1179
                        null,
1180
                        null,
1181
                        null,
1182
                        null,
1183
                        $sessionId
1184
                    );
1185
1186
                    $this->course->resources[RESOURCE_FORUM][$id]->destination_id = $new_id;
1187
                    $forum_topics = 0;
1188
                    if (isset($this->course->resources[RESOURCE_FORUMTOPIC]) &&
1189
                        is_array($this->course->resources[RESOURCE_FORUMTOPIC])
1190
                    ) {
1191
                        foreach ($this->course->resources[RESOURCE_FORUMTOPIC] as $topic_id => $topic) {
1192
                            if ($topic->obj->forum_id == $id) {
1193
                                $this->restore_topic($topic_id, $new_id, $sessionId);
1194
                                $forum_topics++;
1195
                            }
1196
                        }
1197
                    }
1198
                    if ($forum_topics > 0) {
1199
                        $sql = "UPDATE ".$table_forum." SET forum_threads = ".$forum_topics."
1200
                                WHERE c_id = {$this->destination_course_id} AND forum_id = ".(int) $new_id;
1201
                        Database::query($sql);
1202
                    }
1203
                }
1204
            }
1205
        }
1206
    }
1207
1208
    /**
1209
     * Restore forum-categories.
1210
     */
1211
    public function restore_forum_category($my_id = null, $sessionId = 0)
1212
    {
1213
        $forum_cat_table = Database::get_course_table(TABLE_FORUM_CATEGORY);
1214
        $resources = $this->course->resources;
1215
        $sessionId = (int) $sessionId;
1216
        if (!empty($resources[RESOURCE_FORUMCATEGORY])) {
1217
            foreach ($resources[RESOURCE_FORUMCATEGORY] as $id => $forum_cat) {
1218
                if (!empty($my_id)) {
1219
                    if ($my_id != $id) {
1220
                        continue;
1221
                    }
1222
                }
1223
                if ($forum_cat && !$forum_cat->is_restored()) {
1224
                    $params = (array) $forum_cat->obj;
1225
                    $params['c_id'] = $this->destination_course_id;
1226
                    $params['cat_comment'] = DocumentManager::replaceUrlWithNewCourseCode(
1227
                        $params['cat_comment'],
1228
                        $this->course->code,
1229
                        $this->course->destination_path,
1230
                        $this->course->backup_path,
1231
                        $this->course->info['path']
1232
                    );
1233
                    $params['session_id'] = $sessionId;
1234
                    $params['cat_id'] = 0;
1235
                    unset($params['iid']);
1236
1237
                    $params = self::DBUTF8_array($params);
1238
                    $new_id = Database::insert($forum_cat_table, $params);
1239
1240
                    if ($new_id) {
1241
                        $sql = "UPDATE $forum_cat_table SET cat_id = iid WHERE iid = $new_id";
1242
                        Database::query($sql);
1243
1244
                        api_item_property_update(
1245
                            $this->destination_course_info,
1246
                            TOOL_FORUM_CATEGORY,
1247
                            $new_id,
1248
                            'ForumCategoryUpdated',
1249
                            api_get_user_id(),
1250
                            null,
1251
                            null,
1252
                            null,
1253
                            null,
1254
                            $sessionId
1255
                        );
1256
                        $this->course->resources[RESOURCE_FORUMCATEGORY][$id]->destination_id = $new_id;
1257
                    }
1258
1259
                    if (!empty($my_id)) {
1260
                        return $new_id;
1261
                    }
1262
                }
1263
            }
1264
        }
1265
    }
1266
1267
    /**
1268
     * Restore a forum-topic.
1269
     *
1270
     * @param false|string $forum_id
1271
     *
1272
     * @return int
1273
     */
1274
    public function restore_topic($thread_id, $forum_id, $sessionId = 0)
1275
    {
1276
        $table = Database::get_course_table(TABLE_FORUM_THREAD);
1277
        $topic = $this->course->resources[RESOURCE_FORUMTOPIC][$thread_id];
1278
1279
        $sessionId = (int) $sessionId;
1280
        $params = (array) $topic->obj;
1281
1282
        $params = self::DBUTF8_array($params);
1283
        $params['c_id'] = $this->destination_course_id;
1284
        $params['forum_id'] = $forum_id;
1285
        $params['thread_poster_id'] = $this->first_teacher_id;
1286
        $params['thread_date'] = api_get_utc_datetime();
1287
        $params['thread_close_date'] = null;
1288
        $params['thread_last_post'] = 0;
1289
        $params['thread_replies'] = 0;
1290
        $params['thread_views'] = 0;
1291
        $params['session_id'] = $sessionId;
1292
        $params['thread_id'] = 0;
1293
1294
        unset($params['iid']);
1295
1296
        $new_id = Database::insert($table, $params);
1297
1298
        if ($new_id) {
1299
            $sql = "UPDATE $table SET thread_id = iid WHERE iid = $new_id";
1300
            Database::query($sql);
1301
1302
            api_item_property_update(
1303
                $this->destination_course_info,
1304
                TOOL_FORUM_THREAD,
1305
                $new_id,
1306
                'ThreadAdded',
1307
                api_get_user_id(),
1308
                0,
1309
                0,
1310
                null,
1311
                null,
1312
                $sessionId
1313
            );
1314
1315
            $this->course->resources[RESOURCE_FORUMTOPIC][$thread_id]->destination_id = $new_id;
1316
            $topic_replies = -1;
1317
1318
            foreach ($this->course->resources[RESOURCE_FORUMPOST] as $post_id => $post) {
1319
                if ($post->obj->thread_id == $thread_id) {
1320
                    $topic_replies++;
1321
                    $this->restore_post($post_id, $new_id, $forum_id, $sessionId);
1322
                }
1323
            }
1324
        }
1325
1326
        return $new_id;
1327
    }
1328
1329
    /**
1330
     * Restore a forum-post.
1331
     *
1332
     * @TODO Restore tree-structure of posts. For example: attachments to posts.
1333
     *
1334
     * @param false|string $topic_id
1335
     *
1336
     * @return int
1337
     */
1338
    public function restore_post($id, $topic_id, $forum_id, $sessionId = 0)
1339
    {
1340
        $table_post = Database::get_course_table(TABLE_FORUM_POST);
1341
        $post = $this->course->resources[RESOURCE_FORUMPOST][$id];
1342
        $params = (array) $post->obj;
1343
        $params['c_id'] = $this->destination_course_id;
1344
        $params['forum_id'] = $forum_id;
1345
        $params['thread_id'] = $topic_id;
1346
        $params['poster_id'] = $this->first_teacher_id;
1347
        $params['post_date'] = api_get_utc_datetime();
1348
        $params['post_id'] = 0;
1349
        unset($params['iid']);
1350
1351
        $params['post_text'] = DocumentManager::replaceUrlWithNewCourseCode(
1352
            $params['post_text'],
1353
            $this->course->code,
1354
            $this->course->destination_path,
1355
            $this->course->backup_path,
1356
            $this->course->info['path']
1357
        );
1358
        $new_id = Database::insert($table_post, $params);
1359
1360
        if ($new_id) {
1361
            $sql = "UPDATE $table_post SET post_id = iid WHERE iid = $new_id";
1362
            Database::query($sql);
1363
1364
            api_item_property_update(
1365
                $this->destination_course_info,
1366
                TOOL_FORUM_POST,
1367
                $new_id,
1368
                'PostAdded',
1369
                api_get_user_id(),
1370
                0,
1371
                0,
1372
                null,
1373
                null,
1374
                $sessionId
1375
            );
1376
            $this->course->resources[RESOURCE_FORUMPOST][$id]->destination_id = $new_id;
1377
        }
1378
1379
        return $new_id;
1380
    }
1381
1382
    /**
1383
     * Restore links.
1384
     */
1385
    public function restore_links($session_id = 0)
1386
    {
1387
        if ($this->course->has_resources(RESOURCE_LINK)) {
1388
            $link_table = Database::get_course_table(TABLE_LINK);
1389
            $resources = $this->course->resources;
1390
1391
            foreach ($resources[RESOURCE_LINK] as $oldLinkId => $link) {
1392
                $cat_id = (int) $this->restore_link_category($link->category_id, $session_id);
1393
                $sql = "SELECT MAX(display_order)
1394
                        FROM $link_table
1395
                        WHERE
1396
                            c_id = ".$this->destination_course_id." AND
1397
                            category_id='".$cat_id."'";
1398
                $result = Database::query($sql);
1399
                [$max_order] = Database::fetch_array($result);
1400
1401
                $params = [];
1402
                $params['session_id'] = (int) $session_id;
1403
                $params['c_id'] = $this->destination_course_id;
1404
                $params['url'] = self::DBUTF8($link->url);
1405
                $params['title'] = self::DBUTF8($link->title);
1406
                $params['description'] = self::DBUTF8($link->description);
1407
                $params['category_id'] = $cat_id;
1408
                $params['on_homepage'] = $link->on_homepage;
1409
                $params['display_order'] = $max_order + 1;
1410
                $params['target'] = $link->target;
1411
1412
                $id = Database::insert($link_table, $params);
1413
1414
                if ($id) {
1415
                    $sql = "UPDATE $link_table SET id = iid WHERE iid = $id";
1416
                    Database::query($sql);
1417
1418
                    api_item_property_update(
1419
                        $this->destination_course_info,
1420
                        TOOL_LINK,
1421
                        $id,
1422
                        'LinkAdded',
1423
                        api_get_user_id(),
1424
                        null,
1425
                        null,
1426
                        null,
1427
                        null,
1428
                        $session_id
1429
                    );
1430
1431
                    if (!isset($this->course->resources[RESOURCE_LINK][$oldLinkId])) {
1432
                        $this->course->resources[RESOURCE_LINK][$oldLinkId] = new stdClass();
1433
                    }
1434
                    $this->course->resources[RESOURCE_LINK][$oldLinkId]->destination_id = $id;
1435
                }
1436
            }
1437
        }
1438
    }
1439
1440
    /**
1441
     * Restore a link-category.
1442
     *
1443
     * @param int
1444
     * @param int
1445
     *
1446
     * @return bool
1447
     */
1448
    public function restore_link_category($id, $sessionId = 0)
1449
    {
1450
        $params = [];
1451
        $sessionId = (int) $sessionId;
1452
        if (!empty($sessionId)) {
1453
            $params['session_id'] = $sessionId;
1454
        }
1455
1456
        if ($id == 0) {
1457
            return 0;
1458
        }
1459
        $link_cat_table = Database::get_course_table(TABLE_LINK_CATEGORY);
1460
        $resources = $this->course->resources;
1461
        $link_cat = $resources[RESOURCE_LINKCATEGORY][$id];
1462
        if (is_object($link_cat) && !$link_cat->is_restored()) {
1463
            $sql = "SELECT MAX(display_order) FROM  $link_cat_table
1464
                    WHERE c_id = ".$this->destination_course_id;
1465
            $result = Database::query($sql);
1466
            [$orderMax] = Database::fetch_array($result, 'NUM');
1467
            $display_order = $orderMax + 1;
1468
1469
            $params['c_id'] = $this->destination_course_id;
1470
            $params['category_title'] = self::DBUTF8($link_cat->title);
1471
            $params['description'] = self::DBUTF8($link_cat->description);
1472
            $params['display_order'] = $display_order;
1473
            $new_id = Database::insert($link_cat_table, $params);
1474
1475
            if ($new_id) {
1476
                $sql = "UPDATE $link_cat_table
1477
                        SET id = iid
1478
                        WHERE iid = $new_id";
1479
                Database::query($sql);
1480
1481
                $courseInfo = api_get_course_info_by_id($this->destination_course_id);
1482
                api_item_property_update(
1483
                    $courseInfo,
1484
                    TOOL_LINK_CATEGORY,
1485
                    $new_id,
1486
                    'LinkCategoryAdded',
1487
                    api_get_user_id(),
1488
                    null,
1489
                    null,
1490
                    null,
1491
                    null,
1492
                    $sessionId
1493
                );
1494
                api_set_default_visibility(
1495
                    $new_id,
1496
                    TOOL_LINK_CATEGORY,
1497
                    0,
1498
                    $courseInfo,
1499
                    $sessionId
1500
                );
1501
            }
1502
1503
            $this->course->resources[RESOURCE_LINKCATEGORY][$id]->destination_id = $new_id;
1504
1505
            return $new_id;
1506
        }
1507
1508
        return $this->course->resources[RESOURCE_LINKCATEGORY][$id]->destination_id;
1509
    }
1510
1511
    /**
1512
     * Restore tool intro.
1513
     *
1514
     * @param int
1515
     */
1516
    public function restore_tool_intro($sessionId = 0)
1517
    {
1518
        if ($this->course->has_resources(RESOURCE_TOOL_INTRO)) {
1519
            $sessionId = (int) $sessionId;
1520
            $tool_intro_table = Database::get_course_table(TABLE_TOOL_INTRO);
1521
            $resources = $this->course->resources;
1522
            foreach ($resources[RESOURCE_TOOL_INTRO] as $id => $tool_intro) {
1523
                if (!$this->copySessionContent) {
1524
                    $sql = "DELETE FROM $tool_intro_table
1525
                        WHERE
1526
                            c_id = ".$this->destination_course_id." AND
1527
                            id='".self::DBUTF8escapestring($tool_intro->id)."'";
1528
                    Database::query($sql);
1529
                }
1530
1531
                $tool_intro->intro_text = DocumentManager::replaceUrlWithNewCourseCode(
1532
                    $tool_intro->intro_text,
1533
                    $this->course->code,
1534
                    $this->course->destination_path,
1535
                    $this->course->backup_path,
1536
                    $this->course->info['path']
1537
                );
1538
1539
                $params = [
1540
                    'c_id' => $this->destination_course_id,
1541
                    'id' => ($tool_intro->id === false ? '' : self::DBUTF8($tool_intro->id)),
1542
                    'intro_text' => self::DBUTF8($tool_intro->intro_text),
1543
                    'session_id' => $sessionId,
1544
                ];
1545
1546
                $id = Database::insert($tool_intro_table, $params);
1547
                if ($id) {
1548
                    if (!isset($this->course->resources[RESOURCE_TOOL_INTRO][$id])) {
1549
                        $this->course->resources[RESOURCE_TOOL_INTRO][$id] = new stdClass();
1550
                    }
1551
1552
                    $this->course->resources[RESOURCE_TOOL_INTRO][$id]->destination_id = $id;
1553
                }
1554
            }
1555
        }
1556
    }
1557
1558
    /**
1559
     * Restore events.
1560
     *
1561
     * @param int
1562
     */
1563
    public function restore_events($sessionId = 0)
1564
    {
1565
        if ($this->course->has_resources(RESOURCE_EVENT)) {
1566
            $sessionId = (int) $sessionId;
1567
            $table = Database::get_course_table(TABLE_AGENDA);
1568
            $resources = $this->course->resources;
1569
            foreach ($resources[RESOURCE_EVENT] as $id => $event) {
1570
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
1571
                $event->content = DocumentManager::replaceUrlWithNewCourseCode(
1572
                    $event->content,
1573
                    $this->course->code,
1574
                    $this->course->destination_path,
1575
                    $this->course->backup_path,
1576
                    $this->course->info['path']
1577
                );
1578
1579
                $params = [
1580
                    'c_id' => $this->destination_course_id,
1581
                    'title' => self::DBUTF8($event->title),
1582
                    'content' => ($event->content === false ? '' : self::DBUTF8($event->content)),
1583
                    'all_day' => $event->all_day,
1584
                    'start_date' => $event->start_date,
1585
                    'end_date' => $event->end_date,
1586
                    'session_id' => $sessionId,
1587
                ];
1588
                $new_event_id = Database::insert($table, $params);
1589
1590
                if ($new_event_id) {
1591
                    $sql = "UPDATE $table SET id = iid WHERE iid = $new_event_id";
1592
                    Database::query($sql);
1593
1594
                    // Choose default visibility
1595
                    $toolVisibility = api_get_setting('tool_visible_by_default_at_creation');
1596
                    $defaultLpVisibility = 'invisible';
1597
                    if (isset($toolVisibility['learning_path']) && $toolVisibility['learning_path'] == 'true') {
1598
                        $defaultLpVisibility = 'visible';
1599
                    }
1600
1601
                    api_item_property_update(
1602
                        $this->destination_course_info,
1603
                        TOOL_CALENDAR_EVENT,
1604
                        $new_event_id,
1605
                        'AgendaAdded',
1606
                        api_get_user_id(),
1607
                        0,
1608
                        0,
1609
                        0,
1610
                        0,
1611
                        $sessionId
1612
                    );
1613
1614
                    // Set the new Agenda to visible
1615
                    api_item_property_update(
1616
                        $this->destination_course_info,
1617
                        TOOL_CALENDAR_EVENT,
1618
                        $new_event_id,
1619
                        $defaultLpVisibility,
1620
                        api_get_user_id(),
1621
                        0,
1622
                        0,
1623
                        0,
1624
                        0,
1625
                        $sessionId
1626
                    );
1627
1628
                    if (!isset($this->course->resources[RESOURCE_EVENT][$id])) {
1629
                        $this->course->resources[RESOURCE_EVENT][$id] = new stdClass();
1630
                    }
1631
                    $this->course->resources[RESOURCE_EVENT][$id]->destination_id = $new_event_id;
1632
                }
1633
1634
                // Copy event attachment
1635
                $origin_path = $this->course->backup_path.'/upload/calendar/';
1636
                $destination_path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/upload/calendar/';
1637
1638
                if (!empty($this->course->orig)) {
1639
                    $table_attachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
1640
                    $sql = 'SELECT path, comment, size, filename
1641
                            FROM '.$table_attachment.'
1642
                            WHERE c_id = '.$this->destination_course_id.' AND agenda_id = '.$id;
1643
                    $attachment_event = Database::query($sql);
1644
                    $attachment_event = Database::fetch_object($attachment_event);
1645
1646
                    if (file_exists($origin_path.$attachment_event->path) &&
1647
                        !is_dir($origin_path.$attachment_event->path)
1648
                    ) {
1649
                        $new_filename = uniqid(''); //ass seen in the add_agenda_attachment_file() function in agenda.inc.php
1650
                        $copy_result = copy(
1651
                            $origin_path.$attachment_event->path,
1652
                            $destination_path.$new_filename
1653
                        );
1654
                        //$copy_result = true;
1655
                        if ($copy_result) {
1656
                            $table_attachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
1657
1658
                            $params = [
1659
                                'c_id' => $this->destination_course_id,
1660
                                'path' => self::DBUTF8($new_filename),
1661
                                'comment' => self::DBUTF8($attachment_event->comment),
1662
                                'size' => isset($attachment_event->size) ? $attachment_event->size : '',
1663
                                'filename' => isset($attachment_event->filename) ? $attachment_event->filename : '',
1664
                                'agenda_id' => $new_event_id,
1665
                            ];
1666
                            $id = Database::insert($table_attachment, $params);
1667
                            if ($id) {
1668
                                $sql = "UPDATE $table_attachment SET id = iid WHERE iid = $id";
1669
                                Database::query($sql);
1670
                            }
1671
                        }
1672
                    }
1673
                } else {
1674
                    // get the info of the file
1675
                    if (!empty($event->attachment_path) &&
1676
                        is_file($origin_path.$event->attachment_path) &&
1677
                        is_readable($origin_path.$event->attachment_path)
1678
                    ) {
1679
                        $new_filename = uniqid(''); //ass seen in the add_agenda_attachment_file() function in agenda.inc.php
1680
                        $copy_result = copy(
1681
                            $origin_path.$event->attachment_path,
1682
                            $destination_path.$new_filename
1683
                        );
1684
                        if ($copy_result) {
1685
                            $table_attachment = Database::get_course_table(TABLE_AGENDA_ATTACHMENT);
1686
1687
                            $params = [
1688
                                'c_id' => $this->destination_course_id,
1689
                                'path' => self::DBUTF8($new_filename),
1690
                                'comment' => self::DBUTF8($event->attachment_comment),
1691
                                'size' => isset($event->attachment_size) ? $event->attachment_size : '',
1692
                                'filename' => isset($event->attachment_filename) ? $event->attachment_filename : '',
1693
                                'agenda_id' => $new_event_id,
1694
                            ];
1695
                            $id = Database::insert($table_attachment, $params);
1696
1697
                            if ($id) {
1698
                                $sql = "UPDATE $table_attachment SET id = iid WHERE iid = $id";
1699
                                Database::query($sql);
1700
1701
                                api_item_property_update(
1702
                                    $this->destination_course_info,
1703
                                    'calendar_event_attachment',
1704
                                    $id,
1705
                                    'AgendaAttachmentAdded',
1706
                                    api_get_user_id()
1707
                                );
1708
                            }
1709
                        }
1710
                    }
1711
                }
1712
            }
1713
        }
1714
    }
1715
1716
    /**
1717
     * Restore course-description.
1718
     *
1719
     * @param int
1720
     */
1721
    public function restore_course_descriptions($session_id = 0)
1722
    {
1723
        if ($this->course->has_resources(RESOURCE_COURSEDESCRIPTION)) {
1724
            $table = Database::get_course_table(TABLE_COURSE_DESCRIPTION);
1725
            $resources = $this->course->resources;
1726
            foreach ($resources[RESOURCE_COURSEDESCRIPTION] as $id => $cd) {
1727
                $courseDescription = (array) $cd;
1728
1729
                $content = isset($courseDescription['content']) ? $courseDescription['content'] : '';
1730
                $descriptionType = isset($courseDescription['description_type']) ? $courseDescription['description_type'] : '';
1731
                $title = isset($courseDescription['title']) ? $courseDescription['title'] : '';
1732
1733
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
1734
                $description_content = DocumentManager::replaceUrlWithNewCourseCode(
1735
                    $content,
1736
                    $this->course->code,
1737
                    $this->course->destination_path,
1738
                    $this->course->backup_path,
1739
                    $this->course->info['path']
1740
                );
1741
1742
                $params = [];
1743
                $session_id = (int) $session_id;
1744
                $params['session_id'] = $session_id;
1745
                $params['c_id'] = $this->destination_course_id;
1746
                $params['description_type'] = self::DBUTF8($descriptionType);
1747
                $params['title'] = self::DBUTF8($title);
1748
                $params['content'] = ($description_content === false ? '' : self::DBUTF8($description_content));
1749
                $params['progress'] = 0;
1750
1751
                $id = Database::insert($table, $params);
1752
                if ($id) {
1753
                    $sql = "UPDATE $table SET id = iid WHERE iid = $id";
1754
                    Database::query($sql);
1755
1756
                    if (!isset($this->course->resources[RESOURCE_COURSEDESCRIPTION][$id])) {
1757
                        $this->course->resources[RESOURCE_COURSEDESCRIPTION][$id] = new stdClass();
1758
                    }
1759
                    $this->course->resources[RESOURCE_COURSEDESCRIPTION][$id]->destination_id = $id;
1760
                }
1761
            }
1762
        }
1763
    }
1764
1765
    /**
1766
     * Restore announcements.
1767
     *
1768
     * @param int
1769
     */
1770
    public function restore_announcements($sessionId = 0)
1771
    {
1772
        if ($this->course->has_resources(RESOURCE_ANNOUNCEMENT)) {
1773
            $sessionId = (int) $sessionId;
1774
            $table = Database::get_course_table(TABLE_ANNOUNCEMENT);
1775
            $resources = $this->course->resources;
1776
            foreach ($resources[RESOURCE_ANNOUNCEMENT] as $id => $announcement) {
1777
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
1778
                $announcement->content = DocumentManager::replaceUrlWithNewCourseCode(
1779
                    $announcement->content,
1780
                    $this->course->code,
1781
                    $this->course->destination_path,
1782
                    $this->course->backup_path,
1783
                    $this->course->info['path']
1784
                );
1785
1786
                $params = [
1787
                    'c_id' => $this->destination_course_id,
1788
                    'title' => self::DBUTF8($announcement->title),
1789
                    'content' => ($announcement->content === false ? '' : self::DBUTF8($announcement->content)),
1790
                    'end_date' => $announcement->date,
1791
                    'display_order' => $announcement->display_order,
1792
                    'email_sent' => $announcement->email_sent,
1793
                    'session_id' => $sessionId,
1794
                ];
1795
1796
                $new_announcement_id = Database::insert($table, $params);
1797
1798
                if ($new_announcement_id) {
1799
                    $sql = "UPDATE $table SET id = iid WHERE iid = $new_announcement_id";
1800
                    Database::query($sql);
1801
1802
                    if (!isset($this->course->resources[RESOURCE_ANNOUNCEMENT][$id])) {
1803
                        $this->course->resources[RESOURCE_ANNOUNCEMENT][$id] = new stdClass();
1804
                    }
1805
                    $this->course->resources[RESOURCE_ANNOUNCEMENT][$id]->destination_id = $new_announcement_id;
1806
                }
1807
1808
                $origin_path = $this->course->backup_path.'/upload/announcements/';
1809
                $destination_path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/upload/announcements/';
1810
1811
                // Copy announcement attachment file
1812
                if (!empty($this->course->orig)) {
1813
                    $table_attachment = Database::get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
1814
                    $sql = 'SELECT path, comment, size, filename
1815
                            FROM '.$table_attachment.'
1816
                            WHERE
1817
                                c_id = '.$this->destination_course_id.' AND
1818
                                announcement_id = '.$id;
1819
                    $attachment_event = Database::query($sql);
1820
                    $attachment_event = Database::fetch_object($attachment_event);
1821
1822
                    if (file_exists($origin_path.$attachment_event->path) &&
1823
                        !is_dir($origin_path.$attachment_event->path)
1824
                    ) {
1825
                        $new_filename = uniqid(''); //ass seen in the add_agenda_attachment_file() function in agenda.inc.php
1826
                        $copy_result = copy(
1827
                            $origin_path.$attachment_event->path,
1828
                            $destination_path.$new_filename
1829
                        );
1830
1831
                        if ($copy_result) {
1832
                            $table_attachment = Database::get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
1833
1834
                            $params = [
1835
                                'c_id' => $this->destination_course_id,
1836
                                'path' => self::DBUTF8($new_filename),
1837
                                'comment' => self::DBUTF8($attachment_event->comment),
1838
                                'size' => $attachment_event->size,
1839
                                'filename' => $attachment_event->filename,
1840
                                'announcement_id' => $new_announcement_id,
1841
                            ];
1842
1843
                            $attachmentId = Database::insert($table_attachment, $params);
1844
1845
                            if ($attachmentId) {
1846
                                $sql = "UPDATE $table_attachment SET id = iid WHERE iid = $attachmentId";
1847
                                Database::query($sql);
1848
                            }
1849
                        }
1850
                    }
1851
                } else {
1852
                    // get the info of the file
1853
                    if (!empty($announcement->attachment_path) &&
1854
                        is_file($origin_path.$announcement->attachment_path) &&
1855
                        is_readable($origin_path.$announcement->attachment_path)
1856
                    ) {
1857
                        $new_filename = uniqid(''); //ass seen in the add_agenda_attachment_file() function in agenda.inc.php
1858
                        $copy_result = copy($origin_path.$announcement->attachment_path, $destination_path.$new_filename);
1859
1860
                        if ($copy_result) {
1861
                            $table_attachment = Database::get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
1862
1863
                            $params = [
1864
                                'c_id' => $this->destination_course_id,
1865
                                'path' => self::DBUTF8($new_filename),
1866
                                'comment' => self::DBUTF8($announcement->attachment_comment),
1867
                                'size' => $announcement->attachment_size,
1868
                                'filename' => $announcement->attachment_filename,
1869
                                'announcement_id' => $new_announcement_id,
1870
                            ];
1871
1872
                            $attachmentId = Database::insert($table_attachment, $params);
1873
1874
                            if ($attachmentId) {
1875
                                $sql = "UPDATE $table_attachment SET id = iid WHERE iid = $attachmentId";
1876
                                Database::query($sql);
1877
                            }
1878
                        }
1879
                    }
1880
                }
1881
            }
1882
        }
1883
    }
1884
1885
    /**
1886
     * Restore Quiz.
1887
     *
1888
     * @param int  $session_id
1889
     * @param bool $respect_base_content
1890
     */
1891
    public function restore_quizzes(
1892
        $session_id = 0,
1893
        $respect_base_content = false
1894
    ) {
1895
        if ($this->course->has_resources(RESOURCE_QUIZ)) {
1896
            $table_qui = Database::get_course_table(TABLE_QUIZ_TEST);
1897
            $table_rel = Database::get_course_table(TABLE_QUIZ_TEST_QUESTION);
1898
            $table_doc = Database::get_course_table(TABLE_DOCUMENT);
1899
            $resources = $this->course->resources;
1900
            // Check if the "id" column still exists
1901
            $idColumn = true;
1902
            $columns = Database::listTableColumns($table_qui);
1903
            if (!in_array('id', array_keys($columns))) {
1904
                $idColumn = false;
1905
            }
1906
1907
            foreach ($resources[RESOURCE_QUIZ] as $id => $quiz) {
1908
                if (isset($quiz->obj)) {
1909
                    // For new imports
1910
                    $quiz = $quiz->obj;
1911
                } else {
1912
                    // For backward compatibility
1913
                    $quiz->obj = $quiz;
1914
                }
1915
1916
                $doc = '';
1917
                if (!empty($quiz->sound)) {
1918
                    if (isset($this->course->resources[RESOURCE_DOCUMENT][$quiz->sound]) &&
1919
                        $this->course->resources[RESOURCE_DOCUMENT][$quiz->sound]->is_restored()) {
1920
                        $sql = "SELECT path FROM $table_doc
1921
                                WHERE
1922
                                    c_id = ".$this->destination_course_id." AND
1923
                                    id = ".$resources[RESOURCE_DOCUMENT][$quiz->sound]->destination_id;
1924
                        $doc = Database::query($sql);
1925
                        $doc = Database::fetch_object($doc);
1926
                        $doc = str_replace('/audio/', '', $doc->path);
1927
                    }
1928
                }
1929
1930
                if ($id != -1) {
1931
                    // check resources inside html from ckeditor tool and copy correct urls into recipient course
1932
                    $quiz->description = DocumentManager::replaceUrlWithNewCourseCode(
1933
                        $quiz->description,
1934
                        $this->course->code,
1935
                        $this->course->destination_path,
1936
                        $this->course->backup_path,
1937
                        $this->course->info['path']
1938
                    );
1939
1940
                    $quiz->start_time = $quiz->start_time == '0000-00-00 00:00:00' ? null : $quiz->start_time;
1941
                    $quiz->end_time = $quiz->end_time == '0000-00-00 00:00:00' ? null : $quiz->end_time;
1942
1943
                    global $_custom;
1944
                    if (isset($_custom['exercises_clean_dates_when_restoring']) &&
1945
                        $_custom['exercises_clean_dates_when_restoring']
1946
                    ) {
1947
                        $quiz->start_time = null;
1948
                        $quiz->end_time = null;
1949
                    }
1950
1951
                    $params = [
1952
                        'c_id' => $this->destination_course_id,
1953
                        'title' => self::DBUTF8($quiz->title),
1954
                        'description' => ($quiz->description === false ? '' : self::DBUTF8($quiz->description)),
1955
                        'type' => isset($quiz->quiz_type) ? (int) $quiz->quiz_type : $quiz->type,
1956
                        'random' => (int) $quiz->random,
1957
                        'active' => $quiz->active,
1958
                        'sound' => self::DBUTF8($doc),
1959
                        'max_attempt' => (int) $quiz->max_attempt,
1960
                        'results_disabled' => (int) $quiz->results_disabled,
1961
                        'access_condition' => $quiz->access_condition,
1962
                        'pass_percentage' => $quiz->pass_percentage,
1963
                        'feedback_type' => (int) $quiz->feedback_type,
1964
                        'random_answers' => (int) $quiz->random_answers,
1965
                        'random_by_category' => (int) $quiz->random_by_category,
1966
                        'review_answers' => (int) $quiz->review_answers,
1967
                        'propagate_neg' => (int) $quiz->propagate_neg,
1968
                        'text_when_finished' => (string) $quiz->text_when_finished,
1969
                        'expired_time' => (int) $quiz->expired_time,
1970
                        'start_time' => $quiz->start_time,
1971
                        'end_time' => $quiz->end_time,
1972
                        'display_category_name' => 0,
1973
                        'save_correct_answers' => isset($quiz->save_correct_answers) ? $quiz->save_correct_answers : 0,
1974
                        'hide_question_title' => isset($quiz->hide_question_title) ? $quiz->hide_question_title : 0,
1975
                    ];
1976
1977
                    if (true === api_get_configuration_value('exercise_text_when_finished_failure')) {
1978
                        $params['text_when_finished_failure'] = (string) $quiz->text_when_finished_failure;
1979
                    }
1980
1981
                    $allow = api_get_configuration_value('allow_notification_setting_per_exercise');
1982
                    if ($allow) {
1983
                        $params['notifications'] = isset($quiz->notifications) ? $quiz->notifications : '';
1984
                    }
1985
1986
                    if ($respect_base_content) {
1987
                        $my_session_id = $quiz->session_id;
1988
                        if (!empty($quiz->session_id)) {
1989
                            $my_session_id = $session_id;
1990
                        }
1991
                        $params['session_id'] = $my_session_id;
1992
                    } else {
1993
                        if (!empty($session_id)) {
1994
                            $session_id = (int) $session_id;
1995
                            $params['session_id'] = $session_id;
1996
                        }
1997
                    }
1998
                    $new_id = Database::insert($table_qui, $params);
1999
2000
                    if ($new_id && $idColumn) {
2001
                        $sql = "UPDATE $table_qui SET id = iid WHERE iid = $new_id";
2002
                        Database::query($sql);
2003
                    }
2004
                } else {
2005
                    // $id = -1 identifies the fictional test for collecting
2006
                    // orphan questions. We do not store it in the database.
2007
                    $new_id = -1;
2008
                }
2009
2010
                $this->course->resources[RESOURCE_QUIZ][$id]->destination_id = $new_id;
2011
                $order = 0;
2012
                if (!empty($quiz->question_ids)) {
2013
                    foreach ($quiz->question_ids as $index => $question_id) {
2014
                        $qid = $this->restore_quiz_question($question_id, $idColumn);
2015
                        $question_order = $quiz->question_orders[$index] ? $quiz->question_orders[$index] : ++$order;
2016
                        $sql = "INSERT IGNORE INTO $table_rel SET
2017
                                c_id = ".$this->destination_course_id.",
2018
                                question_id = $qid ,
2019
                                exercice_id = $new_id ,
2020
                                question_order = ".$question_order;
2021
                        Database::query($sql);
2022
                    }
2023
                }
2024
            }
2025
        }
2026
    }
2027
2028
    /**
2029
     * Restore quiz-questions.
2030
     *
2031
     * @param int  $id       Question id
2032
     * @param bool $idColumn Whether the 'id' column still exists in this table
2033
     */
2034
    public function restore_quiz_question($id, $idColumn = true)
2035
    {
2036
        $em = Database::getManager();
2037
        $resources = $this->course->resources;
2038
        /** @var QuizQuestion $question */
2039
        $question = isset($resources[RESOURCE_QUIZQUESTION][$id]) ? $resources[RESOURCE_QUIZQUESTION][$id] : null;
2040
        $new_id = 0;
2041
2042
        if (is_object($question)) {
2043
            if ($question->is_restored()) {
2044
                return $question->destination_id;
2045
            }
2046
            $table_que = Database::get_course_table(TABLE_QUIZ_QUESTION);
2047
            $table_ans = Database::get_course_table(TABLE_QUIZ_ANSWER);
2048
            $table_options = Database::get_course_table(TABLE_QUIZ_QUESTION_OPTION);
2049
2050
            // check resources inside html from ckeditor tool and copy correct urls into recipient course
2051
            $question->description = DocumentManager::replaceUrlWithNewCourseCode(
2052
                $question->description,
2053
                $this->course->code,
2054
                $this->course->destination_path,
2055
                $this->course->backup_path,
2056
                $this->course->info['path']
2057
            );
2058
2059
            $imageNewId = '';
2060
            if (preg_match('/^quiz-.*$/', $question->picture) &&
2061
                isset($resources[RESOURCE_DOCUMENT]['image_quiz'][$question->picture])
2062
            ) {
2063
                $imageNewId = $resources[RESOURCE_DOCUMENT]['image_quiz'][$question->picture]['destination_id'];
2064
            } else {
2065
                if (isset($resources[RESOURCE_DOCUMENT][$question->picture])) {
2066
                    $documentsToRestore = $resources[RESOURCE_DOCUMENT][$question->picture];
2067
                    $imageNewId = $documentsToRestore->destination_id;
2068
                }
2069
            }
2070
            $question->question = DocumentManager::replaceUrlWithNewCourseCode(
2071
                $question->question,
2072
                $this->course->code,
2073
                $this->course->destination_path,
2074
                $this->course->backup_path,
2075
                $this->course->info['path']
2076
            );
2077
            $params = [
2078
                'c_id' => $this->destination_course_id,
2079
                'question' => self::DBUTF8($question->question),
2080
                'description' => ($question->description === false ? '' : self::DBUTF8($question->description)),
2081
                'ponderation' => self::DBUTF8($question->ponderation),
2082
                'position' => self::DBUTF8($question->position),
2083
                'type' => self::DBUTF8($question->quiz_type),
2084
                'picture' => self::DBUTF8($imageNewId),
2085
                'level' => self::DBUTF8($question->level),
2086
                'extra' => self::DBUTF8($question->extra),
2087
            ];
2088
2089
            $new_id = Database::insert($table_que, $params);
2090
2091
            if ($new_id) {
2092
                // If the ID column is still present, update it, otherwise just
2093
                // continue
2094
                if ($idColumn) {
2095
                    $sql = "UPDATE $table_que SET id = iid WHERE iid = $new_id";
2096
                    Database::query($sql);
2097
                }
2098
            } else {
2099
                // If no IID was generated, stop right there and return 0
2100
                return 0;
2101
            }
2102
2103
            $correctAnswers = [];
2104
            $allAnswers = [];
2105
            $onlyAnswers = [];
2106
2107
            if (in_array($question->quiz_type, [DRAGGABLE, MATCHING, MATCHING_DRAGGABLE])) {
2108
                $tempAnswerList = $question->answers;
2109
                foreach ($tempAnswerList as &$value) {
2110
                    $value['answer'] = DocumentManager::replaceUrlWithNewCourseCode(
2111
                        $value['answer'],
2112
                        $this->course->code,
2113
                        $this->course->destination_path,
2114
                        $this->course->backup_path,
2115
                        $this->course->info['path']
2116
                    );
2117
                }
2118
                $allAnswers = array_column($tempAnswerList, 'answer', 'id');
2119
            }
2120
2121
            if (in_array($question->quiz_type, [MATCHING, MATCHING_DRAGGABLE])) {
2122
                $temp = [];
2123
                foreach ($question->answers as $index => $answer) {
2124
                    $temp[$answer['position']] = $answer;
2125
                }
2126
2127
                foreach ($temp as $index => $answer) {
2128
                    // check resources inside html from ckeditor tool and copy correct urls into recipient course
2129
                    $answer['answer'] = DocumentManager::replaceUrlWithNewCourseCode(
2130
                        $answer['answer'],
2131
                        $this->course->code,
2132
                        $this->course->destination_path,
2133
                        $this->course->backup_path,
2134
                        $this->course->info['path']
2135
                    );
2136
2137
                    $answer['comment'] = DocumentManager::replaceUrlWithNewCourseCode(
2138
                        $answer['comment'],
2139
                        $this->course->code,
2140
                        $this->course->destination_path,
2141
                        $this->course->backup_path,
2142
                        $this->course->info['path']
2143
                    );
2144
2145
                    $quizAnswer = new CQuizAnswer();
2146
                    $quizAnswer
2147
                        ->setCId($this->destination_course_id)
2148
                        ->setQuestionId($new_id)
2149
                        ->setAnswer(self::DBUTF8($answer['answer']))
2150
                        ->setCorrect($answer['correct'])
2151
                        ->setComment($answer['comment'] === false ? '' : self::DBUTF8($answer['comment']))
2152
                        ->setPonderation($answer['ponderation'])
2153
                        ->setPosition($answer['position'])
2154
                        ->setHotspotCoordinates($answer['hotspot_coordinates'])
2155
                        ->setHotspotType($answer['hotspot_type'])
2156
                        ->setIdAuto(0);
2157
2158
                    $em->persist($quizAnswer);
2159
                    $em->flush();
2160
2161
                    $answerId = $quizAnswer->getId();
2162
2163
                    if ($answerId) {
2164
                        $quizAnswer
2165
                            ->setId($answerId)
2166
                            ->setIdAuto($answerId);
2167
                        $em->merge($quizAnswer);
2168
                        $em->flush();
2169
2170
                        $correctAnswers[$answerId] = $answer['correct'];
2171
                        $onlyAnswers[$answerId] = $answer['answer'];
2172
                    }
2173
                }
2174
            } else {
2175
                foreach ($question->answers as $index => $answer) {
2176
                    // check resources inside html from ckeditor tool and copy correct urls into recipient course
2177
                    $answer['answer'] = DocumentManager::replaceUrlWithNewCourseCode(
2178
                        $answer['answer'],
2179
                        $this->course->code,
2180
                        $this->course->destination_path,
2181
                        $this->course->backup_path,
2182
                        $this->course->info['path']
2183
                    );
2184
2185
                    $answer['comment'] = DocumentManager::replaceUrlWithNewCourseCode(
2186
                        $answer['comment'],
2187
                        $this->course->code,
2188
                        $this->course->destination_path,
2189
                        $this->course->backup_path,
2190
                        $this->course->info['path']
2191
                    );
2192
2193
                    $params = [
2194
                        'c_id' => $this->destination_course_id,
2195
                        'question_id' => $new_id,
2196
                        'answer' => self::DBUTF8($answer['answer']),
2197
                        'correct' => $answer['correct'],
2198
                        'comment' => ($answer['comment'] === false ? '' : self::DBUTF8($answer['comment'])),
2199
                        'ponderation' => $answer['ponderation'],
2200
                        'position' => $answer['position'],
2201
                        'hotspot_coordinates' => $answer['hotspot_coordinates'],
2202
                        'hotspot_type' => $answer['hotspot_type'],
2203
                        'id_auto' => 0,
2204
                        'destination' => '',
2205
                    ];
2206
2207
                    $answerId = Database::insert($table_ans, $params);
2208
2209
                    if ($answerId) {
2210
                        if ($idColumn) {
2211
                            $sql = "UPDATE $table_ans SET id = iid, id_auto = iid WHERE iid = $answerId";
2212
                            Database::query($sql);
2213
                        } else {
2214
                            $sql = "UPDATE $table_ans SET id_auto = iid WHERE iid = $answerId";
2215
                            Database::query($sql);
2216
                        }
2217
                    }
2218
2219
                    $correctAnswers[$answerId] = $answer['correct'];
2220
                    $onlyAnswers[$answerId] = $answer['answer'];
2221
                }
2222
            }
2223
2224
            // Current course id
2225
            $course_id = api_get_course_int_id();
2226
2227
            // Moving quiz_question_options
2228
            if ($question->quiz_type == MULTIPLE_ANSWER_TRUE_FALSE) {
2229
                if (count($question->question_options) < 3) {
2230
                    $options = [1 => 'True', 2 => 'False', 3 => 'DoubtScore'];
2231
                    $correct = [];
2232
                    for ($i = 1; $i <= 3; $i++) {
2233
                        $lastId = Question::saveQuestionOption(
2234
                            $new_id,
2235
                            $options[$i],
2236
                            $this->destination_course_id,
2237
                            $i
2238
                        );
2239
                        $correct[$i] = $lastId;
2240
                    }
2241
2242
                    $correctAnswerValues = Database::select(
2243
                        'DISTINCT(correct)',
2244
                        $table_ans,
2245
                        [
2246
                            'WHERE' => [
2247
                                'question_id = ? AND c_id = ? ' => [
2248
                                    $new_id,
2249
                                    $this->destination_course_id,
2250
                                ],
2251
                            ],
2252
                            'ORDER' => 'correct ASC',
2253
                        ]
2254
                    );
2255
                    $i = 1;
2256
                    foreach ($correctAnswerValues as $correctAnswer) {
2257
                        $params = [];
2258
                        $params['correct'] = $correct[$i];
2259
                        Database::update(
2260
                            $table_ans,
2261
                            $params,
2262
                            [
2263
                                'question_id = ? AND c_id = ? AND correct = ? ' => [
2264
                                    $new_id,
2265
                                    $this->destination_course_id,
2266
                                    $correctAnswer['correct'],
2267
                                ],
2268
                            ],
2269
                            false
2270
                        );
2271
                        $i++;
2272
                    }
2273
                } else {
2274
                    $question_option_list = Question::readQuestionOption($id, $course_id);
2275
2276
                    // Question copied from the current platform
2277
                    if ($question_option_list) {
2278
                        $old_option_ids = [];
2279
                        foreach ($question_option_list as $item) {
2280
                            if (isset($item['iid'])) {
2281
                                $old_id = $item['iid'];
2282
                                unset($item['iid']);
2283
                                unset($item['id']);
2284
                            } else {
2285
                                $old_id = $item['id'];
2286
                                unset($item['id']);
2287
                            }
2288
                            $item['question_id'] = $new_id;
2289
                            $item['c_id'] = $this->destination_course_id;
2290
                            $question_option_id = Database::insert($table_options, $item);
2291
                            if ($question_option_id && $idColumn) {
2292
                                $old_option_ids[$old_id] = $question_option_id;
2293
                                $sql = "UPDATE $table_options SET id = iid WHERE iid = $question_option_id";
2294
                                Database::query($sql);
2295
                            }
2296
                        }
2297
                        if ($old_option_ids) {
2298
                            $new_answers = Database::select(
2299
                                'iid, correct',
2300
                                $table_ans,
2301
                                [
2302
                                    'WHERE' => [
2303
                                        'question_id = ? AND c_id = ? ' => [
2304
                                            $new_id,
2305
                                            $this->destination_course_id,
2306
                                        ],
2307
                                    ],
2308
                                ]
2309
                            );
2310
2311
                            foreach ($new_answers as $answer_item) {
2312
                                $params = [];
2313
                                $params['correct'] = $old_option_ids[$answer_item['correct']];
2314
                                Database::update(
2315
                                    $table_ans,
2316
                                    $params,
2317
                                    [
2318
                                        'iid = ? AND c_id = ? AND question_id = ? ' => [
2319
                                            $answer_item['iid'],
2320
                                            $this->destination_course_id,
2321
                                            $new_id,
2322
                                        ],
2323
                                    ],
2324
                                    false
2325
                                );
2326
                            }
2327
                        }
2328
                    } else {
2329
                        $new_options = [];
2330
                        if (isset($question->question_options)) {
2331
                            foreach ($question->question_options as $obj) {
2332
                                $item = [];
2333
                                $item['question_id'] = $new_id;
2334
                                $item['c_id'] = $this->destination_course_id;
2335
                                $item['name'] = $obj->obj->name;
2336
                                $item['position'] = $obj->obj->position;
2337
                                $question_option_id = Database::insert($table_options, $item);
2338
2339
                                if ($question_option_id) {
2340
                                    $new_options[$obj->obj->id] = $question_option_id;
2341
                                    $sql = "UPDATE $table_options SET id = iid WHERE iid = $question_option_id";
2342
                                    Database::query($sql);
2343
                                }
2344
                            }
2345
2346
                            foreach ($correctAnswers as $answer_id => $correct_answer) {
2347
                                $params = [];
2348
                                $params['correct'] = isset($new_options[$correct_answer]) ? $new_options[$correct_answer] : '';
2349
                                Database::update(
2350
                                    $table_ans,
2351
                                    $params,
2352
                                    [
2353
                                        'iid = ? AND c_id = ? AND question_id = ? ' => [
2354
                                            $answer_id,
2355
                                            $this->destination_course_id,
2356
                                            $new_id,
2357
                                        ],
2358
                                    ],
2359
                                    false
2360
                                );
2361
                            }
2362
                        }
2363
                    }
2364
                }
2365
            }
2366
2367
            // Fix correct answers
2368
            if (in_array($question->quiz_type, [DRAGGABLE, MATCHING, MATCHING_DRAGGABLE])) {
2369
                foreach ($correctAnswers as $answer_id => $correct_answer) {
2370
                    $params = [];
2371
2372
                    if (isset($allAnswers[$correct_answer])) {
2373
                        $correct = '';
2374
                        foreach ($onlyAnswers as $key => $value) {
2375
                            if ($value == $allAnswers[$correct_answer]) {
2376
                                $correct = $key;
2377
                                break;
2378
                            }
2379
                        }
2380
2381
                        $params['correct'] = $correct;
2382
                        Database::update(
2383
                            $table_ans,
2384
                            $params,
2385
                            [
2386
                                'iid = ? AND c_id = ? AND question_id = ? ' => [
2387
                                    $answer_id,
2388
                                    $this->destination_course_id,
2389
                                    $new_id,
2390
                                ],
2391
                            ]
2392
                        );
2393
                    }
2394
                }
2395
            }
2396
2397
            $this->course->resources[RESOURCE_QUIZQUESTION][$id]->destination_id = $new_id;
2398
        }
2399
2400
        return $new_id;
2401
    }
2402
2403
    /**
2404
     * @todo : add session id when used for session
2405
     */
2406
    public function restore_test_category($session_id, $respect_base_content, $destination_course_code)
2407
    {
2408
        // Cannot restore a test category to a session.
2409
        if (!empty($session_id)) {
2410
            return false;
2411
        }
2412
2413
        $destinationCourseId = $this->destination_course_info['real_id'];
2414
        // Let's restore the categories
2415
        $categoryOldVsNewList = []; // used to build the quiz_question_rel_category table
2416
        if ($this->course->has_resources(RESOURCE_TEST_CATEGORY)) {
2417
            $resources = $this->course->resources;
2418
            foreach ($resources[RESOURCE_TEST_CATEGORY] as $id => $courseCopyTestCategory) {
2419
                $categoryOldVsNewList[$courseCopyTestCategory->source_id] = $id;
2420
                // check if this test_category already exist in the destination BDD
2421
                // do not Database::escape_string $title and $description, it will be done later
2422
                $title = $courseCopyTestCategory->title;
2423
                $description = $courseCopyTestCategory->description;
2424
                if (TestCategory::categoryTitleExists($title, $destinationCourseId)) {
2425
                    switch ($this->file_option) {
2426
                        case FILE_SKIP:
2427
                            //Do nothing
2428
                            break;
2429
                        case FILE_RENAME:
2430
                            $new_title = $title.'_';
2431
                            while (TestCategory::categoryTitleExists($new_title, $destinationCourseId)) {
2432
                                $new_title .= '_';
2433
                            }
2434
                            $test_category = new TestCategory();
2435
                            $test_category->name = $new_title;
2436
                            $test_category->description = $description;
2437
                            $new_id = $test_category->save($destinationCourseId);
2438
                            $categoryOldVsNewList[$courseCopyTestCategory->source_id] = $new_id;
2439
                            break;
2440
                        case FILE_OVERWRITE:
2441
                            // get category from source
2442
                            $destinationCategoryId = TestCategory::get_category_id_for_title(
2443
                                $title,
2444
                                $destinationCourseId
2445
                            );
2446
                            if ($destinationCategoryId) {
2447
                                $my_cat = new TestCategory();
2448
                                $my_cat = $my_cat->getCategory($destinationCategoryId, $destinationCourseId);
2449
                                $my_cat->name = $title;
2450
                                $my_cat->description = $description;
2451
                                $my_cat->modifyCategory($destinationCourseId);
2452
                                $categoryOldVsNewList[$courseCopyTestCategory->source_id] = $destinationCategoryId;
2453
                            }
2454
                            break;
2455
                    }
2456
                } else {
2457
                    // create a new test_category
2458
                    $test_category = new TestCategory();
2459
                    $test_category->name = $title;
2460
                    $test_category->description = $description;
2461
                    $new_id = $test_category->save($destinationCourseId);
2462
                    $categoryOldVsNewList[$courseCopyTestCategory->source_id] = $new_id;
2463
                }
2464
                $this->course->resources[RESOURCE_TEST_CATEGORY][$id]->destination_id = $categoryOldVsNewList[$courseCopyTestCategory->source_id];
2465
            }
2466
        }
2467
2468
        // lets check if quizzes-question are restored too,
2469
        // to redo the link between test_category and quizzes question for questions restored
2470
        // we can use the source_id field
2471
        // question source_id => category source_id
2472
        if ($this->course->has_resources(RESOURCE_QUIZQUESTION)) {
2473
            // check the category number of each question restored
2474
            if (!empty($resources[RESOURCE_QUIZQUESTION])) {
2475
                foreach ($resources[RESOURCE_QUIZQUESTION] as $id => $courseCopyQuestion) {
2476
                    $newQuestionId = $resources[RESOURCE_QUIZQUESTION][$id]->destination_id;
2477
                    $questionCategoryId = $courseCopyQuestion->question_category;
2478
                    if ($newQuestionId > 0 &&
2479
                        $questionCategoryId > 0 &&
2480
                        isset($categoryOldVsNewList[$questionCategoryId])
2481
                    ) {
2482
                        TestCategory::addCategoryToQuestion(
2483
                            $categoryOldVsNewList[$questionCategoryId],
2484
                            $newQuestionId,
2485
                            $destinationCourseId
2486
                        );
2487
                    }
2488
                }
2489
            }
2490
        }
2491
    }
2492
2493
    /**
2494
     * Restore surveys.
2495
     *
2496
     * @param int $sessionId Optional. The session id
2497
     */
2498
    public function restore_surveys($sessionId = 0)
2499
    {
2500
        $sessionId = (int) $sessionId;
2501
        if ($this->course->has_resources(RESOURCE_SURVEY)) {
2502
            $table_sur = Database::get_course_table(TABLE_SURVEY);
2503
            $table_que = Database::get_course_table(TABLE_SURVEY_QUESTION);
2504
            $table_ans = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
2505
            $resources = $this->course->resources;
2506
            foreach ($resources[RESOURCE_SURVEY] as $id => $survey) {
2507
                $sql = 'SELECT survey_id FROM '.$table_sur.'
2508
                        WHERE
2509
                            c_id = '.$this->destination_course_id.' AND
2510
                            code = "'.self::DBUTF8escapestring($survey->code).'" AND
2511
                            lang = "'.self::DBUTF8escapestring($survey->lang).'" ';
2512
2513
                $result_check = Database::query($sql);
2514
2515
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
2516
                $survey->title = DocumentManager::replaceUrlWithNewCourseCode(
2517
                    $survey->title,
2518
                    $this->course->code,
2519
                    $this->course->destination_path,
2520
                    $this->course->backup_path,
2521
                    $this->course->info['path']
2522
                );
2523
2524
                $survey->subtitle = DocumentManager::replaceUrlWithNewCourseCode(
2525
                    $survey->subtitle,
2526
                    $this->course->code,
2527
                    $this->course->destination_path,
2528
                    $this->course->backup_path,
2529
                    $this->course->info['path']
2530
                );
2531
2532
                $survey->intro = DocumentManager::replaceUrlWithNewCourseCode(
2533
                    $survey->intro,
2534
                    $this->course->code,
2535
                    $this->course->destination_path,
2536
                    $this->course->backup_path,
2537
                    $this->course->info['path']
2538
                );
2539
2540
                $survey->surveythanks = DocumentManager::replaceUrlWithNewCourseCode(
2541
                    $survey->surveythanks,
2542
                    $this->course->code,
2543
                    $this->course->destination_path,
2544
                    $this->course->backup_path,
2545
                    $this->course->info['path']
2546
                );
2547
2548
                $params = [
2549
                    'c_id' => $this->destination_course_id,
2550
                    'code' => self::DBUTF8($survey->code),
2551
                    'title' => ($survey->title === false ? '' : self::DBUTF8($survey->title)),
2552
                    'subtitle' => ($survey->subtitle === false ? '' : self::DBUTF8($survey->subtitle)),
2553
                    'author' => self::DBUTF8($survey->author),
2554
                    'lang' => self::DBUTF8($survey->lang),
2555
                    'avail_from' => self::DBUTF8($survey->avail_from),
2556
                    'avail_till' => self::DBUTF8($survey->avail_till),
2557
                    'is_shared' => self::DBUTF8($survey->is_shared),
2558
                    'template' => self::DBUTF8($survey->template),
2559
                    'intro' => $survey->intro === false ? '' : self::DBUTF8($survey->intro),
2560
                    'surveythanks' => $survey->surveythanks === false ? '' : self::DBUTF8($survey->surveythanks),
2561
                    'creation_date' => self::DBUTF8($survey->creation_date),
2562
                    'invited' => '0',
2563
                    'answered' => '0',
2564
                    'invite_mail' => self::DBUTF8($survey->invite_mail),
2565
                    'reminder_mail' => self::DBUTF8($survey->reminder_mail),
2566
                    'session_id' => $sessionId,
2567
                    'one_question_per_page' => isset($survey->one_question_per_page) ? $survey->one_question_per_page : 0,
2568
                    'shuffle' => isset($survey->suffle) ? $survey->suffle : 0,
2569
                ];
2570
2571
                // An existing survey exists with the same code and the same language
2572
                if (Database::num_rows($result_check) == 1) {
2573
                    switch ($this->file_option) {
2574
                        case FILE_SKIP:
2575
                            //Do nothing
2576
                            break;
2577
                        case FILE_RENAME:
2578
                            $survey_code = $survey->code.'_';
2579
                            $i = 1;
2580
                            $temp_survey_code = $survey_code.$i;
2581
                            while (!$this->is_survey_code_available($temp_survey_code)) {
2582
                                $temp_survey_code = $survey_code.++$i;
2583
                            }
2584
                            $survey_code = $temp_survey_code;
2585
2586
                            $params['code'] = $survey_code;
2587
                            $new_id = Database::insert($table_sur, $params);
2588
                            if ($new_id) {
2589
                                $sql = "UPDATE $table_sur SET survey_id = iid WHERE iid = $new_id";
2590
                                Database::query($sql);
2591
2592
                                $this->course->resources[RESOURCE_SURVEY][$id]->destination_id = $new_id;
2593
                                foreach ($survey->question_ids as $index => $question_id) {
2594
                                    $qid = $this->restore_survey_question($question_id, $new_id);
2595
                                    $sql = "UPDATE $table_que SET survey_id = $new_id
2596
                                            WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2597
                                    Database::query($sql);
2598
                                    $sql = "UPDATE $table_ans SET survey_id = $new_id
2599
                                            WHERE  c_id = ".$this->destination_course_id." AND  question_id = $qid";
2600
                                    Database::query($sql);
2601
                                }
2602
                            }
2603
                            break;
2604
                        case FILE_OVERWRITE:
2605
                            // Delete the existing survey with the same code and language and
2606
                            // import the one of the source course
2607
                            // getting the information of the survey (used for when the survey is shared)
2608
                            $sql = "SELECT * FROM $table_sur
2609
                                    WHERE
2610
                                        c_id = ".$this->destination_course_id." AND
2611
                                        survey_id='".self::DBUTF8escapestring(Database::result($result_check, 0, 0))."'";
2612
                            $result = Database::query($sql);
2613
                            $survey_data = Database::fetch_array($result, 'ASSOC');
2614
2615
                            // if the survey is shared => also delete the shared content
2616
                            if (isset($survey_data['survey_share']) && is_numeric($survey_data['survey_share'])) {
2617
                                SurveyManager::delete_survey(
2618
                                    $survey_data['survey_share'],
2619
                                    true,
2620
                                    $this->destination_course_id
2621
                                );
2622
                            }
2623
                            SurveyManager::delete_survey(
2624
                                $survey_data['survey_id'],
2625
                                false,
2626
                                $this->destination_course_id
2627
                            );
2628
2629
                            // Insert the new source survey
2630
                            $new_id = Database::insert($table_sur, $params);
2631
2632
                            if ($new_id) {
2633
                                $sql = "UPDATE $table_sur SET survey_id = iid WHERE iid = $new_id";
2634
                                Database::query($sql);
2635
2636
                                $this->course->resources[RESOURCE_SURVEY][$id]->destination_id = $new_id;
2637
                                foreach ($survey->question_ids as $index => $question_id) {
2638
                                    $qid = $this->restore_survey_question(
2639
                                        $question_id,
2640
                                        $new_id
2641
                                    );
2642
                                    $sql = "UPDATE $table_que SET survey_id = $new_id
2643
                                            WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2644
                                    Database::query($sql);
2645
                                    $sql = "UPDATE $table_ans SET survey_id = $new_id
2646
                                            WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2647
                                    Database::query($sql);
2648
                                }
2649
                            }
2650
                            break;
2651
                        default:
2652
                            break;
2653
                    }
2654
                } else {
2655
                    // No existing survey with the same language and the same code, we just copy the survey
2656
                    $new_id = Database::insert($table_sur, $params);
2657
2658
                    if ($new_id) {
2659
                        $sql = "UPDATE $table_sur SET survey_id = iid WHERE iid = $new_id";
2660
                        Database::query($sql);
2661
2662
                        $this->course->resources[RESOURCE_SURVEY][$id]->destination_id = $new_id;
2663
                        foreach ($survey->question_ids as $index => $question_id) {
2664
                            $qid = $this->restore_survey_question(
2665
                                $question_id,
2666
                                $new_id
2667
                            );
2668
                            $sql = "UPDATE $table_que SET survey_id = $new_id
2669
                                    WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2670
                            Database::query($sql);
2671
                            $sql = "UPDATE $table_ans SET survey_id = $new_id
2672
                                    WHERE c_id = ".$this->destination_course_id." AND question_id = $qid";
2673
                            Database::query($sql);
2674
                        }
2675
                    }
2676
                }
2677
            }
2678
        }
2679
    }
2680
2681
    /**
2682
     * Check availability of a survey code.
2683
     *
2684
     * @param string $survey_code
2685
     *
2686
     * @return bool
2687
     */
2688
    public function is_survey_code_available($survey_code)
2689
    {
2690
        $table_sur = Database::get_course_table(TABLE_SURVEY);
2691
        $sql = "SELECT * FROM $table_sur
2692
                WHERE
2693
                    c_id = ".$this->destination_course_id." AND
2694
                    code = '".self::DBUTF8escapestring($survey_code)."'";
2695
        $result = Database::query($sql);
2696
        if (Database::num_rows($result) > 0) {
2697
            return false;
2698
        } else {
2699
            return true;
2700
        }
2701
    }
2702
2703
    /**
2704
     * Restore survey-questions.
2705
     *
2706
     * @param int    $id
2707
     * @param string $survey_id
2708
     */
2709
    public function restore_survey_question($id, $survey_id)
2710
    {
2711
        $resources = $this->course->resources;
2712
        $question = $resources[RESOURCE_SURVEYQUESTION][$id];
2713
        $new_id = 0;
2714
2715
        if (is_object($question)) {
2716
            if ($question->is_restored()) {
2717
                return $question->destination_id;
2718
            }
2719
            $table_que = Database::get_course_table(TABLE_SURVEY_QUESTION);
2720
            $table_ans = Database::get_course_table(TABLE_SURVEY_QUESTION_OPTION);
2721
2722
            // check resources inside html from ckeditor tool and copy correct urls into recipient course
2723
            $question->survey_question = DocumentManager::replaceUrlWithNewCourseCode(
2724
                $question->survey_question,
2725
                $this->course->code,
2726
                $this->course->destination_path,
2727
                $this->course->backup_path,
2728
                $this->course->info['path']
2729
            );
2730
2731
            $params = [
2732
                'c_id' => $this->destination_course_id,
2733
                'survey_id' => self::DBUTF8($survey_id),
2734
                'survey_question' => ($question->survey_question === false ? '' : self::DBUTF8($question->survey_question)),
2735
                'survey_question_comment' => self::DBUTF8($question->survey_question_comment),
2736
                'type' => self::DBUTF8($question->survey_question_type),
2737
                'display' => self::DBUTF8($question->display),
2738
                'sort' => self::DBUTF8($question->sort),
2739
                'shared_question_id' => self::DBUTF8($question->shared_question_id),
2740
                'max_value' => self::DBUTF8($question->max_value),
2741
            ];
2742
            if (api_get_configuration_value('allow_required_survey_questions')) {
2743
                if (isset($question->is_required)) {
2744
                    $params['is_required'] = $question->is_required;
2745
                }
2746
            }
2747
2748
            $new_id = Database::insert($table_que, $params);
2749
            if ($new_id) {
2750
                $sql = "UPDATE $table_que SET question_id = iid WHERE iid = $new_id";
2751
                Database::query($sql);
2752
2753
                foreach ($question->answers as $index => $answer) {
2754
                    // check resources inside html from ckeditor tool and copy correct urls into recipient course
2755
                    $answer['option_text'] = DocumentManager::replaceUrlWithNewCourseCode(
2756
                        $answer['option_text'],
2757
                        $this->course->code,
2758
                        $this->course->destination_path,
2759
                        $this->course->backup_path,
2760
                        $this->course->info['path']
2761
                    );
2762
2763
                    $params = [
2764
                        'c_id' => $this->destination_course_id,
2765
                        'question_id' => $new_id,
2766
                        'option_text' => ($answer['option_text'] === false ? '' : self::DBUTF8($answer['option_text'])),
2767
                        'sort' => $answer['sort'],
2768
                        'survey_id' => self::DBUTF8($survey_id),
2769
                    ];
2770
                    $answerId = Database::insert($table_ans, $params);
2771
                    if ($answerId) {
2772
                        $sql = "UPDATE $table_ans SET question_option_id = iid
2773
                                WHERE iid = $answerId";
2774
                        Database::query($sql);
2775
                    }
2776
                }
2777
                $this->course->resources[RESOURCE_SURVEYQUESTION][$id]->destination_id = $new_id;
2778
            }
2779
        }
2780
2781
        return $new_id;
2782
    }
2783
2784
    /**
2785
     * @param int  $sessionId
2786
     * @param bool $baseContent
2787
     */
2788
    public function restore_learnpath_category($sessionId = 0, $baseContent = false)
2789
    {
2790
        $reuseExisting = false;
2791
2792
        if (isset($this->tool_copy_settings['learnpath_category']) &&
2793
            isset($this->tool_copy_settings['learnpath_category']['reuse_existing']) &&
2794
            true === $this->tool_copy_settings['learnpath_category']['reuse_existing']
2795
        ) {
2796
            $reuseExisting = true;
2797
        }
2798
2799
        $tblLpCategory = Database::get_course_table(TABLE_LP_CATEGORY);
2800
2801
        if ($this->course->has_resources(RESOURCE_LEARNPATH_CATEGORY)) {
2802
            $resources = $this->course->resources;
2803
            /** @var LearnPathCategory $item */
2804
            foreach ($resources[RESOURCE_LEARNPATH_CATEGORY] as $id => $item) {
2805
                /** @var CLpCategory $lpCategory */
2806
                $lpCategory = $item->object;
2807
2808
                if ($lpCategory) {
2809
                    $existingLpCategory = Database::select(
2810
                        'iid',
2811
                        $tblLpCategory,
2812
                        [
2813
                            'WHERE' => [
2814
                                'c_id = ? AND name = ?' => [$this->destination_course_id, $lpCategory->getName()],
2815
                            ],
2816
                        ],
2817
                        'first'
2818
                    );
2819
2820
                    if ($reuseExisting && !empty($existingLpCategory)) {
2821
                        $categoryId = $existingLpCategory['iid'];
2822
                    } else {
2823
                        $values = [
2824
                            'c_id' => $this->destination_course_id,
2825
                            'name' => $lpCategory->getName(),
2826
                        ];
2827
                        $categoryId = \learnpath::createCategory($values);
2828
                    }
2829
2830
                    if ($categoryId) {
2831
                        $this->course->resources[RESOURCE_LEARNPATH_CATEGORY][$id]->destination_id = $categoryId;
2832
                    }
2833
                }
2834
            }
2835
        }
2836
    }
2837
2838
    /**
2839
     * Restoring learning paths.
2840
     *
2841
     * @param int        $session_id
2842
     * @param bool|false $respect_base_content
2843
     */
2844
    public function restore_learnpaths($session_id = 0, $respect_base_content = false)
2845
    {
2846
        $session_id = (int) $session_id;
2847
        if ($this->course->has_resources(RESOURCE_LEARNPATH)) {
2848
            $table_main = Database::get_course_table(TABLE_LP_MAIN);
2849
            $table_item = Database::get_course_table(TABLE_LP_ITEM);
2850
            $table_tool = Database::get_course_table(TABLE_TOOL_LIST);
2851
2852
            $resources = $this->course->resources;
2853
            $origin_path = $this->course->backup_path.'/upload/learning_path/images/';
2854
            $destination_path = api_get_path(SYS_COURSE_PATH).
2855
                $this->course->destination_path.'/upload/learning_path/images/';
2856
2857
            // Choose default visibility
2858
            $toolVisibility = api_get_setting('tool_visible_by_default_at_creation');
2859
            $defaultLpVisibility = 'invisible';
2860
            if (isset($toolVisibility['learning_path']) && $toolVisibility['learning_path'] == 'true') {
2861
                $defaultLpVisibility = 'visible';
2862
            }
2863
2864
            $lpIds = [];
2865
            foreach ($resources[RESOURCE_LEARNPATH] as $id => $lp) {
2866
                $condition_session = '';
2867
                if (!empty($session_id)) {
2868
                    if ($respect_base_content) {
2869
                        $my_session_id = $lp->session_id;
2870
                        if (!empty($lp->session_id)) {
2871
                            $my_session_id = $session_id;
2872
                        }
2873
                        $condition_session = $my_session_id;
2874
                    } else {
2875
                        $session_id = (int) $session_id;
2876
                        $condition_session = $session_id;
2877
                    }
2878
                }
2879
2880
                // Adding the LP image
2881
                if (!empty($lp->preview_image)) {
2882
                    $new_filename = uniqid('').substr(
2883
                        $lp->preview_image,
2884
                        strlen($lp->preview_image) - 7,
2885
                        strlen($lp->preview_image)
2886
                    );
2887
2888
                    if (file_exists($origin_path.$lp->preview_image) &&
2889
                        !is_dir($origin_path.$lp->preview_image)
2890
                    ) {
2891
                        $copy_result = copy(
2892
                            $origin_path.$lp->preview_image,
2893
                            $destination_path.$new_filename
2894
                        );
2895
                        if ($copy_result) {
2896
                            $lp->preview_image = $new_filename;
2897
                            // Create 64 version from original
2898
                            $temp = new \Image($destination_path.$new_filename);
2899
                            $temp->resize(64);
2900
                            $pathInfo = pathinfo($new_filename);
2901
                            if ($pathInfo) {
2902
                                $filename = $pathInfo['filename'];
2903
                                $extension = $pathInfo['extension'];
2904
                                $temp->send_image($destination_path.'/'.$filename.'.64.'.$extension);
2905
                            }
2906
                        } else {
2907
                            $lp->preview_image = '';
2908
                        }
2909
                    }
2910
                }
2911
2912
                if ($this->add_text_in_items) {
2913
                    $lp->name = $lp->name.' '.get_lang('CopyLabelSuffix');
2914
                }
2915
2916
                if (isset($this->tool_copy_settings['learnpaths'])) {
2917
                    if (isset($this->tool_copy_settings['learnpaths']['reset_dates']) &&
2918
                        $this->tool_copy_settings['learnpaths']['reset_dates']
2919
                    ) {
2920
                        $lp->created_on = api_get_utc_datetime();
2921
                        $lp->modified_on = api_get_utc_datetime();
2922
                        $lp->publicated_on = null;
2923
                    }
2924
                }
2925
2926
                $lp->expired_on = isset($lp->expired_on) && $lp->expired_on === '0000-00-00 00:00:00' ? null : $lp->expired_on;
2927
                $lp->publicated_on = isset($lp->publicated_on) && $lp->publicated_on === '0000-00-00 00:00:00' ? null : $lp->publicated_on;
2928
2929
                if (isset($lp->categoryId)) {
2930
                    $lp->categoryId = (int) $lp->categoryId;
2931
                }
2932
2933
                $categoryId = 0;
2934
                if (!empty($lp->categoryId)) {
2935
                    if (isset($resources[RESOURCE_LEARNPATH_CATEGORY][$lp->categoryId])) {
2936
                        $categoryId = $resources[RESOURCE_LEARNPATH_CATEGORY][$lp->categoryId]->destination_id;
2937
                    }
2938
                }
2939
                $params = [
2940
                    'c_id' => $this->destination_course_id,
2941
                    'lp_type' => $lp->lp_type,
2942
                    'name' => self::DBUTF8($lp->name),
2943
                    'path' => self::DBUTF8($lp->path),
2944
                    'ref' => $lp->ref,
2945
                    'description' => self::DBUTF8($lp->description),
2946
                    'content_local' => self::DBUTF8($lp->content_local),
2947
                    'default_encoding' => self::DBUTF8($lp->default_encoding),
2948
                    'default_view_mod' => self::DBUTF8($lp->default_view_mod),
2949
                    'prevent_reinit' => self::DBUTF8($lp->prevent_reinit),
2950
                    'force_commit' => self::DBUTF8($lp->force_commit),
2951
                    'content_maker' => self::DBUTF8($lp->content_maker),
2952
                    'display_order' => self::DBUTF8($lp->display_order),
2953
                    'js_lib' => self::DBUTF8($lp->js_lib),
2954
                    'content_license' => self::DBUTF8($lp->content_license),
2955
                    'author' => self::DBUTF8($lp->author),
2956
                    'preview_image' => self::DBUTF8($lp->preview_image),
2957
                    'use_max_score' => self::DBUTF8($lp->use_max_score),
2958
                    'autolaunch' => self::DBUTF8(isset($lp->autolaunch) ? $lp->autolaunch : ''),
2959
                    'created_on' => empty($lp->created_on) ? api_get_utc_datetime() : self::DBUTF8($lp->created_on),
2960
                    'modified_on' => empty($lp->modified_on) ? api_get_utc_datetime() : self::DBUTF8($lp->modified_on),
2961
                    'publicated_on' => empty($lp->publicated_on) ? api_get_utc_datetime() : self::DBUTF8($lp->publicated_on),
2962
                    'expired_on' => self::DBUTF8($lp->expired_on),
2963
                    'debug' => self::DBUTF8($lp->debug),
2964
                    'theme' => '',
2965
                    'session_id' => $session_id,
2966
                    'prerequisite' => (int) $lp->prerequisite,
2967
                    'hide_toc_frame' => self::DBUTF8(isset($lp->hideTableOfContents) ? $lp->hideTableOfContents : 0),
2968
                    'subscribe_users' => self::DBUTF8(isset($lp->subscribeUsers) ? $lp->subscribeUsers : 0),
2969
                    'seriousgame_mode' => 0,
2970
                    'category_id' => $categoryId,
2971
                    'max_attempts' => 0,
2972
                ];
2973
2974
                if (api_get_configuration_value('lp_minimum_time')) {
2975
                    if (isset($lp->accumulateWorkTime) && !empty($lp->accumulateWorkTime)) {
2976
                        $params['accumulate_work_time'] = $lp->accumulateWorkTime;
2977
                    }
2978
                }
2979
2980
                if (!empty($condition_session)) {
2981
                    $params['session_id'] = $condition_session;
2982
                }
2983
2984
                $new_lp_id = Database::insert($table_main, $params);
2985
                if ($new_lp_id) {
2986
                    $lpIds[$id] = $new_lp_id;
2987
                    // The following only makes sense if a new LP was
2988
                    // created in the destination course
2989
                    $sql = "UPDATE $table_main SET id = iid WHERE iid = $new_lp_id";
2990
                    Database::query($sql);
2991
2992
                    if ($lp->visibility) {
2993
                        $params = [
2994
                            'c_id' => $this->destination_course_id,
2995
                            'name' => self::DBUTF8($lp->name),
2996
                            'link' => "lp/lp_controller.php?action=view&lp_id=$new_lp_id&id_session=$session_id",
2997
                            'image' => 'scormbuilder.gif',
2998
                            'visibility' => '0',
2999
                            'admin' => '0',
3000
                            'address' => 'squaregrey.gif',
3001
                            'session_id' => $session_id,
3002
                        ];
3003
                        $insertId = Database::insert($table_tool, $params);
3004
                        if ($insertId) {
3005
                            $sql = "UPDATE $table_tool SET id = iid WHERE iid = $insertId";
3006
                            Database::query($sql);
3007
                        }
3008
                    }
3009
3010
                    if (isset($lp->extraFields) && !empty($lp->extraFields)) {
3011
                        $extraFieldValue = new \ExtraFieldValue('lp');
3012
                        foreach ($lp->extraFields as $extraField) {
3013
                            $params = [
3014
                                'item_id' => $new_lp_id,
3015
                                'value' => $extraField['value'],
3016
                                'variable' => $extraField['variable'],
3017
                            ];
3018
                            $extraFieldValue->save($params);
3019
                        }
3020
                    }
3021
3022
                    api_item_property_update(
3023
                        $this->destination_course_info,
3024
                        TOOL_LEARNPATH,
3025
                        $new_lp_id,
3026
                        'LearnpathAdded',
3027
                        api_get_user_id(),
3028
                        0,
3029
                        0,
3030
                        0,
3031
                        0,
3032
                        $session_id
3033
                    );
3034
3035
                    // Set the new LP to visible
3036
                    api_item_property_update(
3037
                        $this->destination_course_info,
3038
                        TOOL_LEARNPATH,
3039
                        $new_lp_id,
3040
                        $defaultLpVisibility,
3041
                        api_get_user_id(),
3042
                        0,
3043
                        0,
3044
                        0,
3045
                        0,
3046
                        $session_id
3047
                    );
3048
3049
                    $new_item_ids = [];
3050
                    $parent_item_ids = [];
3051
                    $previous_item_ids = [];
3052
                    $next_item_ids = [];
3053
                    $old_prerequisite = [];
3054
                    $old_refs = [];
3055
                    $prerequisite_ids = [];
3056
3057
                    foreach ($lp->get_items() as $index => $item) {
3058
                        // we set the ref code here and then we update in a for loop
3059
                        $ref = $item['ref'];
3060
3061
                        // Dealing with path the same way as ref as some data has
3062
                        // been put into path when it's a local resource
3063
                        // Only fix the path for no scos
3064
                        if ($item['item_type'] === 'sco') {
3065
                            $path = $item['path'];
3066
                        } else {
3067
                            $path = $this->get_new_id($item['item_type'], $item['path']);
3068
                        }
3069
3070
                        $item['item_type'] = $item['item_type'] === 'dokeos_chapter' ? 'dir' : $item['item_type'];
3071
3072
                        $masteryScore = $item['mastery_score'];
3073
                        // If item is a chamilo quiz, then use the max score as mastery_score.
3074
                        if ($item['item_type'] === 'quiz') {
3075
                            if (empty($masteryScore)) {
3076
                                $masteryScore = $item['max_score'];
3077
                            }
3078
                        }
3079
3080
                        $prerequisiteMinScore = $item['prerequisite_min_score'] ?? null;
3081
                        $prerequisiteMaxScore = $item['prerequisite_max_score'] ?? null;
3082
3083
                        $params = [
3084
                            'c_id' => $this->destination_course_id,
3085
                            'lp_id' => self::DBUTF8($new_lp_id),
3086
                            'item_type' => self::DBUTF8($item['item_type']),
3087
                            'ref' => self::DBUTF8($ref),
3088
                            'path' => self::DBUTF8($path),
3089
                            'title' => self::DBUTF8($item['title']),
3090
                            'description' => self::DBUTF8($item['description']),
3091
                            'min_score' => self::DBUTF8($item['min_score']),
3092
                            'max_score' => self::DBUTF8($item['max_score']),
3093
                            'mastery_score' => self::DBUTF8($masteryScore),
3094
                            'prerequisite_min_score' => $prerequisiteMinScore,
3095
                            'prerequisite_max_score' => $prerequisiteMaxScore,
3096
                            'parent_item_id' => self::DBUTF8($item['parent_item_id']),
3097
                            'previous_item_id' => self::DBUTF8($item['previous_item_id']),
3098
                            'next_item_id' => self::DBUTF8($item['next_item_id']),
3099
                            'display_order' => self::DBUTF8($item['display_order']),
3100
                            'prerequisite' => self::DBUTF8($item['prerequisite']),
3101
                            'parameters' => self::DBUTF8($item['parameters']),
3102
                            'audio' => self::DBUTF8($item['audio']),
3103
                            'launch_data' => self::DBUTF8($item['launch_data']),
3104
                        ];
3105
3106
                        $new_item_id = Database::insert($table_item, $params);
3107
                        if ($new_item_id) {
3108
                            $sql = "UPDATE $table_item SET id = iid WHERE iid = $new_item_id";
3109
                            Database::query($sql);
3110
3111
                            //save a link between old and new item IDs
3112
                            $new_item_ids[$item['id']] = $new_item_id;
3113
                            //save a reference of items that need a parent_item_id refresh
3114
                            $parent_item_ids[$new_item_id] = $item['parent_item_id'];
3115
                            //save a reference of items that need a previous_item_id refresh
3116
                            $previous_item_ids[$new_item_id] = $item['previous_item_id'];
3117
                            //save a reference of items that need a next_item_id refresh
3118
                            $next_item_ids[$new_item_id] = $item['next_item_id'];
3119
3120
                            if (!empty($item['prerequisite'])) {
3121
                                if ($lp->lp_type == '2') {
3122
                                    // if is an sco
3123
                                    $old_prerequisite[$new_item_id] = $item['prerequisite'];
3124
                                } else {
3125
                                    $old_prerequisite[$new_item_id] = isset($new_item_ids[$item['prerequisite']]) ? $new_item_ids[$item['prerequisite']] : '';
3126
                                }
3127
                            }
3128
3129
                            if (!empty($ref)) {
3130
                                if ($lp->lp_type == '2') {
3131
                                    // if is an sco
3132
                                    $old_refs[$new_item_id] = $ref;
3133
                                } elseif (isset($new_item_ids[$ref])) {
3134
                                    $old_refs[$new_item_id] = $new_item_ids[$ref];
3135
                                }
3136
                            }
3137
                            $prerequisite_ids[$new_item_id] = $item['prerequisite'];
3138
3139
                            // Upload audio.
3140
                            if (!empty($item['audio'])) {
3141
                                $courseInfo = api_get_course_info_by_id($this->destination_course_id);
3142
                                // Create the audio folder if it does not exist yet.
3143
                                $filepath = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/document/';
3144
                                if (!is_dir($filepath.'audio')) {
3145
                                    mkdir(
3146
                                        $filepath.'audio',
3147
                                        api_get_permissions_for_new_directories()
3148
                                    );
3149
                                    $audioId = add_document(
3150
                                        $courseInfo,
3151
                                        '/audio',
3152
                                        'folder',
3153
                                        0,
3154
                                        'audio',
3155
                                        '',
3156
                                        0,
3157
                                        true,
3158
                                        null,
3159
                                        $session_id,
3160
                                        api_get_user_id()
3161
                                    );
3162
                                    api_item_property_update(
3163
                                        $courseInfo,
3164
                                        TOOL_DOCUMENT,
3165
                                        $audioId,
3166
                                        'FolderCreated',
3167
                                        api_get_user_id(),
3168
                                        null,
3169
                                        null,
3170
                                        null,
3171
                                        null,
3172
                                        $session_id
3173
                                    );
3174
                                    api_item_property_update(
3175
                                        $courseInfo,
3176
                                        TOOL_DOCUMENT,
3177
                                        $audioId,
3178
                                        'invisible',
3179
                                        api_get_user_id(),
3180
                                        null,
3181
                                        null,
3182
                                        null,
3183
                                        null,
3184
                                        $session_id
3185
                                    );
3186
                                }
3187
                                $originAudioFile = $this->course->backup_path.'/document'.$item['audio'];
3188
                                $uploadedFile = [
3189
                                    'name' => basename($originAudioFile),
3190
                                    'tmp_name' => $originAudioFile,
3191
                                    'size' => filesize($originAudioFile),
3192
                                    'type' => null,
3193
                                    'from_file' => true,
3194
                                    'copy_file' => true,
3195
                                ];
3196
                                $filePath = handle_uploaded_document(
3197
                                    $courseInfo,
3198
                                    $uploadedFile,
3199
                                    api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/document',
3200
                                    '/audio',
3201
                                    api_get_user_id(),
3202
                                    '',
3203
                                    '',
3204
                                    '',
3205
                                    '',
3206
                                    false
3207
                                );
3208
                            }
3209
                        }
3210
                    }
3211
3212
                    // Updating prerequisites
3213
                    foreach ($old_prerequisite as $key => $my_old_prerequisite) {
3214
                        if ($my_old_prerequisite != '') {
3215
                            $my_old_prerequisite = Database::escape_string($my_old_prerequisite);
3216
                            $sql = "UPDATE $table_item SET prerequisite = '$my_old_prerequisite'
3217
                                    WHERE c_id = ".$this->destination_course_id." AND id = '".$key."'  ";
3218
                            Database::query($sql);
3219
                        }
3220
                    }
3221
3222
                    // Updating refs
3223
                    foreach ($old_refs as $key => $my_old_ref) {
3224
                        if ($my_old_ref != '') {
3225
                            $my_old_ref = Database::escape_string($my_old_ref);
3226
                            $sql = "UPDATE $table_item SET ref = '$my_old_ref'
3227
                                    WHERE c_id = ".$this->destination_course_id." AND id = $key";
3228
                            Database::query($sql);
3229
                        }
3230
                    }
3231
3232
                    foreach ($parent_item_ids as $new_item_id => $parent_item_old_id) {
3233
                        $new_item_id = (int) $new_item_id;
3234
                        $parent_new_id = 0;
3235
                        if ($parent_item_old_id != 0) {
3236
                            $parent_new_id = isset($new_item_ids[$parent_item_old_id]) ? $new_item_ids[$parent_item_old_id] : 0;
3237
                        }
3238
3239
                        $parent_new_id = Database::escape_string($parent_new_id);
3240
                        $sql = "UPDATE $table_item SET parent_item_id = '$parent_new_id'
3241
                                WHERE c_id = ".$this->destination_course_id." AND id = $new_item_id";
3242
                        Database::query($sql);
3243
                    }
3244
3245
                    foreach ($previous_item_ids as $new_item_id => $previous_item_old_id) {
3246
                        $new_item_id = (int) $new_item_id;
3247
                        $previous_new_id = 0;
3248
                        if ($previous_item_old_id != 0) {
3249
                            $previous_new_id = isset($new_item_ids[$previous_item_old_id]) ? $new_item_ids[$previous_item_old_id] : 0;
3250
                        }
3251
                        $previous_new_id = Database::escape_string($previous_new_id);
3252
                        $sql = "UPDATE $table_item SET previous_item_id = '$previous_new_id'
3253
                                WHERE c_id = ".$this->destination_course_id." AND id = '".$new_item_id."'";
3254
                        Database::query($sql);
3255
                    }
3256
3257
                    foreach ($next_item_ids as $new_item_id => $next_item_old_id) {
3258
                        $new_item_id = (int) $new_item_id;
3259
                        $next_new_id = 0;
3260
                        if ($next_item_old_id != 0) {
3261
                            $next_new_id = isset($new_item_ids[$next_item_old_id]) ? $new_item_ids[$next_item_old_id] : 0;
3262
                        }
3263
                        $next_new_id = Database::escape_string($next_new_id);
3264
                        $sql = "UPDATE $table_item SET next_item_id = '$next_new_id'
3265
                                WHERE c_id = ".$this->destination_course_id." AND id = '".$new_item_id."'";
3266
                        Database::query($sql);
3267
                    }
3268
3269
                    foreach ($prerequisite_ids as $new_item_id => $prerequisite_old_id) {
3270
                        $new_item_id = (int) $new_item_id;
3271
                        $prerequisite_new_id = 0;
3272
                        if ($prerequisite_old_id != 0) {
3273
                            $prerequisite_new_id = $new_item_ids[$prerequisite_old_id];
3274
                        }
3275
                        $prerequisite_new_id = Database::escape_string($prerequisite_new_id);
3276
                        $sql = "UPDATE $table_item SET prerequisite = '$prerequisite_new_id'
3277
                                WHERE c_id = ".$this->destination_course_id." AND id = $new_item_id";
3278
                        Database::query($sql);
3279
                    }
3280
                    $this->course->resources[RESOURCE_LEARNPATH][$id]->destination_id = $new_lp_id;
3281
                }
3282
            }
3283
            // It updates the current lp id prerequisites
3284
            if (!empty($lpIds)) {
3285
                foreach ($lpIds as $oldLpId => $newLpId) {
3286
                    $sql = "UPDATE $table_main SET prerequisite = '$newLpId'
3287
                                WHERE c_id = ".$this->destination_course_id." AND prerequisite = '$oldLpId'";
3288
                    Database::query($sql);
3289
                }
3290
            }
3291
        }
3292
    }
3293
3294
    /**
3295
     * Copy all directory and sub directory.
3296
     *
3297
     * @param string $source The path origin
3298
     * @param string $dest   The path destination
3299
     * @param bool Option Overwrite
3300
     *
3301
     * @deprecated
3302
     */
3303
    public function allow_create_all_directory($source, $dest, $overwrite = false)
3304
    {
3305
        if (!is_dir($dest)) {
3306
            mkdir($dest, api_get_permissions_for_new_directories());
3307
        }
3308
        if ($handle = opendir($source)) {
3309
            // if the folder exploration is sucsessful, continue
3310
            while (false !== ($file = readdir($handle))) {
3311
                // as long as storing the next file to $file is successful, continue
3312
                if ($file != '.' && $file != '..') {
3313
                    $path = $source.'/'.$file;
3314
                    if (is_file($path)) {
3315
                        /* if (!is_file($dest . '/' . $file) || $overwrite)
3316
                         if (!@copy($path, $dest . '/' . $file)) {
3317
                             echo '<font color="red">File ('.$path.') '.get_lang('NotHavePermission').'</font>';
3318
                         }*/
3319
                    } elseif (is_dir($path)) {
3320
                        if (!is_dir($dest.'/'.$file)) {
3321
                            mkdir($dest.'/'.$file);
3322
                        }
3323
                        self::allow_create_all_directory($path, $dest.'/'.$file, $overwrite);
3324
                    }
3325
                }
3326
            }
3327
            closedir($handle);
3328
        }
3329
    }
3330
3331
    /**
3332
     * Gets the new ID of one specific tool item from the tool name and the old ID.
3333
     *
3334
     * @param	string	Tool name
3335
     * @param	int	Old ID
3336
     *
3337
     * @return int New ID
3338
     */
3339
    public function get_new_id($tool, $ref)
3340
    {
3341
        // Check if the value exist in the current array.
3342
        if ($tool === 'hotpotatoes') {
3343
            $tool = 'document';
3344
        }
3345
3346
        if ($tool === 'student_publication') {
3347
            $tool = RESOURCE_WORK;
3348
        }
3349
3350
        if ('xapi' === $tool && $this->isXapiEnabled) {
3351
            $tool = RESOURCE_XAPI_TOOL;
3352
        }
3353
3354
        if ('h5p' === $tool && $this->isH5pEnabled) {
3355
            $tool = RESOURCE_H5P_TOOL;
3356
        }
3357
3358
        if (isset($this->course->resources[$tool][$ref]) &&
3359
            isset($this->course->resources[$tool][$ref]->destination_id) &&
3360
            !empty($this->course->resources[$tool][$ref]->destination_id)
3361
        ) {
3362
            return $this->course->resources[$tool][$ref]->destination_id;
3363
        }
3364
3365
        // Check if the course is the same (last hope).
3366
        if ($this->course_origin_id == $this->destination_course_id) {
3367
            return $ref;
3368
        }
3369
3370
        return '';
3371
    }
3372
3373
    /**
3374
     * Restore glossary.
3375
     */
3376
    public function restore_glossary($sessionId = 0)
3377
    {
3378
        $sessionId = (int) $sessionId;
3379
        if ($this->course->has_resources(RESOURCE_GLOSSARY)) {
3380
            $table_glossary = Database::get_course_table(TABLE_GLOSSARY);
3381
            $resources = $this->course->resources;
3382
            foreach ($resources[RESOURCE_GLOSSARY] as $id => $glossary) {
3383
                $params = [];
3384
                if (!empty($sessionId)) {
3385
                    $params['session_id'] = $sessionId;
3386
                }
3387
3388
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3389
                $glossary->description = DocumentManager::replaceUrlWithNewCourseCode(
3390
                    $glossary->description,
3391
                    $this->course->code,
3392
                    $this->course->destination_path,
3393
                    $this->course->backup_path,
3394
                    $this->course->info['path']
3395
                );
3396
3397
                $params['c_id'] = $this->destination_course_id;
3398
                $params['description'] = ($glossary->description === false ? '' : self::DBUTF8($glossary->description));
3399
                $params['display_order'] = $glossary->display_order;
3400
                $params['name'] = self::DBUTF8($glossary->name);
3401
                $params['glossary_id'] = 0;
3402
                $my_id = Database::insert($table_glossary, $params);
3403
                if ($my_id) {
3404
                    $sql = "UPDATE $table_glossary SET glossary_id = iid WHERE iid = $my_id";
3405
                    Database::query($sql);
3406
3407
                    api_item_property_update(
3408
                        $this->destination_course_info,
3409
                        TOOL_GLOSSARY,
3410
                        $my_id,
3411
                        'GlossaryAdded',
3412
                        api_get_user_id(),
3413
                        null,
3414
                        null,
3415
                        null,
3416
                        null,
3417
                        $sessionId
3418
                    );
3419
3420
                    if (!isset($this->course->resources[RESOURCE_GLOSSARY][$id])) {
3421
                        $this->course->resources[RESOURCE_GLOSSARY][$id] = new stdClass();
3422
                    }
3423
3424
                    $this->course->resources[RESOURCE_GLOSSARY][$id]->destination_id = $my_id;
3425
                }
3426
            }
3427
        }
3428
    }
3429
3430
    /**
3431
     * @param int $sessionId
3432
     */
3433
    public function restore_wiki($sessionId = 0)
3434
    {
3435
        if ($this->course->has_resources(RESOURCE_WIKI)) {
3436
            // wiki table of the target course
3437
            $table_wiki = Database::get_course_table(TABLE_WIKI);
3438
            $table_wiki_conf = Database::get_course_table(TABLE_WIKI_CONF);
3439
3440
            // storing all the resources that have to be copied in an array
3441
            $resources = $this->course->resources;
3442
3443
            foreach ($resources[RESOURCE_WIKI] as $id => $wiki) {
3444
                // the sql statement to insert the groups from the old course to the new course
3445
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3446
                $wiki->content = DocumentManager::replaceUrlWithNewCourseCode(
3447
                    $wiki->content,
3448
                    $this->course->code,
3449
                    $this->course->destination_path,
3450
                    $this->course->backup_path,
3451
                    $this->course->info['path']
3452
                );
3453
3454
                $params = [
3455
                    'c_id' => $this->destination_course_id,
3456
                    'page_id' => self::DBUTF8($wiki->page_id),
3457
                    'reflink' => self::DBUTF8($wiki->reflink),
3458
                    'title' => self::DBUTF8($wiki->title),
3459
                    'content' => ($wiki->content === false ? '' : self::DBUTF8($wiki->content)),
3460
                    'user_id' => intval($wiki->user_id),
3461
                    'group_id' => intval($wiki->group_id),
3462
                    'dtime' => self::DBUTF8($wiki->dtime),
3463
                    'progress' => self::DBUTF8($wiki->progress),
3464
                    'version' => intval($wiki->version),
3465
                    'session_id' => !empty($sessionId) ? intval($sessionId) : 0,
3466
                    'addlock' => 0,
3467
                    'editlock' => 0,
3468
                    'visibility' => 0,
3469
                    'addlock_disc' => 0,
3470
                    'visibility_disc' => 0,
3471
                    'ratinglock_disc' => 0,
3472
                    'assignment' => 0,
3473
                    'comment' => '',
3474
                    'is_editing' => 0,
3475
                    'linksto' => 0,
3476
                    'tag' => '',
3477
                    'user_ip' => '',
3478
                ];
3479
3480
                $new_id = Database::insert($table_wiki, $params);
3481
3482
                if ($new_id) {
3483
                    $sql = "UPDATE $table_wiki SET page_id = '$new_id', id = iid
3484
                            WHERE c_id = ".$this->destination_course_id." AND iid = '$new_id'";
3485
                    Database::query($sql);
3486
3487
                    $this->course->resources[RESOURCE_WIKI][$id]->destination_id = $new_id;
3488
3489
                    // we also add an entry in wiki_conf
3490
                    $params = [
3491
                        'c_id' => $this->destination_course_id,
3492
                        'page_id' => $new_id,
3493
                        'task' => '',
3494
                        'feedback1' => '',
3495
                        'feedback2' => '',
3496
                        'feedback3' => '',
3497
                        'fprogress1' => '',
3498
                        'fprogress2' => '',
3499
                        'fprogress3' => '',
3500
                        'max_size' => 0,
3501
                        'max_text' => 0,
3502
                        'max_version' => 0,
3503
                        'startdate_assig' => null,
3504
                        'enddate_assig' => null,
3505
                        'delayedsubmit' => 0,
3506
                    ];
3507
3508
                    Database::insert($table_wiki_conf, $params);
3509
                }
3510
            }
3511
        }
3512
    }
3513
3514
    /**
3515
     * Restore xapi tool.
3516
     *
3517
     * @param int $sessionId
3518
     */
3519
    public function restore_xapi_tool()
3520
    {
3521
        if ($this->course->has_resources(RESOURCE_XAPI_TOOL) && $this->isXapiEnabled) {
3522
            $resources = $this->course->resources;
3523
            foreach ($resources[RESOURCE_XAPI_TOOL] as $id => $xapiTool) {
3524
                $launchPath = str_replace(
3525
                    api_get_path(WEB_COURSE_PATH).$this->course->info['path'].'/',
3526
                    '',
3527
                    dirname($xapiTool->params['launch_url'])
3528
                );
3529
3530
                $originPath = $this->course->backup_path.'/'.$launchPath;
3531
                $destinationPath = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/'.$launchPath;
3532
                $xapiDir = dirname($destinationPath);
3533
                @mkdir($xapiDir, api_get_permissions_for_new_directories(), true);
3534
                if (copyDirTo($originPath, $destinationPath, false)) {
3535
                    $xapiTool->params['launch_url'] = str_replace(
3536
                        '/'.$this->course->info['path'].'/',
3537
                        '/'.$this->course->destination_path.'/',
3538
                        $xapiTool->params['launch_url']
3539
                    );
3540
                    $ref = $xapiTool->params['id'];
3541
                    $xapiTool->params['c_id'] = $this->destination_course_id;
3542
                    unset($xapiTool->params['id']);
3543
3544
                    $lastId = Database::insert('xapi_tool_launch', $xapiTool->params, false);
3545
                    $this->course->resources[RESOURCE_XAPI_TOOL][$ref]->destination_id = $lastId;
3546
                }
3547
            }
3548
        }
3549
    }
3550
3551
    /**
3552
     * Restore Thematics.
3553
     *
3554
     * @param int $sessionId
3555
     */
3556
    public function restore_thematic($sessionId = 0)
3557
    {
3558
        if ($this->course->has_resources(RESOURCE_THEMATIC)) {
3559
            $table_thematic = Database::get_course_table(TABLE_THEMATIC);
3560
            $table_thematic_advance = Database::get_course_table(TABLE_THEMATIC_ADVANCE);
3561
            $table_thematic_plan = Database::get_course_table(TABLE_THEMATIC_PLAN);
3562
3563
            $resources = $this->course->resources;
3564
            foreach ($resources[RESOURCE_THEMATIC] as $id => $thematic) {
3565
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3566
                $thematic->params['content'] = DocumentManager::replaceUrlWithNewCourseCode(
3567
                    $thematic->params['content'],
3568
                    $this->course->code,
3569
                    $this->course->destination_path,
3570
                    $this->course->backup_path,
3571
                    $this->course->info['path']
3572
                );
3573
                $thematic->params['c_id'] = $this->destination_course_id;
3574
                unset($thematic->params['id']);
3575
                unset($thematic->params['iid']);
3576
3577
                $last_id = Database::insert($table_thematic, $thematic->params, false);
3578
3579
                if ($last_id) {
3580
                    $sql = "UPDATE $table_thematic SET id = iid WHERE iid = $last_id";
3581
                    Database::query($sql);
3582
3583
                    api_item_property_update(
3584
                        $this->destination_course_info,
3585
                        'thematic',
3586
                        $last_id,
3587
                        'ThematicAdded',
3588
                        api_get_user_id(),
3589
                        null,
3590
                        null,
3591
                        null,
3592
                        null,
3593
                        $sessionId
3594
                    );
3595
3596
                    foreach ($thematic->thematic_advance_list as $thematic_advance) {
3597
                        unset($thematic_advance['id']);
3598
                        unset($thematic_advance['iid']);
3599
                        $thematic_advance['attendance_id'] = 0;
3600
                        $thematic_advance['thematic_id'] = $last_id;
3601
                        $thematic_advance['c_id'] = $this->destination_course_id;
3602
3603
                        $my_id = Database::insert(
3604
                            $table_thematic_advance,
3605
                            $thematic_advance,
3606
                            false
3607
                        );
3608
3609
                        if ($my_id) {
3610
                            $sql = "UPDATE $table_thematic_advance SET id = iid WHERE iid = $my_id";
3611
                            Database::query($sql);
3612
3613
                            api_item_property_update(
3614
                                $this->destination_course_info,
3615
                                'thematic_advance',
3616
                                $my_id,
3617
                                'ThematicAdvanceAdded',
3618
                                api_get_user_id(),
3619
                                null,
3620
                                null,
3621
                                null,
3622
                                null,
3623
                                $sessionId
3624
                            );
3625
                        }
3626
                    }
3627
3628
                    foreach ($thematic->thematic_plan_list as $thematic_plan) {
3629
                        unset($thematic_plan['id']);
3630
                        unset($thematic_plan['iid']);
3631
                        $thematic_plan['thematic_id'] = $last_id;
3632
                        $thematic_plan['c_id'] = $this->destination_course_id;
3633
                        $my_id = Database::insert($table_thematic_plan, $thematic_plan, false);
3634
3635
                        if ($my_id) {
3636
                            $sql = "UPDATE $table_thematic_plan SET id = iid WHERE iid = $my_id";
3637
                            Database::query($sql);
3638
3639
                            api_item_property_update(
3640
                                $this->destination_course_info,
3641
                                'thematic_plan',
3642
                                $my_id,
3643
                                'ThematicPlanAdded',
3644
                                api_get_user_id(),
3645
                                null,
3646
                                null,
3647
                                null,
3648
                                null,
3649
                                $sessionId
3650
                            );
3651
                        }
3652
                    }
3653
                }
3654
            }
3655
        }
3656
    }
3657
3658
    /**
3659
     * Restore Attendance.
3660
     *
3661
     * @param int $sessionId
3662
     */
3663
    public function restore_attendance($sessionId = 0)
3664
    {
3665
        if ($this->course->has_resources(RESOURCE_ATTENDANCE)) {
3666
            $table_attendance = Database::get_course_table(TABLE_ATTENDANCE);
3667
            $table_attendance_calendar = Database::get_course_table(TABLE_ATTENDANCE_CALENDAR);
3668
3669
            $resources = $this->course->resources;
3670
            foreach ($resources[RESOURCE_ATTENDANCE] as $id => $obj) {
3671
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3672
                $obj->params['description'] = DocumentManager::replaceUrlWithNewCourseCode(
3673
                    $obj->params['description'],
3674
                    $this->course->code,
3675
                    $this->course->destination_path,
3676
                    $this->course->backup_path,
3677
                    $this->course->info['path']
3678
                );
3679
3680
                unset($obj->params['id']);
3681
                unset($obj->params['iid']);
3682
                $obj->params['c_id'] = $this->destination_course_id;
3683
                $last_id = Database::insert($table_attendance, $obj->params);
3684
3685
                if (is_numeric($last_id)) {
3686
                    $sql = "UPDATE $table_attendance SET id = iid WHERE iid = $last_id";
3687
                    Database::query($sql);
3688
3689
                    $this->course->resources[RESOURCE_ATTENDANCE][$id]->destination_id = $last_id;
3690
3691
                    api_item_property_update(
3692
                        $this->destination_course_info,
3693
                        TOOL_ATTENDANCE,
3694
                        $last_id,
3695
                        'AttendanceAdded',
3696
                        api_get_user_id(),
3697
                        null,
3698
                        null,
3699
                        null,
3700
                        null,
3701
                        $sessionId
3702
                    );
3703
3704
                    foreach ($obj->attendance_calendar as $attendance_calendar) {
3705
                        unset($attendance_calendar['id']);
3706
                        unset($attendance_calendar['iid']);
3707
3708
                        $attendance_calendar['attendance_id'] = $last_id;
3709
                        $attendance_calendar['c_id'] = $this->destination_course_id;
3710
                        $attendanceCalendarId = Database::insert(
3711
                            $table_attendance_calendar,
3712
                            $attendance_calendar
3713
                        );
3714
3715
                        $sql = "UPDATE $table_attendance_calendar SET id = iid WHERE iid = $attendanceCalendarId";
3716
                        Database::query($sql);
3717
                    }
3718
                }
3719
            }
3720
        }
3721
    }
3722
3723
    /**
3724
     * Restore Works.
3725
     *
3726
     * @param int $sessionId
3727
     */
3728
    public function restore_works($sessionId = 0)
3729
    {
3730
        require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
3731
        if ($this->course->has_resources(RESOURCE_WORK)) {
3732
            $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION_ASSIGNMENT);
3733
3734
            $resources = $this->course->resources;
3735
            foreach ($resources[RESOURCE_WORK] as $obj) {
3736
                // check resources inside html from ckeditor tool and copy correct urls into recipient course
3737
                $obj->params['description'] = DocumentManager::replaceUrlWithNewCourseCode(
3738
                    $obj->params['description'],
3739
                    $this->course->code,
3740
                    $this->course->destination_path,
3741
                    $this->course->backup_path,
3742
                    $this->course->info['path']
3743
                );
3744
3745
                $id_work = $obj->params['id'];
3746
                $obj->params['id'] = null;
3747
                $obj->params['c_id'] = $this->destination_course_info['real_id'];
3748
3749
                // re-create dir
3750
                // @todo check security against injection of dir in crafted course backup here!
3751
                $path = $obj->params['url'];
3752
                $path = '/'.str_replace('/', '', substr($path, 1));
3753
3754
                $workData = [];
3755
3756
                switch ($this->file_option) {
3757
                    case FILE_SKIP:
3758
                        $workData = get_work_data_by_path(
3759
                            $path,
3760
                            $this->destination_course_info['real_id']
3761
                        );
3762
                        if (!empty($workData)) {
3763
                            break;
3764
                        }
3765
                        break;
3766
                    case FILE_OVERWRITE:
3767
                        if (!empty($this->course_origin_id)) {
3768
                            $sql = 'SELECT * FROM '.$table.'
3769
                                    WHERE
3770
                                        c_id = '.$this->course_origin_id.' AND
3771
                                        publication_id = '.$id_work;
3772
                            $result = Database::query($sql);
3773
                            $cant = Database::num_rows($result);
3774
                            if ($cant > 0) {
3775
                                $row = Database::fetch_assoc($result);
3776
                            }
3777
3778
                            $obj->params['enableExpiryDate'] = empty($row['expires_on']) ? false : true;
3779
                            $obj->params['enableEndDate'] = empty($row['ends_on']) ? false : true;
3780
                            $obj->params['expires_on'] = $row['expires_on'];
3781
                            $obj->params['ends_on'] = $row['ends_on'];
3782
                            $obj->params['enable_qualification'] = $row['enable_qualification'];
3783
                            $obj->params['add_to_calendar'] = !empty($row['add_to_calendar']) ? 1 : 0;
3784
                        }
3785
                        //no break
3786
                    case FILE_RENAME:
3787
                        $workData = get_work_data_by_path(
3788
                            $path,
3789
                            $this->destination_course_info['real_id']
3790
                        );
3791
                        break;
3792
                }
3793
3794
                $obj->params['work_title'] = $obj->params['title'];
3795
                $obj->params['new_dir'] = $obj->params['title'];
3796
3797
                if (empty($workData)) {
3798
                    $workId = addDir(
3799
                        $obj->params,
3800
                        api_get_user_id(),
3801
                        $this->destination_course_info,
3802
                        0,
3803
                        $sessionId
3804
                    );
3805
                    $this->course->resources[RESOURCE_WORK][$id_work]->destination_id = $workId;
3806
                } else {
3807
                    $workId = $workData['iid'];
3808
                    updateWork(
3809
                        $workId,
3810
                        $obj->params,
3811
                        $this->destination_course_info,
3812
                        $sessionId
3813
                    );
3814
                    updatePublicationAssignment(
3815
                        $workId,
3816
                        $obj->params,
3817
                        $this->destination_course_info,
3818
                        0
3819
                    );
3820
                    $this->course->resources[RESOURCE_WORK][$id_work]->destination_id = $workId;
3821
                }
3822
            }
3823
        }
3824
    }
3825
3826
    /**
3827
     * Restore gradebook.
3828
     *
3829
     * @param int $sessionId
3830
     *
3831
     * @return bool
3832
     */
3833
    public function restore_gradebook($sessionId = 0)
3834
    {
3835
        if (in_array($this->file_option, [FILE_SKIP, FILE_RENAME])) {
3836
            return false;
3837
        }
3838
        // if overwrite
3839
        if ($this->course->has_resources(RESOURCE_GRADEBOOK)) {
3840
            $resources = $this->course->resources;
3841
            $destinationCourseCode = $this->destination_course_info['code'];
3842
            // Delete destination gradebook
3843
            $cats = \Category::load(
3844
                null,
3845
                null,
3846
                $destinationCourseCode,
3847
                null,
3848
                null,
3849
                $sessionId
3850
            );
3851
3852
            if (!empty($cats)) {
3853
                /** @var \Category $cat */
3854
                foreach ($cats as $cat) {
3855
                    $cat->delete_all();
3856
                }
3857
            }
3858
3859
            /** @var GradeBookBackup $obj */
3860
            foreach ($resources[RESOURCE_GRADEBOOK] as $id => $obj) {
3861
                if (!empty($obj->categories)) {
3862
                    $categoryIdList = [];
3863
                    /** @var \Category $cat */
3864
                    foreach ($obj->categories as $cat) {
3865
                        $cat->set_course_code($destinationCourseCode);
3866
                        $cat->set_session_id($sessionId);
3867
3868
                        $parentId = $cat->get_parent_id();
3869
                        if (!empty($parentId)) {
3870
                            if (isset($categoryIdList[$parentId])) {
3871
                                $cat->set_parent_id($categoryIdList[$parentId]);
3872
                            }
3873
                        }
3874
                        $oldId = $cat->get_id();
3875
                        $categoryId = $cat->add();
3876
                        $categoryIdList[$oldId] = $categoryId;
3877
                        if (!empty($cat->evaluations)) {
3878
                            /** @var \Evaluation $evaluation */
3879
                            foreach ($cat->evaluations as $evaluation) {
3880
                                $evaluation->set_category_id($categoryId);
3881
                                $evaluation->set_course_code($destinationCourseCode);
3882
                                $evaluation->setSessionId($sessionId);
3883
                                $evaluation->add();
3884
                            }
3885
                        }
3886
3887
                        if (!empty($cat->links)) {
3888
                            /** @var \AbstractLink $link */
3889
                            foreach ($cat->links as $link) {
3890
                                $link->set_category_id($categoryId);
3891
                                $link->set_course_code($destinationCourseCode);
3892
                                $link->set_session_id($sessionId);
3893
                                $import = false;
3894
                                $itemId = $link->get_ref_id();
3895
                                switch ($link->get_type()) {
3896
                                    case LINK_EXERCISE:
3897
                                        $type = RESOURCE_QUIZ;
3898
                                        break;
3899
                                    /*case LINK_DROPBOX:
3900
                                        break;*/
3901
                                    case LINK_STUDENTPUBLICATION:
3902
                                        $type = RESOURCE_WORK;
3903
                                        break;
3904
                                    case LINK_LEARNPATH:
3905
                                        $type = RESOURCE_LEARNPATH;
3906
                                        break;
3907
                                    case LINK_FORUM_THREAD:
3908
                                        $type = RESOURCE_FORUMTOPIC;
3909
                                        break;
3910
                                    case LINK_ATTENDANCE:
3911
                                        $type = RESOURCE_ATTENDANCE;
3912
                                        break;
3913
                                    case LINK_SURVEY:
3914
                                        $type = RESOURCE_ATTENDANCE;
3915
                                        break;
3916
                                    case LINK_HOTPOTATOES:
3917
                                        $type = RESOURCE_QUIZ;
3918
                                        break;
3919
                                }
3920
3921
                                if ($this->course->has_resources($type) &&
3922
                                    isset($this->course->resources[$type][$itemId])
3923
                                ) {
3924
                                    $item = $this->course->resources[$type][$itemId];
3925
                                    if ($item && $item->is_restored()) {
3926
                                        $link->set_ref_id($item->destination_id);
3927
                                        $import = true;
3928
                                    }
3929
                                }
3930
3931
                                if ($import) {
3932
                                    $link->add();
3933
                                }
3934
                            }
3935
                        }
3936
                    }
3937
                }
3938
            }
3939
        }
3940
    }
3941
3942
    /**
3943
     * Restore course assets (not included in documents).
3944
     */
3945
    public function restore_assets()
3946
    {
3947
        if ($this->course->has_resources(RESOURCE_ASSET)) {
3948
            $resources = $this->course->resources;
3949
            $path = api_get_path(SYS_COURSE_PATH).$this->course->destination_path.'/';
3950
3951
            foreach ($resources[RESOURCE_ASSET] as $asset) {
3952
                if (is_file($this->course->backup_path.'/'.$asset->path) &&
3953
                    is_readable($this->course->backup_path.'/'.$asset->path) &&
3954
                    is_dir(dirname($path.$asset->path)) &&
3955
                    is_writeable(dirname($path.$asset->path))
3956
                ) {
3957
                    switch ($this->file_option) {
3958
                        case FILE_SKIP:
3959
                            break;
3960
                        case FILE_OVERWRITE:
3961
                            copy(
3962
                                $this->course->backup_path.'/'.$asset->path,
3963
                                $path.$asset->path
3964
                            );
3965
                            break;
3966
                    }
3967
                }
3968
            }
3969
        }
3970
    }
3971
3972
    /**
3973
     * @param string $str
3974
     *
3975
     * @return string
3976
     */
3977
    public function DBUTF8($str)
3978
    {
3979
        if (UTF8_CONVERT) {
3980
            $str = utf8_encode($str);
3981
        }
3982
3983
        return $str;
3984
    }
3985
3986
    /**
3987
     * @param string $str
3988
     *
3989
     * @return string
3990
     */
3991
    public function DBUTF8escapestring($str)
3992
    {
3993
        if (UTF8_CONVERT) {
3994
            $str = utf8_encode($str);
3995
        }
3996
3997
        return Database::escape_string($str);
3998
    }
3999
4000
    /**
4001
     * @param array $array
4002
     *
4003
     * @return mixed
4004
     */
4005
    public function DBUTF8_array($array)
4006
    {
4007
        if (UTF8_CONVERT) {
4008
            foreach ($array as &$item) {
4009
                $item = utf8_encode($item);
4010
            }
4011
4012
            return $array;
4013
        } else {
4014
            return $array;
4015
        }
4016
    }
4017
4018
    /**
4019
     * @param int $groupId
4020
     *
4021
     * @return array
4022
     */
4023
    public function checkGroupId($groupId)
4024
    {
4025
        return \GroupManager::get_group_properties($groupId);
4026
    }
4027
4028
    /**
4029
     * @param string $documentPath
4030
     * @param string $webEditorCss
4031
     */
4032
    public function fixEditorHtmlContent($documentPath, $webEditorCss = '')
4033
    {
4034
        $extension = pathinfo(basename($documentPath), PATHINFO_EXTENSION);
4035
4036
        switch ($extension) {
4037
            case 'html':
4038
            case 'htm':
4039
                $contents = file_get_contents($documentPath);
4040
                $contents = str_replace(
4041
                    '{{css_editor}}',
4042
                    $webEditorCss,
4043
                    $contents
4044
                );
4045
                file_put_contents($documentPath, $contents);
4046
                break;
4047
        }
4048
    }
4049
4050
    /**
4051
     * Check if user exist otherwise use current user.
4052
     *
4053
     * @param int  $userId
4054
     * @param bool $returnNull
4055
     *
4056
     * @return int
4057
     */
4058
    private function checkUserId($userId, $returnNull = false)
4059
    {
4060
        if (!empty($userId)) {
4061
            $userInfo = api_get_user_info($userId);
4062
            if (empty($userInfo)) {
4063
                return api_get_user_id();
4064
            }
4065
        }
4066
4067
        if ($returnNull) {
4068
            return null;
4069
        }
4070
4071
        if (empty($userId)) {
4072
            return api_get_user_id();
4073
        }
4074
4075
        return $userId;
4076
    }
4077
}
4078