Passed
Push — 1.11.x ( 6c301e...0d0c88 )
by Angel Fernando Quiroz
08:19
created

sanitizeSvgFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 14
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * FILE UPLOAD LIBRARY.
6
 *
7
 * This is the file upload library for Chamilo.
8
 * Include/require it in your code to use its functionality.
9
 *
10
 * @package chamilo.library
11
 *
12
 * @todo test and reorganise
13
 */
14
15
use enshrined\svgSanitize\Sanitizer;
16
17
/**
18
 * Changes the file name extension from .php to .phps
19
 * Useful for securing a site.
20
 *
21
 * @author Hugues Peeters <[email protected]>
22
 *
23
 * @param string $file_name Name of a file
24
 *
25
 * @return string the filename phps'ized
26
 */
27
function php2phps($file_name)
28
{
29
    return preg_replace('/\.(phar.?|php.?|phtml.?)(\.){0,1}.*$/i', '.phps', $file_name);
30
}
31
32
/**
33
 * Renames .htaccess & .HTACCESS to htaccess.txt.
34
 *
35
 * @param string $filename
36
 *
37
 * @return string
38
 */
39
function htaccess2txt($filename)
40
{
41
    return str_replace(['.htaccess', '.HTACCESS'], ['htaccess.txt', 'htaccess.txt'], $filename);
42
}
43
44
/**
45
 * This function executes our safety precautions
46
 * more functions can be added.
47
 *
48
 * @param string $filename
49
 *
50
 * @return string
51
 *
52
 * @see php2phps()
53
 * @see htaccess2txt()
54
 */
55
function disable_dangerous_file($filename)
56
{
57
    return htaccess2txt(php2phps($filename));
58
}
59
60
/**
61
 * Returns the name without extension, used for the title.
62
 *
63
 * @param string $name
64
 *
65
 * @return name without the extension
66
 */
67
function get_document_title($name)
68
{
69
    // If they upload .htaccess...
70
    $name = disable_dangerous_file($name);
71
    $ext = substr(strrchr($name, '.'), 0);
72
73
    if (empty($ext)) {
74
        return substr($name, 0, strlen($name));
75
    }
76
77
    return substr($name, 0, strlen($name) - strlen(strstr($name, $ext)));
78
}
79
80
/**
81
 * This function checks if the upload succeeded.
82
 *
83
 * @param array $uploaded_file ($_FILES)
84
 *
85
 * @return true if upload succeeded
86
 */
87
function process_uploaded_file($uploaded_file, $show_output = true)
88
{
89
    // Checking the error code sent with the file upload.
90
    if (isset($uploaded_file['error'])) {
91
        switch ($uploaded_file['error']) {
92
            case 1:
93
                // The uploaded file exceeds the upload_max_filesize directive in php.ini.
94
                if ($show_output) {
95
                    Display::addFlash(
96
                        Display::return_message(
97
                            get_lang('UplExceedMaxServerUpload').ini_get('upload_max_filesize'),
98
                            'error'
99
                        )
100
                    );
101
                }
102
103
                return false;
104
            case 2:
105
                // The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
106
                // Not used at the moment, but could be handy if we want to limit the size of an upload
107
                // (e.g. image upload in html editor).
108
                $max_file_size = (int) $_POST['MAX_FILE_SIZE'];
109
                if ($show_output) {
110
                    Display::addFlash(
111
                        Display::return_message(
112
                            get_lang('UplExceedMaxPostSize').format_file_size($max_file_size),
113
                            'error'
114
                        )
115
                    );
116
                }
117
118
                return false;
119
            case 3:
120
                // The uploaded file was only partially uploaded.
121
                if ($show_output) {
122
                    Display::addFlash(
123
                        Display::return_message(
124
                            get_lang('UplPartialUpload').' '.get_lang('PleaseTryAgain'),
125
                            'error'
126
                        )
127
                    );
128
                }
129
130
                return false;
131
            case 4:
132
                // No file was uploaded.
133
                if ($show_output) {
134
                    Display::addFlash(
135
                        Display::return_message(
136
                            get_lang('UplNoFileUploaded').' '.get_lang('UplSelectFileFirst'),
137
                            'error'
138
                        )
139
                    );
140
                }
141
142
                return false;
143
        }
144
    }
145
146
    if (!file_exists($uploaded_file['tmp_name'])) {
147
        // No file was uploaded.
148
        if ($show_output) {
149
            Display::addFlash(Display::return_message(get_lang('UplUploadFailed'), 'error'));
150
        }
151
152
        return false;
153
    }
154
155
    if (file_exists($uploaded_file['tmp_name'])) {
156
        $filesize = filesize($uploaded_file['tmp_name']);
157
        if (empty($filesize)) {
158
            // No file was uploaded.
159
            if ($show_output) {
160
                Display::addFlash(
161
                    Display::return_message(
162
                        get_lang('UplUploadFailedSizeIsZero'),
163
                        'error'
164
                    )
165
                );
166
            }
167
168
            return false;
169
        }
170
    }
171
172
    $course_id = api_get_course_id();
173
174
    //Checking course quota if we are in a course
175
    if (!empty($course_id)) {
176
        $max_filled_space = DocumentManager::get_course_quota();
177
        // Check if there is enough space to save the file
178
        if (!DocumentManager::enough_space($uploaded_file['size'], $max_filled_space)) {
179
            if ($show_output) {
180
                Display::addFlash(
181
                    Display::return_message(
182
                        get_lang('UplNotEnoughSpace'),
183
                        'error'
184
                    )
185
                );
186
            }
187
188
            return false;
189
        }
190
    }
191
192
    // case 0: default: We assume there is no error, the file uploaded with success.
193
    return true;
194
}
195
196
function sanitizeSvgFile(string $fullPath)
197
{
198
    $fileType = mime_content_type($fullPath);
199
200
    if ('image/svg+xml' !== $fileType) {
201
        return;
202
    }
203
204
    $svgContent = file_get_contents($fullPath);
205
206
    $sanitizer = new Sanitizer();
207
    $cleanSvg = $sanitizer->sanitize($svgContent);
208
209
    file_put_contents($fullPath, $cleanSvg);
210
}
211
212
/**
213
 * This function does the save-work for the documents.
214
 * It handles the uploaded file and adds the properties to the database
215
 * If unzip=1 and the file is a zipfile, it is extracted
216
 * If we decide to save ALL kinds of documents in one database,
217
 * we could extend this with a $type='document', 'scormdocument',...
218
 *
219
 * @param array  $courseInfo
220
 * @param array  $uploadedFile            ($_FILES)
221
 *                                        array(
222
 *                                        'name' => 'picture.jpg',
223
 *                                        'tmp_name' => '...', // absolute path
224
 *                                        );
225
 * @param string $documentDir             Example: /var/www/chamilo/courses/ABC/document
226
 * @param string $uploadPath              Example: /folder1/folder2/
227
 * @param int    $userId
228
 * @param int    $groupId                 group.id
229
 * @param int    $toUserId                User ID, or NULL for everybody
230
 * @param int    $unzip                   1/0
231
 * @param string $whatIfFileExists        overwrite, rename or warn if exists (default)
232
 * @param bool   $output                  optional output parameter
233
 * @param bool   $onlyUploadFile
234
 * @param string $comment
235
 * @param int    $sessionId
236
 * @param bool   $treat_spaces_as_hyphens
237
 *
238
 * So far only use for unzip_uploaded_document function.
239
 * If no output wanted on success, set to false.
240
 *
241
 * @return string path of the saved file
242
 */
243
function handle_uploaded_document(
244
    $courseInfo,
245
    $uploadedFile,
246
    $documentDir,
247
    $uploadPath,
248
    $userId,
249
    $groupId = 0,
250
    $toUserId = null,
251
    $unzip = 0,
252
    $whatIfFileExists = '',
253
    $output = true,
254
    $onlyUploadFile = false,
255
    $comment = null,
256
    $sessionId = null,
257
    $treat_spaces_as_hyphens = true
258
) {
259
    if (empty($uploadedFile) || empty($userId) || empty($courseInfo) || empty($documentDir) || empty($uploadPath)) {
260
        return false;
261
    }
262
263
    $userInfo = api_get_user_info();
264
    $uploadedFile['name'] = stripslashes($uploadedFile['name']);
265
    // Add extension to files without one (if possible)
266
    $uploadedFile['name'] = add_ext_on_mime($uploadedFile['name'], $uploadedFile['type']);
267
    $sessionId = (int) $sessionId;
268
    if (empty($sessionId)) {
269
        $sessionId = api_get_session_id();
270
    }
271
272
    $groupInfo = [];
273
    if (!empty($groupId)) {
274
        $groupInfo = GroupManager::get_group_properties($groupId);
275
    }
276
277
    // Just in case process_uploaded_file is not called
278
    $maxSpace = DocumentManager::get_course_quota();
279
    // Check if there is enough space to save the file
280
    if (!DocumentManager::enough_space($uploadedFile['size'], $maxSpace)) {
281
        if ($output) {
282
            Display::addFlash(Display::return_message(get_lang('UplNotEnoughSpace'), 'error'));
283
        }
284
285
        return false;
286
    }
287
288
    if (!Security::check_abs_path($documentDir.$uploadPath, $documentDir.'/')) {
289
        Display::addFlash(
290
            Display::return_message(
291
                get_lang('Forbidden'),
292
                'error'
293
            )
294
        );
295
296
        return false;
297
    }
298
299
    // If the want to unzip, check if the file has a .zip (or ZIP,Zip,ZiP,...) extension
300
    if ($unzip == 1 && preg_match('/.zip$/', strtolower($uploadedFile['name']))) {
301
        return unzip_uploaded_document(
302
            $courseInfo,
303
            $userInfo,
304
            $uploadedFile,
305
            $uploadPath,
306
            $documentDir,
307
            $maxSpace,
308
            $sessionId,
309
            $groupId,
310
            $output,
311
            $onlyUploadFile,
312
            $whatIfFileExists
313
        );
314
    } elseif ($unzip == 1 && !preg_match('/.zip$/', strtolower($uploadedFile['name']))) {
315
        // We can only unzip ZIP files (no gz, tar,...)
316
        if ($output) {
317
            Display::addFlash(
318
                Display::return_message(get_lang('UplNotAZip')." ".get_lang('PleaseTryAgain'), 'error')
319
            );
320
        }
321
322
        return false;
323
    } else {
324
        // Clean up the name, only ASCII characters should stay. (and strict)
325
        $cleanName = api_replace_dangerous_char($uploadedFile['name'], $treat_spaces_as_hyphens);
326
327
        // No "dangerous" files
328
        $cleanName = disable_dangerous_file($cleanName);
329
330
        // Checking file extension
331
        if (!filter_extension($cleanName)) {
332
            if ($output) {
333
                Display::addFlash(
334
                    Display::return_message(get_lang('UplUnableToSaveFileFilteredExtension'), 'error')
335
                );
336
            }
337
338
            return false;
339
        } else {
340
            // If the upload path differs from / (= root) it will need a slash at the end
341
            if ($uploadPath !== '/') {
342
                $uploadPath = $uploadPath.'/';
343
            }
344
345
            // Full path to where we want to store the file with trailing slash
346
            $whereToSave = $documentDir.$uploadPath;
347
348
            // At least if the directory doesn't exist, tell so
349
            if (!is_dir($whereToSave)) {
350
                if (!mkdir($whereToSave, api_get_permissions_for_new_directories())) {
351
                    if ($output) {
352
                        Display::addFlash(
353
                            Display::return_message(
354
                                get_lang('DestDirectoryDoesntExist').' ('.$uploadPath.')',
355
                                'error'
356
                            )
357
                        );
358
                    }
359
360
                    return false;
361
                }
362
            }
363
364
            // Just upload the file "as is"
365
            if ($onlyUploadFile) {
366
                $errorResult = moveUploadedFile($uploadedFile, $whereToSave.$cleanName);
367
                if ($errorResult) {
368
                    return $whereToSave.$cleanName;
369
                } else {
370
                    return $errorResult;
371
                }
372
            }
373
374
            /*
375
                Based in the clean name we generate a new filesystem name
376
                Using the session_id and group_id if values are not empty
377
            */
378
            $fileSystemName = DocumentManager::fixDocumentName(
379
                $cleanName,
380
                'file',
381
                $courseInfo,
382
                $sessionId,
383
                $groupId
384
            );
385
386
            // Name of the document without the extension (for the title)
387
            $documentTitle = get_document_title($uploadedFile['name']);
388
389
            // Size of the uploaded file (in bytes)
390
            $fileSize = $uploadedFile['size'];
391
392
            // File permissions
393
            $filePermissions = api_get_permissions_for_new_files();
394
395
            // Example: /var/www/chamilo/courses/xxx/document/folder/picture.jpg
396
            $fullPath = $whereToSave.$fileSystemName;
397
398
            // Example: /folder/picture.jpg
399
            $filePath = $uploadPath.$fileSystemName;
400
401
            $docId = DocumentManager::get_document_id(
402
                $courseInfo,
403
                $filePath,
404
                $sessionId
405
            );
406
407
            // What to do if the target file exists
408
            switch ($whatIfFileExists) {
409
                // Overwrite the file if it exists
410
                case 'overwrite':
411
                    // Check if the target file exists, so we can give another message
412
                    $fileExists = file_exists($fullPath);
413
414
                    if (moveUploadedFile($uploadedFile, $fullPath)) {
415
                        sanitizeSvgFile($fullPath);
416
                        chmod($fullPath, $filePermissions);
417
418
                        if ($fileExists && $docId) {
419
                            // UPDATE DATABASE
420
                            $documentId = DocumentManager::get_document_id(
421
                                $courseInfo,
422
                                $filePath
423
                            );
424
                            if (is_numeric($documentId)) {
425
                                // Update file size
426
                                update_existing_document(
427
                                    $courseInfo,
428
                                    $documentId,
429
                                    $uploadedFile['size']
430
                                );
431
432
                                // Update document item_property
433
                                api_item_property_update(
434
                                    $courseInfo,
435
                                    TOOL_DOCUMENT,
436
                                    $documentId,
437
                                    'DocumentUpdated',
438
                                    $userId,
439
                                    $groupInfo,
440
                                    $toUserId,
441
                                    null,
442
                                    null,
443
                                    $sessionId
444
                                );
445
446
                                // Redo visibility
447
                                api_set_default_visibility(
448
                                    $documentId,
449
                                    TOOL_DOCUMENT,
450
                                    null,
451
                                    $courseInfo
452
                                );
453
                            } else {
454
                                // There might be cases where the file exists on disk but there is no registration of
455
                                // that in the database
456
                                // In this case, and if we are in overwrite mode, overwrite and create the db record
457
                                $documentId = add_document(
458
                                    $courseInfo,
459
                                    $filePath,
460
                                    'file',
461
                                    $fileSize,
462
                                    $documentTitle,
463
                                    $comment,
464
                                    0,
465
                                    true,
466
                                    $groupId,
467
                                    $sessionId
468
                                );
469
470
                                if ($documentId) {
471
                                    // Put the document in item_property update
472
                                    api_item_property_update(
473
                                        $courseInfo,
474
                                        TOOL_DOCUMENT,
475
                                        $documentId,
476
                                        'DocumentAdded',
477
                                        $userId,
478
                                        $groupInfo,
479
                                        $toUserId,
480
                                        null,
481
                                        null,
482
                                        $sessionId
483
                                    );
484
485
                                    // Redo visibility
486
                                    api_set_default_visibility(
487
                                        $documentId,
488
                                        TOOL_DOCUMENT,
489
                                        null,
490
                                        $courseInfo
491
                                    );
492
                                }
493
                            }
494
495
                            // If the file is in a folder, we need to update all parent folders
496
                            item_property_update_on_folder($courseInfo, $uploadPath, $userId);
497
498
                            // Display success message with extra info to user
499
                            if ($output) {
500
                                Display::addFlash(
501
                                    Display::return_message(
502
                                        get_lang('UplUploadSucceeded').'<br /> '.
503
                                        $documentTitle.' '.get_lang('UplFileOverwritten'),
504
                                        'confirmation',
505
                                        false
506
                                    )
507
                                );
508
                            }
509
510
                            return $filePath;
511
                        } else {
512
                            // Put the document data in the database
513
                            $documentId = add_document(
514
                                $courseInfo,
515
                                $filePath,
516
                                'file',
517
                                $fileSize,
518
                                $documentTitle,
519
                                $comment,
520
                                0,
521
                                true,
522
                                $groupId,
523
                                $sessionId
524
                            );
525
526
                            if ($documentId) {
527
                                // Put the document in item_property update
528
                                api_item_property_update(
529
                                    $courseInfo,
530
                                    TOOL_DOCUMENT,
531
                                    $documentId,
532
                                    'DocumentAdded',
533
                                    $userId,
534
                                    $groupInfo,
535
                                    $toUserId,
536
                                    null,
537
                                    null,
538
                                    $sessionId
539
                                );
540
541
                                // Redo visibility
542
                                api_set_default_visibility($documentId, TOOL_DOCUMENT, null, $courseInfo);
543
                            }
544
545
                            // If the file is in a folder, we need to update all parent folders
546
                            item_property_update_on_folder($courseInfo, $uploadPath, $userId);
547
548
                            // Display success message to user
549
                            if ($output) {
550
                                Display::addFlash(
551
                                    Display::return_message(
552
                                        get_lang('UplUploadSucceeded').'<br /> '.$documentTitle,
553
                                        'confirmation',
554
                                        false
555
                                    )
556
                                );
557
                            }
558
559
                            return $filePath;
560
                        }
561
                    } else {
562
                        if ($output) {
563
                            Display::addFlash(
564
                                Display::return_message(
565
                                    get_lang('UplUnableToSaveFile'),
566
                                    'error',
567
                                    false
568
                                )
569
                            );
570
                        }
571
572
                        return false;
573
                    }
574
                    break;
575
                case 'rename':
576
                    // Rename the file if it exists
577
                    // Always rename.
578
                    $cleanName = DocumentManager::getUniqueFileName(
579
                        $uploadPath,
580
                        $cleanName,
581
                        $courseInfo,
582
                        $sessionId,
583
                        $groupId
584
                    );
585
586
                    $fileSystemName = DocumentManager::fixDocumentName(
587
                        $cleanName,
588
                        'file',
589
                        $courseInfo,
590
                        $sessionId,
591
                        $groupId
592
                    );
593
594
                    $documentTitle = disable_dangerous_file($cleanName);
595
                    $fullPath = $whereToSave.$fileSystemName;
596
                    $filePath = $uploadPath.$fileSystemName;
597
598
                    if (moveUploadedFile($uploadedFile, $fullPath)) {
599
                        sanitizeSvgFile($fullPath);
600
                        chmod($fullPath, $filePermissions);
601
                        // Put the document data in the database
602
                        $documentId = add_document(
603
                            $courseInfo,
604
                            $filePath,
605
                            'file',
606
                            $fileSize,
607
                            $documentTitle,
608
                            $comment, // comment
609
                            0, // read only
610
                            true, // save visibility
611
                            $groupId,
612
                            $sessionId
613
                        );
614
615
                        if ($documentId) {
616
                            // Update document item_property
617
                            api_item_property_update(
618
                                $courseInfo,
619
                                TOOL_DOCUMENT,
620
                                $documentId,
621
                                'DocumentAdded',
622
                                $userId,
623
                                $groupInfo,
624
                                $toUserId,
625
                                null,
626
                                null,
627
                                $sessionId
628
                            );
629
630
                            // Redo visibility
631
                            api_set_default_visibility($documentId, TOOL_DOCUMENT, null, $courseInfo);
632
                        }
633
634
                        // If the file is in a folder, we need to update all parent folders
635
                        item_property_update_on_folder($courseInfo, $uploadPath, $userId);
636
637
                        // Display success message to user
638
                        if ($output) {
639
                            Display::addFlash(
640
                                Display::return_message(
641
                                    get_lang('UplUploadSucceeded').'<br />'.
642
                                    get_lang('UplFileSavedAs').' '.$documentTitle,
643
                                    'success',
644
                                    false
645
                                )
646
                            );
647
                        }
648
649
                        return $filePath;
650
                    } else {
651
                        if ($output) {
652
                            Display::addFlash(
653
                                Display::return_message(
654
                                    get_lang('UplUnableToSaveFile'),
655
                                    'error',
656
                                    false
657
                                )
658
                            );
659
                        }
660
661
                        return false;
662
                    }
663
                    break;
664
                case 'nothing':
665
                    $fileExists = file_exists($fullPath);
666
                    if ($fileExists) {
667
                        if ($output) {
668
                            Display::addFlash(
669
                                Display::return_message(
670
                                    $uploadPath.$cleanName.' '.get_lang('UplAlreadyExists'),
671
                                    'warning',
672
                                    false
673
                                )
674
                            );
675
                        }
676
                        break;
677
                    }
678
                    // no break
679
                default:
680
                    // Only save the file if it doesn't exist or warn user if it does exist
681
                    if (file_exists($fullPath) && $docId) {
682
                        if ($output) {
683
                            Display::addFlash(
684
                                Display::return_message($cleanName.' '.get_lang('UplAlreadyExists'), 'warning', false)
685
                            );
686
                        }
687
                    } else {
688
                        if (moveUploadedFile($uploadedFile, $fullPath)) {
689
                            chmod($fullPath, $filePermissions);
690
691
                            // Put the document data in the database
692
                            $documentId = add_document(
693
                                $courseInfo,
694
                                $filePath,
695
                                'file',
696
                                $fileSize,
697
                                $documentTitle,
698
                                $comment,
699
                                0,
700
                                true,
701
                                $groupId,
702
                                $sessionId
703
                            );
704
705
                            if ($documentId) {
706
                                // Update document item_property
707
                                api_item_property_update(
708
                                    $courseInfo,
709
                                    TOOL_DOCUMENT,
710
                                    $documentId,
711
                                    'DocumentAdded',
712
                                    $userId,
713
                                    $groupInfo,
714
                                    $toUserId,
715
                                    null,
716
                                    null,
717
                                    $sessionId
718
                                );
719
                                // Redo visibility
720
                                api_set_default_visibility($documentId, TOOL_DOCUMENT, null, $courseInfo);
721
                            }
722
723
                            // If the file is in a folder, we need to update all parent folders
724
                            item_property_update_on_folder(
725
                                $courseInfo,
726
                                $uploadPath,
727
                                $userId
728
                            );
729
730
                            // Display success message to user
731
                            if ($output) {
732
                                Display::addFlash(
733
                                    Display::return_message(
734
                                        get_lang('UplUploadSucceeded').'<br /> '.$documentTitle,
735
                                        'confirm',
736
                                        false
737
                                    )
738
                                );
739
                            }
740
741
                            return $filePath;
742
                        } else {
743
                            if ($output) {
744
                                Display::addFlash(
745
                                    Display::return_message(
746
                                        get_lang('UplUnableToSaveFile'),
747
                                        'error',
748
                                        false
749
                                    )
750
                                );
751
                            }
752
753
                            return false;
754
                        }
755
                    }
756
                    break;
757
            }
758
        }
759
    }
760
}
761
762
function moveUploadedFile(array $file, string $storePath): bool
763
{
764
    $handleFromFile = isset($file['from_file']) && $file['from_file'];
765
    $moveFile = isset($file['move_file']) && $file['move_file'];
766
    $copyFile = isset($file['copy_file']) && $file['copy_file'];
767
    if ($moveFile) {
768
        $copied = copy($file['tmp_name'], $storePath);
769
770
        if (!$copied) {
771
            return false;
772
        }
773
    }
774
775
    if ($copyFile) {
776
        $copied = copy($file['tmp_name'], $storePath);
777
        unlink($file['tmp_name']);
778
779
        return $copied;
780
    }
781
782
    if ($handleFromFile) {
783
        return file_exists($file['tmp_name']);
784
    } else {
785
        return move_uploaded_file($file['tmp_name'], $storePath);
786
    }
787
}
788
789
/**
790
 * Checks if there is enough place to add a file on a directory
791
 * on the base of a maximum directory size allowed
792
 * deprecated: use enough_space instead!
793
 *
794
 * @author Hugues Peeters <[email protected]>
795
 *
796
 * @param int    $file_size     Size of the file in byte
797
 * @param string $dir           Path of the directory where the file should be added
798
 * @param int    $max_dir_space Maximum size of the diretory in byte
799
 *
800
 * @return bool true if there is enough space, false otherwise
801
 *
802
 * @see enough_size() uses  dir_total_space() function
803
 */
804
function enough_size($file_size, $dir, $max_dir_space)
805
{
806
    // If the directory is the archive directory, safely ignore the size limit
807
    if (api_get_path(SYS_ARCHIVE_PATH) == $dir) {
808
        return true;
809
    }
810
811
    if ($max_dir_space) {
812
        $already_filled_space = dir_total_space($dir);
813
        if (($file_size + $already_filled_space) > $max_dir_space) {
814
            return false;
815
        }
816
    }
817
818
    return true;
819
}
820
821
/**
822
 * Computes the size already occupied by a directory and is subdirectories.
823
 *
824
 * @author Hugues Peeters <[email protected]>
825
 *
826
 * @param string $dir_path Size of the file in byte
827
 *
828
 * @return int Return the directory size in bytes
829
 */
830
function dir_total_space($dir_path)
831
{
832
    $save_dir = getcwd();
833
    chdir($dir_path);
834
    $handle = opendir($dir_path);
835
    $sumSize = 0;
836
    $dirList = [];
837
    while ($element = readdir($handle)) {
838
        if ($element == '.' || $element == '..') {
839
            continue; // Skip the current and parent directories
840
        }
841
        if (is_file($element)) {
842
            $sumSize += filesize($element);
843
        }
844
        if (is_dir($element)) {
845
            $dirList[] = $dir_path.'/'.$element;
846
        }
847
    }
848
849
    closedir($handle);
850
851
    if (sizeof($dirList) > 0) {
852
        foreach ($dirList as $j) {
853
            $sizeDir = dir_total_space($j); // Recursivity
854
            $sumSize += $sizeDir;
855
        }
856
    }
857
    chdir($save_dir); // Return to initial position
858
859
    return $sumSize;
860
}
861
862
/**
863
 * Tries to add an extension to files without extension
864
 * Some applications on Macintosh computers don't add an extension to the files.
865
 * This subroutine try to fix this on the basis of the MIME type sent
866
 * by the browser.
867
 *
868
 * Note : some browsers don't send the MIME Type (e.g. Netscape 4).
869
 *        We don't have solution for this kind of situation
870
 *
871
 * @author Hugues Peeters <[email protected]>
872
 * @author Bert Vanderkimpen
873
 *
874
 * @param string $file_name Name of the file
875
 * @param string $file_type Type of the file
876
 *
877
 * @return string File name
878
 */
879
function add_ext_on_mime($file_name, $file_type)
880
{
881
    // Check whether the file has an extension AND whether the browser has sent a MIME Type
882
883
    if (!preg_match('/^.*\.[a-zA-Z_0-9]+$/', $file_name) && $file_type) {
884
        // Build a "MIME-types / extensions" connection table
885
        static $mime_type = [];
886
887
        $mime_type[] = 'application/msword';
888
        $extension[] = '.doc';
889
        $mime_type[] = 'application/rtf';
890
        $extension[] = '.rtf';
891
        $mime_type[] = 'application/vnd.ms-powerpoint';
892
        $extension[] = '.ppt';
893
        $mime_type[] = 'application/vnd.ms-excel';
894
        $extension[] = '.xls';
895
        $mime_type[] = 'application/pdf';
896
        $extension[] = '.pdf';
897
        $mime_type[] = 'application/postscript';
898
        $extension[] = '.ps';
899
        $mime_type[] = 'application/mac-binhex40';
900
        $extension[] = '.hqx';
901
        $mime_type[] = 'application/x-gzip';
902
        $extension[] = 'tar.gz';
903
        $mime_type[] = 'application/x-shockwave-flash';
904
        $extension[] = '.swf';
905
        $mime_type[] = 'application/x-stuffit';
906
        $extension[] = '.sit';
907
        $mime_type[] = 'application/x-tar';
908
        $extension[] = '.tar';
909
        $mime_type[] = 'application/zip';
910
        $extension[] = '.zip';
911
        $mime_type[] = 'application/x-tar';
912
        $extension[] = '.tar';
913
        $mime_type[] = 'text/html';
914
        $extension[] = '.html';
915
        $mime_type[] = 'text/plain';
916
        $extension[] = '.txt';
917
        $mime_type[] = 'text/rtf';
918
        $extension[] = '.rtf';
919
        $mime_type[] = 'img/gif';
920
        $extension[] = '.gif';
921
        $mime_type[] = 'img/jpeg';
922
        $extension[] = '.jpg';
923
        $mime_type[] = 'img/png';
924
        $extension[] = '.png';
925
        $mime_type[] = 'audio/midi';
926
        $extension[] = '.mid';
927
        $mime_type[] = 'audio/mpeg';
928
        $extension[] = '.mp3';
929
        $mime_type[] = 'audio/x-aiff';
930
        $extension[] = '.aif';
931
        $mime_type[] = 'audio/x-pn-realaudio';
932
        $extension[] = '.rm';
933
        $mime_type[] = 'audio/x-pn-realaudio-plugin';
934
        $extension[] = '.rpm';
935
        $mime_type[] = 'audio/x-wav';
936
        $extension[] = '.wav';
937
        $mime_type[] = 'video/mpeg';
938
        $extension[] = '.mpg';
939
        $mime_type[] = 'video/mpeg4-generic';
940
        $extension[] = '.mp4';
941
        $mime_type[] = 'video/quicktime';
942
        $extension[] = '.mov';
943
        $mime_type[] = 'video/x-msvideo';
944
        $extension[] = '.avi';
945
946
        $mime_type[] = 'video/x-ms-wmv';
947
        $extension[] = '.wmv';
948
        $mime_type[] = 'video/x-flv';
949
        $extension[] = '.flv';
950
        $mime_type[] = 'image/svg+xml';
951
        $extension[] = '.svg';
952
        $mime_type[] = 'image/svg+xml';
953
        $extension[] = '.svgz';
954
        $mime_type[] = 'video/ogg';
955
        $extension[] = '.ogv';
956
        $mime_type[] = 'audio/ogg';
957
        $extension[] = '.oga';
958
        $mime_type[] = 'application/ogg';
959
        $extension[] = '.ogg';
960
        $mime_type[] = 'application/ogg';
961
        $extension[] = '.ogx';
962
        $mime_type[] = 'application/x-freemind';
963
        $extension[] = '.mm';
964
965
        $mime_type[] = 'application/vnd.ms-word.document.macroEnabled.12';
966
        $extension[] = '.docm';
967
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
968
        $extension[] = '.docx';
969
        $mime_type[] = 'application/vnd.ms-word.template.macroEnabled.12';
970
        $extension[] = '.dotm';
971
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.template';
972
        $extension[] = '.dotx';
973
        $mime_type[] = 'application/vnd.ms-powerpoint.template.macroEnabled.12';
974
        $extension[] = '.potm';
975
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.template';
976
        $extension[] = '.potx';
977
        $mime_type[] = 'application/vnd.ms-powerpoint.addin.macroEnabled.12';
978
        $extension[] = '.ppam';
979
        $mime_type[] = 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12';
980
        $extension[] = '.ppsm';
981
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.slideshow';
982
        $extension[] = '.ppsx';
983
        $mime_type[] = 'application/vnd.ms-powerpoint.presentation.macroEnabled.12';
984
        $extension[] = '.pptm';
985
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
986
        $extension[] = '.pptx';
987
        $mime_type[] = 'application/vnd.ms-excel.addin.macroEnabled.12';
988
        $extension[] = '.xlam';
989
        $mime_type[] = 'application/vnd.ms-excel.sheet.binary.macroEnabled.12';
990
        $extension[] = '.xlsb';
991
        $mime_type[] = 'application/vnd.ms-excel.sheet.macroEnabled.12';
992
        $extension[] = '.xlsm';
993
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
994
        $extension[] = '.xlsx';
995
        $mime_type[] = 'application/vnd.ms-excel.template.macroEnabled.12';
996
        $extension[] = '.xltm';
997
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.template';
998
        $extension[] = '.xltx';
999
1000
        // Test on PC (files with no extension get application/octet-stream)
1001
        //$mime_type[] = 'application/octet-stream';      $extension[] = '.ext';
1002
        // Check whether the MIME type sent by the browser is within the table
1003
        foreach ($mime_type as $key => &$type) {
1004
            if ($type == $file_type) {
1005
                $file_name .= $extension[$key];
1006
                break;
1007
            }
1008
        }
1009
1010
        unset($mime_type, $extension, $type, $key); // Delete to eschew possible collisions
1011
    }
1012
1013
    return $file_name;
1014
}
1015
1016
/**
1017
 * Manages all the unzipping process of an uploaded file.
1018
 *
1019
 * @author Hugues Peeters <[email protected]>
1020
 *
1021
 * @param array  $uploaded_file    - follows the $_FILES Structure
1022
 * @param string $upload_path      - destination of the upload.
1023
 *                                 This path is to append to $base_work_dir
1024
 * @param string $base_work_dir    - base working directory of the module
1025
 * @param int    $max_filled_space - amount of bytes to not exceed in the base
1026
 *                                 working directory
1027
 *
1028
 * @return bool true if it succeeds false otherwise
1029
 */
1030
function unzip_uploaded_file($uploaded_file, $upload_path, $base_work_dir, $max_filled_space)
1031
{
1032
    $zip_file = new PclZip($uploaded_file['tmp_name']);
1033
1034
    // Check the zip content (real size and file extension)
1035
    if (file_exists($uploaded_file['tmp_name'])) {
1036
        $zip_content_array = $zip_file->listContent();
1037
        $ok_scorm = false;
1038
        $realFileSize = 0;
1039
        $ok_plantyn_scorm1 = false;
1040
        $ok_plantyn_scorm2 = false;
1041
        $ok_plantyn_scorm3 = false;
1042
        $ok_aicc_scorm = false;
1043
        foreach ($zip_content_array as $this_content) {
1044
            if (preg_match('~.(php.*|phtml|phar|htaccess)$~i', $this_content['filename'])) {
1045
                Display::addFlash(
1046
                    Display::return_message(get_lang('ZipNoPhp'))
1047
                );
1048
1049
                return false;
1050
            } elseif (stristr($this_content['filename'], 'imsmanifest.xml')) {
1051
                $ok_scorm = true;
1052
            } elseif (stristr($this_content['filename'], 'LMS')) {
1053
                $ok_plantyn_scorm1 = true;
1054
            } elseif (stristr($this_content['filename'], 'REF')) {
1055
                $ok_plantyn_scorm2 = true;
1056
            } elseif (stristr($this_content['filename'], 'SCO')) {
1057
                $ok_plantyn_scorm3 = true;
1058
            } elseif (stristr($this_content['filename'], 'AICC')) {
1059
                $ok_aicc_scorm = true;
1060
            }
1061
            $realFileSize += $this_content['size'];
1062
        }
1063
1064
        if (($ok_plantyn_scorm1 && $ok_plantyn_scorm2 && $ok_plantyn_scorm3) || $ok_aicc_scorm) {
1065
            $ok_scorm = true;
1066
        }
1067
1068
        if (!$ok_scorm && defined('CHECK_FOR_SCORM') && CHECK_FOR_SCORM) {
1069
            Display::addFlash(
1070
                Display::return_message(get_lang('NotScormContent'))
1071
            );
1072
1073
            return false;
1074
        }
1075
1076
        if (!enough_size($realFileSize, $base_work_dir, $max_filled_space)) {
1077
            Display::addFlash(
1078
                Display::return_message(get_lang('NoSpace'))
1079
            );
1080
1081
            return false;
1082
        }
1083
1084
        // It happens on Linux that $upload_path sometimes doesn't start with '/'
1085
        if ($upload_path[0] != '/' && substr($base_work_dir, -1, 1) != '/') {
1086
            $upload_path = '/'.$upload_path;
1087
        }
1088
1089
        if ($upload_path[strlen($upload_path) - 1] == '/') {
1090
            $upload_path = substr($upload_path, 0, -1);
1091
        }
1092
1093
        /*	Uncompressing phase */
1094
        $save_dir = getcwd();
1095
        chdir($base_work_dir.$upload_path);
1096
        $unzippingState = $zip_file->extract();
1097
        for ($j = 0; $j < count($unzippingState); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1098
            $state = $unzippingState[$j];
1099
            // Fix relative links in html files
1100
            $extension = strrchr($state['stored_filename'], '.');
1101
        }
1102
        if ($dir = @opendir($base_work_dir.$upload_path)) {
1103
            while ($file = readdir($dir)) {
1104
                if ($file != '.' && $file != '..') {
1105
                    $filetype = 'file';
1106
                    if (is_dir($base_work_dir.$upload_path.'/'.$file)) {
1107
                        $filetype = 'folder';
1108
                    }
1109
1110
                    $safe_file = api_replace_dangerous_char($file);
1111
                    $safe_file = disable_dangerous_file($safe_file);
1112
1113
                    @rename($base_work_dir.$upload_path.'/'.$file, $base_work_dir.$upload_path.'/'.$safe_file);
1114
                    set_default_settings($upload_path, $safe_file, $filetype);
1115
                }
1116
            }
1117
1118
            closedir($dir);
1119
        } else {
1120
            error_log('Could not create directory '.$base_work_dir.$upload_path.' to unzip files');
1121
        }
1122
        chdir($save_dir); // Back to previous dir position
1123
    }
1124
1125
    return true;
1126
}
1127
1128
/**
1129
 * Manages all the unzipping process of an uploaded document
1130
 * This uses the item_property table for properties of documents.
1131
 *
1132
 * @author Hugues Peeters <[email protected]>
1133
 * @author Bert Vanderkimpen
1134
 *
1135
 * @param array  $courseInfo
1136
 * @param array  $userInfo
1137
 * @param array  $uploaded_file    - follows the $_FILES Structure
1138
 * @param string $uploadPath       - destination of the upload.
1139
 *                                 This path is to append to $base_work_dir
1140
 * @param string $base_work_dir    - base working directory of the module
1141
 * @param int    $maxFilledSpace   - amount of bytes to not exceed in the base
1142
 *                                 working directory
1143
 * @param int    $sessionId
1144
 * @param int    $groupId          group.id
1145
 * @param bool   $output           Optional. If no output not wanted on success, set to false.
1146
 * @param bool   $onlyUploadFile
1147
 * @param string $whatIfFileExists (only works if $onlyUploadFile is false)
1148
 *
1149
 * @return bool true if it succeeds false otherwise
1150
 */
1151
function unzip_uploaded_document(
1152
    $courseInfo,
1153
    $userInfo,
1154
    $uploaded_file,
1155
    $uploadPath,
1156
    $base_work_dir,
1157
    $maxFilledSpace,
1158
    $sessionId = 0,
1159
    $groupId = 0,
1160
    $output = true,
1161
    $onlyUploadFile = false,
1162
    $whatIfFileExists = 'overwrite'
1163
) {
1164
    if (empty($courseInfo) || empty($userInfo) || empty($uploaded_file) || empty($uploadPath)) {
1165
        return false;
1166
    }
1167
1168
    $zip = new PclZip($uploaded_file['tmp_name']);
1169
1170
    // Check the zip content (real size and file extension)
1171
    $zip_content_array = (array) $zip->listContent();
1172
    $realSize = 0;
1173
    foreach ($zip_content_array as &$this_content) {
1174
        $realSize += $this_content['size'];
1175
    }
1176
1177
    if (!DocumentManager::enough_space($realSize, $maxFilledSpace)) {
1178
        echo Display::return_message(get_lang('UplNotEnoughSpace'), 'error');
1179
1180
        return false;
1181
    }
1182
1183
    $folder = api_get_unique_id();
1184
    $destinationDir = api_get_path(SYS_ARCHIVE_PATH).$folder;
1185
    mkdir($destinationDir, api_get_permissions_for_new_directories(), true);
1186
1187
    // Uncompress zip file
1188
    // We extract using a callback function that "cleans" the path
1189
    $zip->extract(
1190
        PCLZIP_OPT_PATH,
1191
        $destinationDir,
1192
        PCLZIP_CB_PRE_EXTRACT,
1193
        'clean_up_files_in_zip',
1194
        PCLZIP_OPT_REPLACE_NEWER
1195
    );
1196
1197
    if ($onlyUploadFile === false) {
1198
        // Add all documents in the unzipped folder to the database
1199
        add_all_documents_in_folder_to_database(
1200
            $courseInfo,
1201
            $userInfo,
1202
            $base_work_dir,
1203
            $destinationDir,
1204
            $sessionId,
1205
            $groupId,
1206
            $output,
1207
            ['path' => $uploadPath],
1208
            $whatIfFileExists
1209
        );
1210
    } else {
1211
        // Copy result
1212
        $fs = new \Symfony\Component\Filesystem\Filesystem();
1213
        $fs->mirror($destinationDir, $base_work_dir.$uploadPath, null, ['overwrite']);
1214
    }
1215
1216
    if (is_dir($destinationDir)) {
1217
        rmdirr($destinationDir);
1218
    }
1219
1220
    return true;
1221
}
1222
1223
/**
1224
 * This function is a callback function that is used while extracting a zipfile
1225
 * http://www.phpconcept.net/pclzip/man/en/index.php?options-pclzip_cb_pre_extract.
1226
 *
1227
 * @param array $p_event
1228
 * @param array $p_header
1229
 *
1230
 * @return int (If the function returns 1, then the extraction is resumed, if 0 the path was skipped)
1231
 */
1232
function clean_up_files_in_zip($p_event, &$p_header)
1233
{
1234
    $originalStoredFileName = $p_header['stored_filename'];
1235
    $baseName = basename($originalStoredFileName);
1236
    // Skip files
1237
    $skipFiles = [
1238
        '__MACOSX',
1239
        '.Thumbs.db',
1240
        'Thumbs.db',
1241
    ];
1242
1243
    if (in_array($baseName, $skipFiles)) {
1244
        return 0;
1245
    }
1246
    $modifiedStoredFileName = clean_up_path($originalStoredFileName);
1247
    $p_header['filename'] = str_replace($originalStoredFileName, $modifiedStoredFileName, $p_header['filename']);
1248
1249
    return 1;
1250
}
1251
1252
function cleanZipFilesNoRename($p_event, &$p_header)
1253
{
1254
    $originalStoredFileName = $p_header['stored_filename'];
1255
    $baseName = basename($originalStoredFileName);
1256
    // Skip files
1257
    $skipFiles = [
1258
        '__MACOSX',
1259
        '.Thumbs.db',
1260
        'Thumbs.db',
1261
    ];
1262
1263
    if (in_array($baseName, $skipFiles)) {
1264
        return 0;
1265
    }
1266
    $modifiedStoredFileName = clean_up_path($originalStoredFileName, false);
1267
    $p_header['filename'] = str_replace($originalStoredFileName, $modifiedStoredFileName, $p_header['filename']);
1268
1269
    return 1;
1270
}
1271
1272
/**
1273
 * Allow .htaccess file.
1274
 *
1275
 * @param $p_event
1276
 * @param $p_header
1277
 *
1278
 * @return int
1279
 */
1280
function cleanZipFilesAllowHtaccess($p_event, &$p_header)
1281
{
1282
    $originalStoredFileName = $p_header['stored_filename'];
1283
    $baseName = basename($originalStoredFileName);
1284
1285
    $allowFiles = ['.htaccess'];
1286
    if (in_array($baseName, $allowFiles)) {
1287
        return 1;
1288
    }
1289
1290
    // Skip files
1291
    $skipFiles = [
1292
        '__MACOSX',
1293
        '.Thumbs.db',
1294
        'Thumbs.db',
1295
    ];
1296
1297
    if (in_array($baseName, $skipFiles)) {
1298
        return 0;
1299
    }
1300
    $modifiedStoredFileName = clean_up_path($originalStoredFileName);
1301
    $p_header['filename'] = str_replace($originalStoredFileName, $modifiedStoredFileName, $p_header['filename']);
1302
1303
    return 1;
1304
}
1305
1306
/**
1307
 * This function cleans up a given path
1308
 * by eliminating dangerous file names and cleaning them.
1309
 *
1310
 * @param string $path
1311
 * @param bool   $replaceName
1312
 *
1313
 * @return string
1314
 *
1315
 * @see disable_dangerous_file()
1316
 * @see api_replace_dangerous_char()
1317
 */
1318
function clean_up_path($path, $replaceName = true)
1319
{
1320
    // Split the path in folders and files
1321
    $path_array = explode('/', $path);
1322
    // Clean up every folder and filename in the path
1323
    foreach ($path_array as $key => &$val) {
1324
        // We don't want to lose the dots in ././folder/file (cfr. zipfile)
1325
        if ($val != '.') {
1326
            if ($replaceName) {
1327
                $val = api_replace_dangerous_char($val);
1328
            }
1329
            $val = disable_dangerous_file($val);
1330
        }
1331
    }
1332
    // Join the "cleaned" path (modified in-place as passed by reference)
1333
    $path = implode('/', $path_array);
1334
    filter_extension($path);
1335
1336
    return $path;
1337
}
1338
1339
/**
1340
 * Checks if the file is dangerous, based on extension and/or mimetype.
1341
 * The list of extensions accepted/rejected can be found from
1342
 * api_get_setting('upload_extensions_exclude') and api_get_setting('upload_extensions_include').
1343
 *
1344
 * @param string $filename passed by reference. The filename will be modified
1345
 *                         if filter rules say so! (you can include path but the filename should look like 'abc.html')
1346
 *
1347
 * @return int 0 to skip file, 1 to keep file
1348
 */
1349
function filter_extension(&$filename)
1350
{
1351
    if (substr($filename, -1) == '/') {
1352
        return 1; // Authorize directories
1353
    }
1354
    $blacklist = api_get_setting('upload_extensions_list_type');
1355
    if ($blacklist != 'whitelist') { // if = blacklist
1356
        $extensions = explode(';', strtolower(api_get_setting('upload_extensions_blacklist')));
1357
1358
        $skip = api_get_setting('upload_extensions_skip');
1359
        $ext = strrchr($filename, '.');
1360
        $ext = substr($ext, 1);
1361
        if (empty($ext)) {
1362
            return 1; // We're in blacklist mode, so accept empty extensions
1363
        }
1364
        if (in_array(strtolower($ext), $extensions)) {
1365
            if ($skip == 'true') {
1366
                return 0;
1367
            } else {
1368
                $new_ext = getReplacedByExtension();
1369
                $filename = str_replace('.'.$ext, '.'.$new_ext, $filename);
1370
1371
                return 1;
1372
            }
1373
        } else {
1374
            return 1;
1375
        }
1376
    } else {
1377
        $extensions = explode(';', strtolower(api_get_setting('upload_extensions_whitelist')));
1378
        $skip = api_get_setting('upload_extensions_skip');
1379
        $ext = strrchr($filename, '.');
1380
        $ext = substr($ext, 1);
1381
        if (empty($ext)) {
1382
            return 1; // Accept empty extensions
1383
        }
1384
        if (!in_array(strtolower($ext), $extensions)) {
1385
            if ($skip == 'true') {
1386
                return 0;
1387
            } else {
1388
                $new_ext = getReplacedByExtension();
1389
                $filename = str_replace('.'.$ext, '.'.$new_ext, $filename);
1390
1391
                return 1;
1392
            }
1393
        } else {
1394
            return 1;
1395
        }
1396
    }
1397
}
1398
1399
function getReplacedByExtension()
1400
{
1401
    $extension = api_get_setting('upload_extensions_replace_by');
1402
1403
    return 'REPLACED_'.api_replace_dangerous_char(str_replace('.', '', $extension));
1404
}
1405
1406
/**
1407
 * Adds a new document to the database.
1408
 *
1409
 * @param array  $courseInfo
1410
 * @param string $path
1411
 * @param string $fileType
1412
 * @param int    $fileSize
1413
 * @param string $title
1414
 * @param string $comment
1415
 * @param int    $readonly
1416
 * @param bool   $saveVisibility
1417
 * @param int    $group_id         group.id
1418
 * @param int    $sessionId        Session ID, if any
1419
 * @param int    $userId           creator user id
1420
 * @param bool   $sendNotification
1421
 *
1422
 * @return int id if inserted document
1423
 */
1424
function add_document(
1425
    $courseInfo,
1426
    $path,
1427
    $fileType,
1428
    $fileSize,
1429
    $title,
1430
    $comment = null,
1431
    $readonly = 0,
1432
    $saveVisibility = true,
1433
    $group_id = 0,
1434
    $sessionId = 0,
1435
    $userId = 0,
1436
    $sendNotification = true
1437
) {
1438
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
1439
    $userId = empty($userId) ? api_get_user_id() : $userId;
1440
1441
    $readonly = (int) $readonly;
1442
    $c_id = $courseInfo['real_id'];
1443
    $params = [
1444
        'c_id' => $c_id,
1445
        'path' => $path,
1446
        'filetype' => $fileType,
1447
        'size' => $fileSize,
1448
        'title' => $title,
1449
        'comment' => $comment,
1450
        'readonly' => $readonly,
1451
        'session_id' => $sessionId,
1452
    ];
1453
    $table = Database::get_course_table(TABLE_DOCUMENT);
1454
    $documentId = Database::insert($table, $params);
1455
    if ($documentId) {
1456
        $sql = "UPDATE $table SET id = iid WHERE iid = $documentId";
1457
        Database::query($sql);
1458
1459
        if ($saveVisibility) {
1460
            api_set_default_visibility(
1461
                $documentId,
1462
                TOOL_DOCUMENT,
1463
                $group_id,
1464
                $courseInfo,
1465
                $sessionId,
1466
                $userId
1467
            );
1468
        }
1469
1470
        $allowNotification = api_get_configuration_value('send_notification_when_document_added');
1471
        if ($sendNotification && $allowNotification) {
1472
            $courseTitle = $courseInfo['title'];
1473
            if (!empty($sessionId)) {
1474
                $sessionInfo = api_get_session_info($sessionId);
1475
                $courseTitle .= " ( ".$sessionInfo['name'].") ";
1476
            }
1477
1478
            $url = api_get_path(WEB_CODE_PATH).
1479
                'document/showinframes.php?cidReq='.$courseInfo['code'].'&id_session='.$sessionId.'&id='.$documentId;
1480
            $link = Display::url(basename($title), $url, ['target' => '_blank']);
1481
            $userInfo = api_get_user_info($userId);
1482
1483
            $message = sprintf(
1484
                get_lang('DocumentXHasBeenAddedToDocumentInYourCourseXByUserX'),
1485
                $link,
1486
                $courseTitle,
1487
                $userInfo['complete_name']
1488
            );
1489
            $subject = sprintf(get_lang('NewDocumentAddedToCourseX'), $courseTitle);
1490
            MessageManager::sendMessageToAllUsersInCourse($subject, $message, $courseInfo, $sessionId);
1491
        }
1492
1493
        return $documentId;
1494
    } else {
1495
        return false;
1496
    }
1497
}
1498
1499
/**
1500
 * Updates an existing document in the database
1501
 * as the file exists, we only need to change the size.
1502
 *
1503
 * @param array $_course
1504
 * @param int   $documentId
1505
 * @param int   $filesize
1506
 * @param int   $readonly
1507
 *
1508
 * @return bool true /false
1509
 */
1510
function update_existing_document($_course, $documentId, $filesize, $readonly = 0)
1511
{
1512
    $document_table = Database::get_course_table(TABLE_DOCUMENT);
1513
    $documentId = intval($documentId);
1514
    $filesize = intval($filesize);
1515
    $readonly = intval($readonly);
1516
    $course_id = $_course['real_id'];
1517
1518
    $sql = "UPDATE $document_table SET
1519
            size = '$filesize',
1520
            readonly = '$readonly'
1521
			WHERE c_id = $course_id AND id = $documentId";
1522
    if (Database::query($sql)) {
1523
        return true;
1524
    } else {
1525
        return false;
1526
    }
1527
}
1528
1529
/**
1530
 * This function updates the last_edit_date, last edit user id on all folders in a given path.
1531
 *
1532
 * @param array  $_course
1533
 * @param string $path
1534
 * @param int    $user_id
1535
 */
1536
function item_property_update_on_folder($_course, $path, $user_id)
1537
{
1538
    // If we are in the root, just return... no need to update anything
1539
    if ($path == '/') {
1540
        return;
1541
    }
1542
1543
    $user_id = intval($user_id);
1544
1545
    // If the given path ends with a / we remove it
1546
    $endchar = substr($path, strlen($path) - 1, 1);
1547
    if ($endchar == '/') {
1548
        $path = substr($path, 0, strlen($path) - 1);
1549
    }
1550
1551
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1552
1553
    // Get the time
1554
    $time = api_get_utc_datetime();
1555
1556
    // Det all paths in the given path
1557
    // /folder/subfolder/subsubfolder/file
1558
    // if file is updated, subsubfolder, subfolder and folder are updated
1559
    $exploded_path = explode('/', $path);
1560
    $course_id = api_get_course_int_id();
1561
    $newpath = '';
1562
    foreach ($exploded_path as $key => &$value) {
1563
        // We don't want a slash before our first slash
1564
        if ($key != 0) {
1565
            $newpath .= '/'.$value;
1566
            // Select ID of given folder
1567
            $folder_id = DocumentManager::get_document_id($_course, $newpath);
1568
1569
            if ($folder_id) {
1570
                $sql = "UPDATE $table SET
1571
				        lastedit_date = '$time',
1572
				        lastedit_type = 'DocumentInFolderUpdated',
1573
				        lastedit_user_id='$user_id'
1574
						WHERE
1575
						    c_id = $course_id AND
1576
						    tool='".TOOL_DOCUMENT."' AND
1577
						    ref = '$folder_id'";
1578
                Database::query($sql);
1579
            }
1580
        }
1581
    }
1582
}
1583
1584
/**
1585
 * Adds file to document table in database
1586
 * deprecated: use file_set_default_settings instead.
1587
 *
1588
 * @author	Olivier Cauberghe <[email protected]>
1589
 *
1590
 * @param	path,filename
1591
 * action:	Adds an entry to the document table with the default settings
1592
 */
1593
function set_default_settings($upload_path, $filename, $filetype = 'file')
1594
{
1595
    $dbTable = Database::get_course_table(TABLE_DOCUMENT);
1596
    global $default_visibility;
1597
1598
    if (!$default_visibility) {
1599
        $default_visibility = 'v';
1600
    }
1601
    $filetype = Database::escape_string($filetype);
1602
1603
    $upload_path = str_replace('\\', '/', $upload_path);
1604
    $upload_path = str_replace('//', '/', $upload_path);
1605
1606
    if ($upload_path == '/') {
1607
        $upload_path = '';
1608
    } elseif (!empty($upload_path) && $upload_path[0] != '/') {
1609
        $upload_path = "/$upload_path";
1610
    }
1611
1612
    $endchar = substr($filename, strlen($filename) - 1, 1);
1613
1614
    if ($endchar == '/') {
1615
        $filename = substr($filename, 0, -1);
1616
    }
1617
    $filename = Database::escape_string($filename);
1618
    $query = "SELECT count(*) as bestaat FROM $dbTable
1619
              WHERE path='$upload_path/$filename'";
1620
    $result = Database::query($query);
1621
    $row = Database::fetch_array($result);
1622
    if ($row['bestaat'] > 0) {
1623
        $query = "UPDATE $dbTable SET
1624
		            path='$upload_path/$filename',
1625
		            visibility='$default_visibility',
1626
		            filetype='$filetype'
1627
		          WHERE path='$upload_path/$filename'";
1628
    } else {
1629
        $query = "INSERT INTO $dbTable (path,visibility,filetype)
1630
		          VALUES('$upload_path/$filename','$default_visibility','$filetype')";
1631
    }
1632
    Database::query($query);
1633
}
1634
1635
/**
1636
 * Retrieves the image path list in a html file.
1637
 *
1638
 * @author Hugues Peeters <[email protected]>
1639
 *
1640
 * @param string $html_file
1641
 *
1642
 * @return array -  images path list
1643
 */
1644
function search_img_from_html($html_file)
1645
{
1646
    $img_path_list = [];
1647
1648
    if (!$fp = fopen($html_file, 'r')) {
1649
        return;
1650
    }
1651
1652
    // Aearch and store occurences of the <img> tag in an array
1653
    $size_file = (filesize($html_file) === 0) ? 1 : filesize($html_file);
1654
    if (isset($fp) && $fp !== false) {
1655
        $buffer = fread($fp, $size_file);
1656
        if (strlen($buffer) >= 0 && $buffer !== false) {
1657
        } else {
1658
            exit('<center>Can not read file.</center>');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1659
        }
1660
    } else {
1661
        exit('<center>Can not read file.</center>');
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1662
    }
1663
    $matches = [];
1664
    if (preg_match_all('~<[[:space:]]*img[^>]*>~i', $buffer, $matches)) {
1665
        $img_tag_list = $matches[0];
1666
    }
1667
1668
    fclose($fp);
1669
    unset($buffer);
1670
1671
    // Search the image file path from all the <IMG> tag detected
1672
1673
    if (sizeof($img_tag_list) > 0) {
1674
        foreach ($img_tag_list as &$this_img_tag) {
1675
            if (preg_match('~src[[:space:]]*=[[:space:]]*[\"]{1}([^\"]+)[\"]{1}~i', $this_img_tag, $matches)) {
1676
                $img_path_list[] = $matches[1];
1677
            }
1678
        }
1679
        $img_path_list = array_unique($img_path_list); // Remove duplicate entries
1680
    }
1681
1682
    return $img_path_list;
1683
}
1684
1685
/**
1686
 * Creates a new directory trying to find a directory name
1687
 * that doesn't already exist.
1688
 *
1689
 * @author  Hugues Peeters <[email protected]>
1690
 * @author  Bert Vanderkimpen
1691
 *
1692
 * @param array  $_course                 current course information
1693
 * @param int    $user_id                 current user id
1694
 * @param int    $session_id
1695
 * @param int    $to_group_id             group.id
1696
 * @param int    $to_user_id
1697
 * @param string $base_work_dir           /var/www/chamilo/courses/ABC/document
1698
 * @param string $desired_dir_name        complete path of the desired name
1699
 *                                        Example: /folder1/folder2
1700
 * @param string $title                   "folder2"
1701
 * @param int    $visibility              (0 for invisible, 1 for visible, 2 for deleted)
1702
 * @param bool   $generateNewNameIfExists
1703
 * @param bool   $sendNotification        depends in conf setting "send_notification_when_document_added"
1704
 *
1705
 * @return string actual directory name if it succeeds,
1706
 *                boolean false otherwise
1707
 */
1708
function create_unexisting_directory(
1709
    $_course,
1710
    $user_id,
1711
    $session_id,
1712
    $to_group_id,
1713
    $to_user_id,
1714
    $base_work_dir,
1715
    $desired_dir_name,
1716
    $title = '',
1717
    $visibility = '',
1718
    $generateNewNameIfExists = false,
1719
    $sendNotification = true
1720
) {
1721
    $course_id = $_course['real_id'];
1722
    $session_id = (int) $session_id;
1723
1724
    $folderExists = DocumentManager::folderExists(
1725
        $desired_dir_name,
1726
        $_course,
1727
        $session_id,
1728
        $to_group_id
1729
    );
1730
1731
    if ($folderExists === true) {
1732
        if ($generateNewNameIfExists) {
1733
            $counter = 1;
1734
            while (1) {
1735
                $folderExists = DocumentManager::folderExists(
1736
                    $desired_dir_name.'_'.$counter,
1737
                    $_course,
1738
                    $session_id,
1739
                    $to_group_id
1740
                );
1741
1742
                if ($folderExists === false) {
1743
                    break;
1744
                }
1745
                $counter++;
1746
            }
1747
            $desired_dir_name = $desired_dir_name.'_'.$counter;
1748
        } else {
1749
            return false;
1750
        }
1751
    }
1752
1753
    $systemFolderName = $desired_dir_name;
1754
1755
    // Adding suffix
1756
    $suffix = DocumentManager::getDocumentSuffix(
1757
        $_course,
1758
        $session_id,
1759
        $to_group_id
1760
    );
1761
1762
    $systemFolderName .= $suffix;
1763
1764
    if ($title == null) {
1765
        $title = basename($desired_dir_name);
1766
    }
1767
1768
    if (!is_dir($base_work_dir.$systemFolderName)) {
1769
        $result = @mkdir(
1770
            $base_work_dir.$systemFolderName,
1771
            api_get_permissions_for_new_directories(),
1772
            true
1773
        );
1774
1775
        if ($result) {
1776
            // Check if pathname already exists inside document table
1777
            $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
1778
            $sql = "SELECT id, path FROM $tbl_document
1779
                    WHERE
1780
                        c_id = $course_id AND
1781
                        (
1782
                            path = '".Database::escape_string($systemFolderName)."'
1783
                        )
1784
            ";
1785
1786
            $groupInfo = [];
1787
            if (!empty($to_group_id)) {
1788
                $groupInfo = GroupManager::get_group_properties($to_group_id);
1789
            }
1790
1791
            $rs = Database::query($sql);
1792
            if (Database::num_rows($rs) == 0) {
1793
                $document_id = add_document(
1794
                    $_course,
1795
                    $systemFolderName,
1796
                    'folder',
1797
                    0,
1798
                    $title,
1799
                    null,
1800
                    0,
1801
                    true,
1802
                    $to_group_id,
1803
                    $session_id,
1804
                    $user_id,
1805
                    $sendNotification
1806
                );
1807
1808
                if ($document_id) {
1809
                    $lastEditType = [
1810
                        0 => 'invisible',
1811
                        1 => 'visible',
1812
                        2 => 'delete',
1813
                    ];
1814
                    // Update document item_property
1815
                    if (isset($lastEditType[$visibility])) {
1816
                        api_item_property_update(
1817
                            $_course,
1818
                            TOOL_DOCUMENT,
1819
                            $document_id,
1820
                            $lastEditType[$visibility],
1821
                            $user_id,
1822
                            $groupInfo,
1823
                            $to_user_id,
1824
                            null,
1825
                            null,
1826
                            $session_id
1827
                        );
1828
                    } else {
1829
                        api_item_property_update(
1830
                            $_course,
1831
                            TOOL_DOCUMENT,
1832
                            $document_id,
1833
                            'FolderCreated',
1834
                            $user_id,
1835
                            $groupInfo,
1836
                            $to_user_id,
1837
                            null,
1838
                            null,
1839
                            $session_id
1840
                        );
1841
                    }
1842
1843
                    $documentData = DocumentManager::get_document_data_by_id(
1844
                        $document_id,
1845
                        $_course['code'],
1846
                        false,
1847
                        $session_id
1848
                    );
1849
1850
                    return $documentData;
1851
                }
1852
            } else {
1853
                $document = Database::fetch_array($rs);
1854
                $documentData = DocumentManager::get_document_data_by_id(
1855
                    $document['id'],
1856
                    $_course['code'],
1857
                    false,
1858
                    $session_id
1859
                );
1860
1861
                /* This means the folder NOT exist in the filesystem
1862
                 (now this was created) but there is a record in the Database*/
1863
1864
                return $documentData;
1865
            }
1866
        }
1867
    }
1868
1869
    return false;
1870
}
1871
1872
/**
1873
 * Handles uploaded missing images.
1874
 *
1875
 * @author Hugues Peeters <[email protected]>
1876
 * @author Bert Vanderkimpen
1877
 *
1878
 * @param array  $_course
1879
 * @param array  $uploaded_file_collection - follows the $_FILES Structure
1880
 * @param string $base_work_dir
1881
 * @param string $missing_files_dir
1882
 * @param int    $user_id
1883
 * @param int    $to_group_id              group.id
1884
 */
1885
function move_uploaded_file_collection_into_directory(
1886
    $_course,
1887
    $uploaded_file_collection,
1888
    $base_work_dir,
1889
    $missing_files_dir,
1890
    $user_id,
1891
    $to_group_id,
1892
    $to_user_id,
1893
    $max_filled_space
1894
) {
1895
    $number_of_uploaded_images = count($uploaded_file_collection['name']);
1896
    $list = [];
1897
    for ($i = 0; $i < $number_of_uploaded_images; $i++) {
1898
        $missing_file['name'] = $uploaded_file_collection['name'][$i];
1899
        $missing_file['type'] = $uploaded_file_collection['type'][$i];
1900
        $missing_file['tmp_name'] = $uploaded_file_collection['tmp_name'][$i];
1901
        $missing_file['error'] = $uploaded_file_collection['error'][$i];
1902
        $missing_file['size'] = $uploaded_file_collection['size'][$i];
1903
1904
        $upload_ok = process_uploaded_file($missing_file);
1905
        if ($upload_ok) {
1906
            $list[] = handle_uploaded_document(
1907
                $_course,
1908
                $missing_file,
1909
                $base_work_dir,
1910
                $missing_files_dir,
1911
                $user_id,
1912
                $to_group_id,
1913
                $to_user_id,
1914
                $max_filled_space,
1915
                0,
1916
                'overwrite'
1917
            );
1918
        }
1919
        unset($missing_file);
1920
    }
1921
1922
    return $list;
1923
}
1924
1925
/**
1926
 * Opens the old html file and replace the src path into the img tag
1927
 * This also works for files in subdirectories.
1928
 *
1929
 * @param $original_img_path is an array
1930
 * @param $new_img_path is an array
1931
 */
1932
function replace_img_path_in_html_file($original_img_path, $new_img_path, $html_file)
1933
{
1934
    // Open the file
1935
    $fp = fopen($html_file, 'r');
1936
    $buffer = fread($fp, filesize($html_file));
1937
    $new_html_content = '';
1938
1939
    // Fix the image tags
1940
    for ($i = 0, $fileNb = count($original_img_path); $i < $fileNb; $i++) {
1941
        $replace_what = $original_img_path[$i];
1942
        // We only need the directory and the filename /path/to/file_html_files/missing_file.gif -> file_html_files/missing_file.gif
1943
        $exploded_file_path = explode('/', $new_img_path[$i]);
1944
        $replace_by = $exploded_file_path[count($exploded_file_path) - 2].'/'.$exploded_file_path[count($exploded_file_path) - 1];
1945
        $buffer = str_replace($replace_what, $replace_by, $buffer);
1946
    }
1947
1948
    $new_html_content .= $buffer;
1949
1950
    @fclose($fp);
1951
1952
    // Write the resulted new file
1953
1954
    if (!$fp = fopen($html_file, 'w')) {
1955
        return;
1956
    }
1957
1958
    if (!fwrite($fp, $new_html_content)) {
1959
        return;
1960
    }
1961
}
1962
1963
/**
1964
 * Checks the extension of a file, if it's .htm or .html
1965
 * we use search_img_from_html to get all image paths in the file.
1966
 *
1967
 * @param string $file
1968
 *
1969
 * @return array paths
1970
 *
1971
 * @see check_for_missing_files() uses search_img_from_html()
1972
 */
1973
function check_for_missing_files($file)
1974
{
1975
    if (strrchr($file, '.') == '.htm' || strrchr($file, '.') == '.html') {
1976
        $img_file_path = search_img_from_html($file);
1977
1978
        return $img_file_path;
1979
    }
1980
1981
    return false;
1982
}
1983
1984
/**
1985
 * This function builds a form that asks for the missing images in a html file
1986
 * maybe we should do this another way?
1987
 *
1988
 * @param array  $missing_files
1989
 * @param string $upload_path
1990
 * @param string $file_name
1991
 *
1992
 * @return string the form
1993
 */
1994
function build_missing_files_form($missing_files, $upload_path, $file_name)
1995
{
1996
    // Do we need a / or not?
1997
    $added_slash = ($upload_path == '/') ? '' : '/';
1998
    $folder_id = DocumentManager::get_document_id(api_get_course_info(), $upload_path);
1999
    // Build the form
2000
    $form = "<p><strong>".get_lang('MissingImagesDetected')."</strong></p>"
2001
        ."<form method=\"post\" action=\"".api_get_self()."\" enctype=\"multipart/form-data\">"
2002
        // Related_file is the path to the file that has missing images
2003
        ."<input type=\"hidden\" name=\"related_file\" value=\"".$upload_path.$added_slash.$file_name."\" />"
2004
        ."<input type=\"hidden\" name=\"upload_path\" value=\"".$upload_path."\" />"
2005
        ."<input type=\"hidden\" name=\"id\" value=\"".$folder_id."\" />"
2006
        ."<table border=\"0\">";
2007
    foreach ($missing_files as &$this_img_file_path) {
2008
        $form .= "<tr>"
2009
            ."<td>".basename($this_img_file_path)." : </td>"
2010
            ."<td>"
2011
            ."<input type=\"file\" name=\"img_file[]\"/>"
2012
            ."<input type=\"hidden\" name=\"img_file_path[]\" value=\"".$this_img_file_path."\" />"
2013
            ."</td>"
2014
            ."</tr>";
2015
    }
2016
    $form .= "</table>"
2017
        ."<button type='submit' name=\"cancel_submit_image\" value=\"".get_lang('Cancel')."\" class=\"cancel\">".get_lang('Cancel')."</button>"
2018
        ."<button type='submit' name=\"submit_image\" value=\"".get_lang('Ok')."\" class=\"save\">".get_lang('Ok')."</button>"
2019
        ."</form>";
2020
2021
    return $form;
2022
}
2023
2024
/**
2025
 * This recursive function can be used during the upgrade process form older
2026
 * versions of Chamilo
2027
 * It crawls the given directory, checks if the file is in the DB and adds
2028
 * it if it's not.
2029
 *
2030
 * @param array  $courseInfo
2031
 * @param array  $userInfo
2032
 * @param string $base_work_dir    course document dir
2033
 * @param string $folderPath       folder to read
2034
 * @param int    $sessionId
2035
 * @param int    $groupId          group.id
2036
 * @param bool   $output
2037
 * @param array  $parent
2038
 * @param string $whatIfFileExists
2039
 *
2040
 * @return bool
2041
 */
2042
function add_all_documents_in_folder_to_database(
2043
    $courseInfo,
2044
    $userInfo,
2045
    $base_work_dir,
2046
    $folderPath,
2047
    $sessionId = 0,
2048
    $groupId = 0,
2049
    $output = false,
2050
    $parent = [],
2051
    $whatIfFileExists = 'overwrite'
2052
) {
2053
    if (empty($userInfo) || empty($courseInfo)) {
2054
        return false;
2055
    }
2056
2057
    $userId = $userInfo['user_id'];
2058
2059
    // Open dir
2060
    $handle = opendir($folderPath);
2061
2062
    if (is_dir($folderPath)) {
2063
        // Run trough
2064
        while ($file = readdir($handle)) {
2065
            if ($file == '.' || $file == '..') {
2066
                continue;
2067
            }
2068
2069
            $parentPath = '';
2070
            if (!empty($parent) && isset($parent['path'])) {
2071
                $parentPath = $parent['path'];
2072
                if ($parentPath == '/') {
2073
                    $parentPath = '';
2074
                }
2075
            }
2076
2077
            $completePath = $parentPath.'/'.$file;
2078
            $sysFolderPath = $folderPath.'/'.$file;
2079
2080
            // Is directory?
2081
            if (is_dir($sysFolderPath)) {
2082
                $folderExists = DocumentManager::folderExists(
2083
                    $completePath,
2084
                    $courseInfo,
2085
                    $sessionId,
2086
                    $groupId
2087
                );
2088
2089
                if ($folderExists === true) {
2090
                    switch ($whatIfFileExists) {
2091
                        case 'overwrite':
2092
                            $documentId = DocumentManager::get_document_id($courseInfo, $completePath, $sessionId);
2093
                            if ($documentId) {
2094
                                $newFolderData = DocumentManager::get_document_data_by_id(
2095
                                    $documentId,
2096
                                    $courseInfo['code'],
2097
                                    false,
2098
                                    $sessionId
2099
                                );
2100
                            }
2101
                            break;
2102
                        case 'rename':
2103
                            $newFolderData = create_unexisting_directory(
2104
                                $courseInfo,
2105
                                $userId,
2106
                                $sessionId,
2107
                                $groupId,
2108
                                null,
2109
                                $base_work_dir,
2110
                                $completePath,
2111
                                null,
2112
                                null,
2113
                                true
2114
                            );
2115
                            break;
2116
                        case 'nothing':
2117
                            if ($output) {
2118
                                $documentId = DocumentManager::get_document_id($courseInfo, $completePath, $sessionId);
2119
                                if ($documentId) {
2120
                                    $folderData = DocumentManager::get_document_data_by_id(
2121
                                        $documentId,
2122
                                        $courseInfo['code'],
2123
                                        false,
2124
                                        $sessionId
2125
                                    );
2126
                                    Display::addFlash(
2127
                                        Display::return_message(
2128
                                            $folderData['path'].' '.get_lang('UplAlreadyExists'),
2129
                                            'warning'
2130
                                        )
2131
                                    );
2132
                                }
2133
                            }
2134
                            continue 2;
2135
                            break;
2136
                    }
2137
                } else {
2138
                    $newFolderData = create_unexisting_directory(
2139
                        $courseInfo,
2140
                        $userId,
2141
                        $sessionId,
2142
                        $groupId,
2143
                        null,
2144
                        $base_work_dir,
2145
                        $completePath,
2146
                        null,
2147
                        null,
2148
                        false
2149
                    );
2150
                }
2151
2152
                // Recursive
2153
                add_all_documents_in_folder_to_database(
2154
                    $courseInfo,
2155
                    $userInfo,
2156
                    $base_work_dir,
2157
                    $sysFolderPath,
2158
                    $sessionId,
2159
                    $groupId,
2160
                    $output,
2161
                    $newFolderData,
2162
                    $whatIfFileExists
2163
                );
2164
            } else {
2165
                // Rename
2166
                $uploadedFile = [
2167
                    'name' => $file,
2168
                    'tmp_name' => $sysFolderPath,
2169
                    'size' => filesize($sysFolderPath),
2170
                    'type' => null,
2171
                    'from_file' => true,
2172
                    'move_file' => true,
2173
                ];
2174
2175
                handle_uploaded_document(
2176
                    $courseInfo,
2177
                    $uploadedFile,
2178
                    $base_work_dir,
2179
                    $parentPath,
2180
                    $userId,
2181
                    $groupId,
2182
                    null,
2183
                    0,
2184
                    $whatIfFileExists,
2185
                    $output,
2186
                    false,
2187
                    null,
2188
                    $sessionId
2189
                );
2190
            }
2191
        }
2192
    }
2193
}
2194
2195
/**
2196
 * Get the uploax max filesize from ini php in bytes.
2197
 *
2198
 * @return int
2199
 */
2200
function getIniMaxFileSizeInBytes($humanReadable = false, $checkMessageSetting = false)
2201
{
2202
    $maxSize = 0;
2203
    $uploadMaxFilesize = ini_get('upload_max_filesize');
2204
    $fileSizeForTeacher = getFileUploadSizeLimitForTeacher();
2205
    if (!empty($fileSizeForTeacher)) {
2206
        $uploadMaxFilesize = $fileSizeForTeacher.'M';
2207
    }
2208
2209
    if (empty($fileSizeForTeacher) && $checkMessageSetting) {
2210
        $uploadMaxFilesize = api_get_setting('message_max_upload_filesize'); // in bytes
2211
        if ($humanReadable) {
2212
            $uploadMaxFilesize = format_file_size($uploadMaxFilesize);
2213
        }
2214
2215
        return $uploadMaxFilesize;
2216
    }
2217
2218
    if ($humanReadable) {
2219
        return $uploadMaxFilesize;
2220
    }
2221
2222
    if (preg_match('/^([0-9]+)([a-zA-Z]*)$/', $uploadMaxFilesize, $matches)) {
2223
        // see http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
2224
        switch (strtoupper($matches['2'])) {
2225
            case 'G':
2226
                $maxSize = $matches['1'] * 1073741824;
2227
                break;
2228
            case 'M':
2229
                $maxSize = $matches['1'] * 1048576;
2230
                break;
2231
            case 'K':
2232
                $maxSize = $matches['1'] * 1024;
2233
                break;
2234
            default:
2235
                $maxSize = $matches['1'];
2236
        }
2237
    }
2238
    $maxSize = (int) $maxSize;
2239
2240
    return $maxSize;
2241
}
2242
2243
/**
2244
 * Get the uploax max filesize from configuration.php for trainers in bytes.
2245
 *
2246
 * @return int
2247
 */
2248
function getFileUploadSizeLimitForTeacher()
2249
{
2250
    $size = 0;
2251
    $settingValue = (int) api_get_configuration_value('file_upload_size_limit_for_teacher'); // setting value in MB
2252
    if ($settingValue > 0 && (api_is_allowed_to_create_course() && !api_is_platform_admin())) {
2253
        $size = $settingValue;
2254
    }
2255
2256
    return $size;
2257
}
2258