Passed
Push — master ( 5d82a6...ffd823 )
by Julito
18:09 queued 09:19
created

create_unexisting_directory()   F

Complexity

Conditions 16
Paths 325

Size

Total Lines 141
Code Lines 84

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 84
nc 325
nop 12
dl 0
loc 141
rs 2.8857
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\ResourceLink;
5
use Chamilo\CoreBundle\Framework\Container;
6
use Chamilo\CourseBundle\Entity\CDocument;
7
use Symfony\Component\HttpFoundation\File\UploadedFile;
8
9
/**
10
 * FILE UPLOAD LIBRARY.
11
 *
12
 * This is the file upload library for Chamilo.
13
 * Include/require it in your code to use its functionality.
14
 *
15
 * @todo test and reorganise
16
 */
17
18
/**
19
 * Changes the file name extension from .php to .phps
20
 * Useful for securing a site.
21
 *
22
 * @author Hugues Peeters <[email protected]>
23
 *
24
 * @param string $file_name Name of a file
25
 *
26
 * @return string the filename phps'ized
27
 */
28
function php2phps($file_name)
29
{
30
    return preg_replace('/\.(php.?|phtml.?)(\.){0,1}.*$/i', '.phps', $file_name);
31
}
32
33
/**
34
 * Renames .htaccess & .HTACCESS to htaccess.txt.
35
 *
36
 * @param string $filename
37
 *
38
 * @return string
39
 */
40
function htaccess2txt($filename)
41
{
42
    return str_replace(['.htaccess', '.HTACCESS'], ['htaccess.txt', 'htaccess.txt'], $filename);
43
}
44
45
/**
46
 * This function executes our safety precautions
47
 * more functions can be added.
48
 *
49
 * @param string $filename
50
 *
51
 * @return string
52
 *
53
 * @see php2phps()
54
 * @see htaccess2txt()
55
 */
56
function disable_dangerous_file($filename)
57
{
58
    return htaccess2txt(php2phps($filename));
59
}
60
61
/**
62
 * Returns the name without extension, used for the title.
63
 *
64
 * @param string $name
65
 *
66
 * @return name without the extension
67
 */
68
function get_document_title($name)
69
{
70
    // If they upload .htaccess...
71
    $name = disable_dangerous_file($name);
72
    $ext = substr(strrchr($name, '.'), 0);
73
74
    if (empty($ext)) {
75
        return substr($name, 0, strlen($name));
76
    }
77
78
    return substr($name, 0, strlen($name) - strlen(strstr($name, $ext)));
79
}
80
81
/**
82
 * This function checks if the upload succeeded.
83
 *
84
 * @return true if upload succeeded
85
 */
86
function process_uploaded_file($uploadedFileData, $show_output = true)
87
{
88
    $uploadedFile = [];
89
    if ($uploadedFileData instanceof UploadedFile) {
90
        $uploadedFile['error'] = $uploadedFileData->getError();
91
        $uploadedFile['tmp_name'] = $uploadedFileData->getPathname();
92
        $uploadedFile['size'] = $uploadedFileData->getSize();
93
    } else {
94
        $uploadedFile = $uploadedFileData;
95
    }
96
97
    // Checking the error code sent with the file upload.
98
    if (isset($uploadedFile['error'])) {
99
        switch ($uploadedFile['error']) {
100
            case 1:
101
                // The uploaded file exceeds the upload_max_filesize directive in php.ini.
102
                if ($show_output) {
103
                    Display::addFlash(
104
                        Display::return_message(
105
                            get_lang('The uploaded file exceeds the maximum filesize allowed by the server:').ini_get('upload_max_filesize'),
106
                            'error'
107
                        )
108
                    );
109
                }
110
111
                return false;
112
            case 2:
113
                // The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.
114
                // Not used at the moment, but could be handy if we want to limit the size of an upload
115
                // (e.g. image upload in html editor).
116
                $max_file_size = (int) $_POST['MAX_FILE_SIZE'];
117
                if ($show_output) {
118
                    Display::addFlash(
119
                        Display::return_message(
120
                            get_lang('The file size exceeds the maximum allowed setting:').format_file_size($max_file_size),
121
                            'error'
122
                        )
123
                    );
124
                }
125
126
                return false;
127
            case 3:
128
                // The uploaded file was only partially uploaded.
129
                if ($show_output) {
130
                    Display::addFlash(
131
                        Display::return_message(
132
                            get_lang('The uploaded file was only partially uploaded.').' '.get_lang('Please Try Again!'),
133
                            'error'
134
                        )
135
                    );
136
                }
137
138
                return false;
139
            case 4:
140
                // No file was uploaded.
141
                if ($show_output) {
142
                    Display::addFlash(
143
                        Display::return_message(
144
                            get_lang('No file was uploaded.').' '.get_lang('Please select a file before pressing the upload button.'),
145
                            'error'
146
                        )
147
                    );
148
                }
149
150
                return false;
151
        }
152
    }
153
154
    if (!file_exists($uploadedFile['tmp_name'])) {
155
        // No file was uploaded.
156
        if ($show_output) {
157
            Display::addFlash(Display::return_message(get_lang('The file upload has failed.'), 'error'));
158
        }
159
160
        return false;
161
    }
162
163
    if (file_exists($uploadedFile['tmp_name'])) {
164
        $filesize = filesize($uploadedFile['tmp_name']);
165
        if (empty($filesize)) {
166
            // No file was uploaded.
167
            if ($show_output) {
168
                Display::addFlash(
169
                    Display::return_message(
170
                        get_lang('The file upload has failed.SizeIsZero'),
171
                        'error'
172
                    )
173
                );
174
            }
175
176
            return false;
177
        }
178
    }
179
180
    $course_id = api_get_course_id();
181
182
    //Checking course quota if we are in a course
183
    if (!empty($course_id)) {
184
        $max_filled_space = DocumentManager::get_course_quota();
185
        // Check if there is enough space to save the file
186
        if (!DocumentManager::enough_space($uploadedFile['size'], $max_filled_space)) {
187
            if ($show_output) {
188
                Display::addFlash(
189
                    Display::return_message(
190
                        get_lang('There is not enough space to upload this file.'),
191
                        'error'
192
                    )
193
                );
194
            }
195
196
            return false;
197
        }
198
    }
199
200
    // case 0: default: We assume there is no error, the file uploaded with success.
201
    return true;
202
}
203
204
/**
205
 * This function does the save-work for the documents.
206
 * It handles the uploaded file and adds the properties to the database
207
 * If unzip=1 and the file is a zipfile, it is extracted
208
 * If we decide to save ALL kinds of documents in one database,
209
 * we could extend this with a $type='document', 'scormdocument',...
210
 *
211
 * @param array  $courseInfo
212
 * @param array  $uploadedFile            ($_FILES)
213
 *                                        array(
214
 *                                        'name' => 'picture.jpg',
215
 *                                        'tmp_name' => '...', // absolute path
216
 *                                        );
217
 * @param string $documentDir             Example: /var/www/chamilo/courses/ABC/document
218
 * @param string $uploadPath              Example: /folder1/folder2/
219
 * @param int    $userId
220
 * @param int    $groupId                 group.id
221
 * @param int    $toUserId                User ID, or NULL for everybody
222
 * @param int    $unzip                   1/0
223
 * @param string $whatIfFileExists        overwrite, rename or warn if exists (default)
224
 * @param bool   $output                  optional output parameter
225
 * @param bool   $onlyUploadFile
226
 * @param string $comment
227
 * @param int    $sessionId
228
 * @param bool   $treat_spaces_as_hyphens
229
 * @param string $uploadKey
230
 * @param int    $parentId
231
 * @param $content
232
 *
233
 * So far only use for unzip_uploaded_document function.
234
 * If no output wanted on success, set to false.
235
 *
236
 * @return CDocument|false
237
 */
238
function handle_uploaded_document(
239
    $courseInfo,
240
    $uploadedFile,
241
    $documentDir,
242
    $uploadPath,
243
    $userId,
244
    $groupId = 0,
245
    $toUserId = null,
246
    $unzip = 0,
247
    $whatIfFileExists = '',
248
    $output = true,
249
    $onlyUploadFile = false,
250
    $comment = null,
251
    $sessionId = null,
252
    $treat_spaces_as_hyphens = true,
253
    $uploadKey = '',
254
    $parentId = 0,
255
    $content = null
256
) {
257
    if (!$userId) {
258
        return false;
259
    }
260
261
    $userInfo = api_get_user_info();
262
    $uploadedFile['name'] = stripslashes($uploadedFile['name']);
263
    // Add extension to files without one (if possible)
264
    $uploadedFile['name'] = add_ext_on_mime($uploadedFile['name'], $uploadedFile['type']);
265
    $sessionId = (int) $sessionId;
266
    if (empty($sessionId)) {
267
        $sessionId = api_get_session_id();
268
    }
269
270
    $group = api_get_group_entity($groupId);
271
272
    // Just in case process_uploaded_file is not called
273
    $maxSpace = DocumentManager::get_course_quota();
274
275
    // Check if there is enough space to save the file
276
    if (!DocumentManager::enough_space($uploadedFile['size'], $maxSpace)) {
277
        if ($output) {
278
            Display::addFlash(
279
                Display::return_message(get_lang('There is not enough space to upload this file.'), 'error')
280
            );
281
        }
282
283
        return false;
284
    }
285
286
    $defaultVisibility = api_get_setting('course.active_tools_on_create');
287
    $defaultVisibility = in_array('document', $defaultVisibility) ? ResourceLink::VISIBILITY_PUBLISHED : ResourceLink::VISIBILITY_DRAFT;
288
289
    // If the want to unzip, check if the file has a .zip (or ZIP,Zip,ZiP,...) extension
290
    if (1 == $unzip && preg_match('/.zip$/', strtolower($uploadedFile['name']))) {
291
        return unzip_uploaded_document(
292
            $courseInfo,
293
            $userInfo,
294
            $uploadedFile,
295
            $uploadPath,
296
            $documentDir,
297
            $maxSpace,
298
            $sessionId,
299
            $groupId,
300
            $output,
301
            $onlyUploadFile,
302
            $whatIfFileExists
303
        );
304
    } elseif (1 == $unzip && !preg_match('/.zip$/', strtolower($uploadedFile['name']))) {
305
        // We can only unzip ZIP files (no gz, tar,...)
306
        if ($output) {
307
            Display::addFlash(
308
                Display::return_message(
309
                    get_lang('The file you selected was not a zip file.')." ".get_lang('Please Try Again!'),
310
                    'error'
311
                )
312
            );
313
        }
314
315
        return false;
316
    } else {
317
        // Clean up the name, only ASCII characters should stay. (and strict)
318
        $cleanName = api_replace_dangerous_char($uploadedFile['name'], $treat_spaces_as_hyphens);
319
320
        // No "dangerous" files
321
        $cleanName = disable_dangerous_file($cleanName);
322
323
        // Checking file extension
324
        if (!filter_extension($cleanName)) {
325
            if ($output) {
326
                Display::addFlash(
327
                    Display::return_message(
328
                        get_lang('File upload failed: this file extension or file type is prohibited'),
329
                        'error'
330
                    )
331
                );
332
            }
333
334
            return false;
335
        } else {
336
            // If the upload path differs from / (= root) it will need a slash at the end
337
            if ('/' !== $uploadPath) {
338
                $uploadPath = $uploadPath.'/';
339
            }
340
341
            // Full path to where we want to store the file with trailing slash
342
            $whereToSave = $documentDir.$uploadPath;
343
344
            // Just upload the file "as is"
345
            /*if ($onlyUploadFile) {
346
                $errorResult = moveUploadedFile($uploadedFile, $whereToSave.$cleanName);
347
                if ($errorResult) {
348
                    return $whereToSave.$cleanName;
349
                }
350
351
                return $errorResult;
352
            }*/
353
354
            /*
355
                Based in the clean name we generate a new filesystem name
356
                Using the session_id and group_id if values are not empty
357
            */
358
359
            // @todo fix clean name use hash instead of custom document name
360
            /*$fileSystemName = DocumentManager::fixDocumentName(
361
                $cleanName,
362
                'file',
363
                $courseInfo,
364
                $sessionId,
365
                $groupId
366
            );*/
367
368
            $fileSystemName = $cleanName;
369
370
            // Name of the document without the extension (for the title)
371
            $documentTitle = get_document_title($uploadedFile['name']);
372
373
            // Size of the uploaded file (in bytes)
374
            $fileSize = $uploadedFile['size'];
375
376
            // Example: /folder/picture.jpg
377
            /*$filePath = $uploadPath.$fileSystemName;
378
            $docId = DocumentManager::get_document_id(
379
                $courseInfo,
380
                $filePath,
381
                $sessionId
382
            );*/
383
384
            $courseEntity = api_get_course_entity($courseInfo['real_id']);
385
            if (empty($courseEntity)) {
386
                return false;
387
            }
388
389
            $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
390
            $session = api_get_session_entity($sessionId);
391
            $group = api_get_group_entity($groupId);
392
            $documentRepo = Container::getDocumentRepository();
393
394
            /** @var \Chamilo\CoreBundle\Entity\AbstractResource $parentResource */
395
            $parentResource = $courseEntity;
396
            if (!empty($parentId)) {
397
                $parent = $documentRepo->find($parentId);
398
                if ($parent) {
399
                    $parentResource = $parent;
400
                }
401
            }
402
403
            $document = $documentRepo->findResourceByTitle(
404
                $documentTitle,
405
                $parentResource->getResourceNode(),
406
                $courseEntity,
407
                $session,
408
                $group
409
            );
410
411
            if (!($content instanceof UploadedFile)) {
412
                $request = Container::getRequest();
413
                $content = $request->files->get($uploadKey);
414
                if (is_array($content)) {
415
                    $content = $content[0];
416
                }
417
            }
418
419
            // What to do if the target file exists
420
            switch ($whatIfFileExists) {
421
                // Overwrite the file if it exists
422
                case 'overwrite':
423
                    if ($document) {
424
                        // Update file size
425
                        /*update_existing_document(
426
                            $courseInfo,
427
                            $document->getIid(),
428
                            $uploadedFile['size']
429
                        );*/
430
431
                        $document = DocumentManager::addFileToDocument(
432
                            $document,
433
                            null,
434
                            $content,
435
                            $defaultVisibility,
436
                            null,
437
                            $group
438
                        );
439
440
                        // Display success message with extra info to user
441
                        if ($document && $output) {
442
                            Display::addFlash(
443
                                Display::return_message(
444
                                    get_lang('File upload succeeded!').'<br /> '.
445
                                    $document->getTitle().' '.get_lang(' was overwritten.'),
446
                                    'confirmation',
447
                                    false
448
                                )
449
                            );
450
                        }
451
452
                        return $document;
453
                    } else {
454
                        // Put the document data in the database
455
                        $document = DocumentManager::addDocument(
456
                            $courseInfo,
457
                            null,
458
                            'file',
459
                            $fileSize,
460
                            $documentTitle,
461
                            $comment,
462
                            0,
463
                            $defaultVisibility,
464
                            $groupId,
465
                            $sessionId,
466
                            0,
467
                            true,
468
                            $content
469
                        );
470
471
                        // Display success message to user
472
                        if ($document) {
473
                            Display::addFlash(
474
                                Display::return_message(
475
                                    get_lang('File upload succeeded!').'<br /> '.$documentTitle,
476
                                    'confirmation',
477
                                    false
478
                                )
479
                            );
480
                        }
481
482
                        return $document;
483
                    }
484
                    break;
485
                case 'rename':
486
                    // Rename the file if it exists
487
                    $cleanName = DocumentManager::getUniqueFileName(
488
                        $uploadPath,
489
                        $cleanName,
490
                        $courseInfo,
491
                        $sessionId,
492
                        $groupId
493
                    );
494
495
                    $fileSystemName = DocumentManager::fixDocumentName(
496
                        $cleanName,
497
                        'file',
498
                        $courseInfo,
499
                        $sessionId,
500
                        $groupId
501
                    );
502
503
                    $documentTitle = disable_dangerous_file($cleanName);
504
                    $filePath = $uploadPath.$fileSystemName;
505
506
                    // Put the document data in the database
507
                    $document = DocumentManager::addDocument(
508
                        $courseInfo,
509
                        $filePath,
510
                        'file',
511
                        $fileSize,
512
                        $documentTitle,
513
                        $comment, // comment
514
                        0, // read only
515
                        $defaultVisibility, // save visibility
516
                        $groupId,
517
                        $sessionId,
518
                        0,
519
                        true,
520
                        $content,
521
                        $parentId
522
                    );
523
524
                    // Display success message to user
525
                    if ($output && $document) {
526
                        Display::addFlash(
527
                            Display::return_message(
528
                                get_lang('File upload succeeded!').'<br />'.
529
                                get_lang('File saved as').' '.$document->getTitle(),
530
                                'success',
531
                                false
532
                            )
533
                        );
534
                    }
535
536
                    return $document;
537
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
538
                case 'nothing':
539
                    if ($document) {
540
                        if ($output) {
541
                            Display::addFlash(
542
                                Display::return_message(
543
                                    $uploadPath.$cleanName.' '.get_lang(' already exists.'),
544
                                    'warning',
545
                                    false
546
                                )
547
                            );
548
                        }
549
                        break;
550
                    }
551
                    // no break
552
                default:
553
                    // Only save the file if it doesn't exist or warn user if it does exist
554
                    if ($document) {
555
                        if ($output) {
556
                            Display::addFlash(
557
                                Display::return_message($cleanName.' '.get_lang(' already exists.'), 'warning', false)
558
                            );
559
                        }
560
                    } else {
561
                        // Put the document data in the database
562
                        $document = DocumentManager::addDocument(
563
                            $courseInfo,
564
                            $filePath,
565
                            'file',
566
                            $fileSize,
567
                            $documentTitle,
568
                            $comment,
569
                            0,
570
                            $defaultVisibility,
571
                            $groupId,
572
                            $sessionId,
573
                            0,
574
                            true,
575
                            $content
576
                        );
577
578
                        if ($document) {
579
                            // Display success message to user
580
                            if ($output) {
581
                                Display::addFlash(
582
                                    Display::return_message(
583
                                        get_lang('File upload succeeded!').'<br /> '.$documentTitle,
584
                                        'confirm',
585
                                        false
586
                                    )
587
                                );
588
                            }
589
590
                            return $document;
591
                        } else {
592
                            if ($output) {
593
                                Display::addFlash(
594
                                    Display::return_message(
595
                                        get_lang('The uploaded file could not be saved (perhaps a permission problem?)'),
596
                                        'error',
597
                                        false
598
                                    )
599
                                );
600
                            }
601
                        }
602
                    }
603
                    break;
604
            }
605
        }
606
    }
607
}
608
609
/**
610
 * @param string $file
611
 * @param string $storePath
612
 *
613
 * @return bool
614
 */
615
function moveUploadedFile($file, $storePath)
616
{
617
    $handleFromFile = isset($file['from_file']) && $file['from_file'] ? true : false;
618
    $moveFile = isset($file['move_file']) && $file['move_file'] ? true : false;
619
    if ($moveFile) {
620
        $copied = copy($file['tmp_name'], $storePath);
621
622
        if (!$copied) {
623
            return false;
624
        }
625
    }
626
    if ($handleFromFile) {
627
        return file_exists($file['tmp_name']);
628
    } else {
629
        return move_uploaded_file($file['tmp_name'], $storePath);
630
    }
631
}
632
633
/**
634
 * Checks if there is enough place to add a file on a directory
635
 * on the base of a maximum directory size allowed
636
 * deprecated: use enough_space instead!
637
 *
638
 * @author Hugues Peeters <[email protected]>
639
 *
640
 * @param int    $file_size     Size of the file in byte
641
 * @param string $dir           Path of the directory where the file should be added
642
 * @param int    $max_dir_space Maximum size of the diretory in byte
643
 *
644
 * @return bool true if there is enough space, false otherwise
645
 *
646
 * @see enough_size() uses  dir_total_space() function
647
 */
648
function enough_size($file_size, $dir, $max_dir_space)
649
{
650
    // If the directory is the archive directory, safely ignore the size limit
651
    if (api_get_path(SYS_ARCHIVE_PATH) == $dir) {
652
        return true;
653
    }
654
655
    if ($max_dir_space) {
656
        $already_filled_space = dir_total_space($dir);
657
        if (($file_size + $already_filled_space) > $max_dir_space) {
658
            return false;
659
        }
660
    }
661
662
    return true;
663
}
664
665
/**
666
 * Computes the size already occupied by a directory and is subdirectories.
667
 *
668
 * @author Hugues Peeters <[email protected]>
669
 *
670
 * @param string $dir_path Size of the file in byte
671
 *
672
 * @return int Return the directory size in bytes
673
 */
674
function dir_total_space($dir_path)
675
{
676
    $save_dir = getcwd();
677
    chdir($dir_path);
678
    $handle = opendir($dir_path);
679
    $sumSize = 0;
680
    $dirList = [];
681
    while ($element = readdir($handle)) {
682
        if ('.' == $element || '..' == $element) {
683
            continue; // Skip the current and parent directories
684
        }
685
        if (is_file($element)) {
686
            $sumSize += filesize($element);
687
        }
688
        if (is_dir($element)) {
689
            $dirList[] = $dir_path.'/'.$element;
690
        }
691
    }
692
693
    closedir($handle);
694
695
    if (sizeof($dirList) > 0) {
696
        foreach ($dirList as $j) {
697
            $sizeDir = dir_total_space($j); // Recursivity
698
            $sumSize += $sizeDir;
699
        }
700
    }
701
    chdir($save_dir); // Return to initial position
702
703
    return $sumSize;
704
}
705
706
/**
707
 * Tries to add an extension to files without extension
708
 * Some applications on Macintosh computers don't add an extension to the files.
709
 * This subroutine try to fix this on the basis of the MIME type sent
710
 * by the browser.
711
 *
712
 * Note : some browsers don't send the MIME Type (e.g. Netscape 4).
713
 *        We don't have solution for this kind of situation
714
 *
715
 * @author Hugues Peeters <[email protected]>
716
 * @author Bert Vanderkimpen
717
 *
718
 * @param string $file_name Name of the file
719
 * @param string $file_type Type of the file
720
 *
721
 * @return string File name
722
 */
723
function add_ext_on_mime($file_name, $file_type)
724
{
725
    // Check whether the file has an extension AND whether the browser has sent a MIME Type
726
727
    if (!preg_match('/^.*\.[a-zA-Z_0-9]+$/', $file_name) && $file_type) {
728
        // Build a "MIME-types / extensions" connection table
729
        static $mime_type = [];
730
731
        $mime_type[] = 'application/msword';
732
        $extension[] = '.doc';
733
        $mime_type[] = 'application/rtf';
734
        $extension[] = '.rtf';
735
        $mime_type[] = 'application/vnd.ms-powerpoint';
736
        $extension[] = '.ppt';
737
        $mime_type[] = 'application/vnd.ms-excel';
738
        $extension[] = '.xls';
739
        $mime_type[] = 'application/pdf';
740
        $extension[] = '.pdf';
741
        $mime_type[] = 'application/postscript';
742
        $extension[] = '.ps';
743
        $mime_type[] = 'application/mac-binhex40';
744
        $extension[] = '.hqx';
745
        $mime_type[] = 'application/x-gzip';
746
        $extension[] = 'tar.gz';
747
        $mime_type[] = 'application/x-shockwave-flash';
748
        $extension[] = '.swf';
749
        $mime_type[] = 'application/x-stuffit';
750
        $extension[] = '.sit';
751
        $mime_type[] = 'application/x-tar';
752
        $extension[] = '.tar';
753
        $mime_type[] = 'application/zip';
754
        $extension[] = '.zip';
755
        $mime_type[] = 'application/x-tar';
756
        $extension[] = '.tar';
757
        $mime_type[] = 'text/html';
758
        $extension[] = '.html';
759
        $mime_type[] = 'text/plain';
760
        $extension[] = '.txt';
761
        $mime_type[] = 'text/rtf';
762
        $extension[] = '.rtf';
763
        $mime_type[] = 'img/gif';
764
        $extension[] = '.gif';
765
        $mime_type[] = 'img/jpeg';
766
        $extension[] = '.jpg';
767
        $mime_type[] = 'img/png';
768
        $extension[] = '.png';
769
        $mime_type[] = 'audio/midi';
770
        $extension[] = '.mid';
771
        $mime_type[] = 'audio/mpeg';
772
        $extension[] = '.mp3';
773
        $mime_type[] = 'audio/x-aiff';
774
        $extension[] = '.aif';
775
        $mime_type[] = 'audio/x-pn-realaudio';
776
        $extension[] = '.rm';
777
        $mime_type[] = 'audio/x-pn-realaudio-plugin';
778
        $extension[] = '.rpm';
779
        $mime_type[] = 'audio/x-wav';
780
        $extension[] = '.wav';
781
        $mime_type[] = 'video/mpeg';
782
        $extension[] = '.mpg';
783
        $mime_type[] = 'video/mpeg4-generic';
784
        $extension[] = '.mp4';
785
        $mime_type[] = 'video/quicktime';
786
        $extension[] = '.mov';
787
        $mime_type[] = 'video/x-msvideo';
788
        $extension[] = '.avi';
789
790
        $mime_type[] = 'video/x-ms-wmv';
791
        $extension[] = '.wmv';
792
        $mime_type[] = 'video/x-flv';
793
        $extension[] = '.flv';
794
        $mime_type[] = 'image/svg+xml';
795
        $extension[] = '.svg';
796
        $mime_type[] = 'image/svg+xml';
797
        $extension[] = '.svgz';
798
        $mime_type[] = 'video/ogg';
799
        $extension[] = '.ogv';
800
        $mime_type[] = 'audio/ogg';
801
        $extension[] = '.oga';
802
        $mime_type[] = 'application/ogg';
803
        $extension[] = '.ogg';
804
        $mime_type[] = 'application/ogg';
805
        $extension[] = '.ogx';
806
        $mime_type[] = 'application/x-freemind';
807
        $extension[] = '.mm';
808
809
        $mime_type[] = 'application/vnd.ms-word.document.macroEnabled.12';
810
        $extension[] = '.docm';
811
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
812
        $extension[] = '.docx';
813
        $mime_type[] = 'application/vnd.ms-word.template.macroEnabled.12';
814
        $extension[] = '.dotm';
815
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.template';
816
        $extension[] = '.dotx';
817
        $mime_type[] = 'application/vnd.ms-powerpoint.template.macroEnabled.12';
818
        $extension[] = '.potm';
819
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.template';
820
        $extension[] = '.potx';
821
        $mime_type[] = 'application/vnd.ms-powerpoint.addin.macroEnabled.12';
822
        $extension[] = '.ppam';
823
        $mime_type[] = 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12';
824
        $extension[] = '.ppsm';
825
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.slideshow';
826
        $extension[] = '.ppsx';
827
        $mime_type[] = 'application/vnd.ms-powerpoint.presentation.macroEnabled.12';
828
        $extension[] = '.pptm';
829
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
830
        $extension[] = '.pptx';
831
        $mime_type[] = 'application/vnd.ms-excel.addin.macroEnabled.12';
832
        $extension[] = '.xlam';
833
        $mime_type[] = 'application/vnd.ms-excel.sheet.binary.macroEnabled.12';
834
        $extension[] = '.xlsb';
835
        $mime_type[] = 'application/vnd.ms-excel.sheet.macroEnabled.12';
836
        $extension[] = '.xlsm';
837
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
838
        $extension[] = '.xlsx';
839
        $mime_type[] = 'application/vnd.ms-excel.template.macroEnabled.12';
840
        $extension[] = '.xltm';
841
        $mime_type[] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.template';
842
        $extension[] = '.xltx';
843
844
        // Test on PC (files with no extension get application/octet-stream)
845
        //$mime_type[] = 'application/octet-stream';      $extension[] = '.ext';
846
        // Check whether the MIME type sent by the browser is within the table
847
        foreach ($mime_type as $key => &$type) {
848
            if ($type == $file_type) {
849
                $file_name .= $extension[$key];
850
                break;
851
            }
852
        }
853
854
        unset($mime_type, $extension, $type, $key); // Delete to eschew possible collisions
855
    }
856
857
    return $file_name;
858
}
859
860
/**
861
 * Manages all the unzipping process of an uploaded file.
862
 *
863
 * @author Hugues Peeters <[email protected]>
864
 *
865
 * @param array  $uploaded_file    - follows the $_FILES Structure
866
 * @param string $upload_path      - destination of the upload.
867
 *                                 This path is to append to $base_work_dir
868
 * @param string $base_work_dir    - base working directory of the module
869
 * @param int    $max_filled_space - amount of bytes to not exceed in the base
870
 *                                 working directory
871
 *
872
 * @return bool true if it succeeds false otherwise
873
 */
874
function unzip_uploaded_file($uploaded_file, $upload_path, $base_work_dir, $max_filled_space)
875
{
876
    $zip_file = new PclZip($uploaded_file['tmp_name']);
877
878
    // Check the zip content (real size and file extension)
879
    if (file_exists($uploaded_file['tmp_name'])) {
880
        $zip_content_array = $zip_file->listContent();
881
        $ok_scorm = false;
882
        $realFileSize = 0;
883
        foreach ($zip_content_array as &$this_content) {
884
            if (preg_match('~.(php.*|phtml)$~i', $this_content['filename'])) {
885
                Display::addFlash(
886
                    Display::return_message(get_lang('The zip file can not contain .PHP files'))
887
                );
888
889
                return false;
890
            } elseif (stristr($this_content['filename'], 'imsmanifest.xml')) {
891
                $ok_scorm = true;
892
            } elseif (stristr($this_content['filename'], 'LMS')) {
893
                $ok_plantyn_scorm1 = true;
894
            } elseif (stristr($this_content['filename'], 'REF')) {
895
                $ok_plantyn_scorm2 = true;
896
            } elseif (stristr($this_content['filename'], 'SCO')) {
897
                $ok_plantyn_scorm3 = true;
898
            } elseif (stristr($this_content['filename'], 'AICC')) {
899
                $ok_aicc_scorm = true;
900
            }
901
            $realFileSize += $this_content['size'];
902
        }
903
904
        if (($ok_plantyn_scorm1 && $ok_plantyn_scorm2 && $ok_plantyn_scorm3) || $ok_aicc_scorm) {
905
            $ok_scorm = true;
906
        }
907
908
        if (!$ok_scorm && defined('CHECK_FOR_SCORM') && CHECK_FOR_SCORM) {
909
            Display::addFlash(
910
                Display::return_message(get_lang('This is not a valid SCORM ZIP file !'))
911
            );
912
913
            return false;
914
        }
915
916
        if (!enough_size($realFileSize, $base_work_dir, $max_filled_space)) {
917
            Display::addFlash(
918
                Display::return_message(get_lang('The upload has failed. Either you have exceeded your maximum quota, or there is not enough disk space.'))
919
            );
920
921
            return false;
922
        }
923
924
        // It happens on Linux that $upload_path sometimes doesn't start with '/'
925
        if ('/' != $upload_path[0] && '/' != substr($base_work_dir, -1, 1)) {
926
            $upload_path = '/'.$upload_path;
927
        }
928
929
        if ('/' == $upload_path[strlen($upload_path) - 1]) {
930
            $upload_path = substr($upload_path, 0, -1);
931
        }
932
933
        /*	Uncompressing phase */
934
935
        /*
936
            The first version, using OS unzip, is not used anymore
937
            because it does not return enough information.
938
            We need to process each individual file in the zip archive to
939
            - add it to the database
940
            - parse & change relative html links
941
        */
942
        if (PHP_OS == 'Linux' && !get_cfg_var('safe_mode') && false) { // *** UGent, changed by OC ***
943
            // Shell Method - if this is possible, it gains some speed
944
            exec("unzip -d \"".$base_work_dir.$upload_path."/\"".$uploaded_file['name']." ".$uploaded_file['tmp_name']);
945
        } else {
946
            // PHP method - slower...
947
            $save_dir = getcwd();
948
            chdir($base_work_dir.$upload_path);
949
            $unzippingState = $zip_file->extract();
950
            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...
951
                $state = $unzippingState[$j];
952
953
                // Fix relative links in html files
954
                $extension = strrchr($state['stored_filename'], '.');
955
            }
956
            if ($dir = @opendir($base_work_dir.$upload_path)) {
957
                while ($file = readdir($dir)) {
958
                    if ('.' != $file && '..' != $file) {
959
                        $filetype = 'file';
960
                        if (is_dir($base_work_dir.$upload_path.'/'.$file)) {
961
                            $filetype = 'folder';
962
                        }
963
964
                        $safe_file = api_replace_dangerous_char($file);
965
                        @rename($base_work_dir.$upload_path.'/'.$file, $base_work_dir.$upload_path.'/'.$safe_file);
966
                        set_default_settings($upload_path, $safe_file, $filetype);
967
                    }
968
                }
969
970
                closedir($dir);
971
            } else {
972
                error_log('Could not create directory '.$base_work_dir.$upload_path.' to unzip files');
973
            }
974
            chdir($save_dir); // Back to previous dir position
975
        }
976
    }
977
978
    return true;
979
}
980
981
/**
982
 * Manages all the unzipping process of an uploaded document
983
 * This uses the item_property table for properties of documents.
984
 *
985
 * @author Hugues Peeters <[email protected]>
986
 * @author Bert Vanderkimpen
987
 *
988
 * @param array  $courseInfo
989
 * @param array  $userInfo
990
 * @param array  $uploaded_file    - follows the $_FILES Structure
991
 * @param string $uploadPath       - destination of the upload.
992
 *                                 This path is to append to $base_work_dir
993
 * @param string $base_work_dir    - base working directory of the module
994
 * @param int    $maxFilledSpace   - amount of bytes to not exceed in the base
995
 *                                 working directory
996
 * @param int    $sessionId
997
 * @param int    $groupId          group.id
998
 * @param bool   $output           Optional. If no output not wanted on success, set to false.
999
 * @param bool   $onlyUploadFile
1000
 * @param string $whatIfFileExists (only works if $onlyUploadFile is false)
1001
 *
1002
 * @return bool true if it succeeds false otherwise
1003
 */
1004
function unzip_uploaded_document(
1005
    $courseInfo,
1006
    $userInfo,
1007
    $uploaded_file,
1008
    $uploadPath,
1009
    $base_work_dir,
1010
    $maxFilledSpace,
1011
    $sessionId = 0,
1012
    $groupId = 0,
1013
    $output = true,
1014
    $onlyUploadFile = false,
1015
    $whatIfFileExists = 'overwrite'
1016
) {
1017
    $zip = new PclZip($uploaded_file['tmp_name']);
1018
1019
    // Check the zip content (real size and file extension)
1020
    $zip_content_array = (array) $zip->listContent();
1021
    $realSize = 0;
1022
    foreach ($zip_content_array as &$this_content) {
1023
        $realSize += $this_content['size'];
1024
    }
1025
1026
    if (!DocumentManager::enough_space($realSize, $maxFilledSpace)) {
1027
        echo Display::return_message(get_lang('There is not enough space to upload this file.'), 'error');
1028
1029
        return false;
1030
    }
1031
1032
    $folder = api_get_unique_id();
1033
    $destinationDir = api_get_path(SYS_ARCHIVE_PATH).$folder;
1034
    mkdir($destinationDir, api_get_permissions_for_new_directories(), true);
1035
1036
    // Uncompress zip file
1037
    // We extract using a callback function that "cleans" the path
1038
    $zip->extract(
1039
        PCLZIP_OPT_PATH,
1040
        $destinationDir,
1041
        PCLZIP_CB_PRE_EXTRACT,
1042
        'clean_up_files_in_zip',
1043
        PCLZIP_OPT_REPLACE_NEWER
1044
    );
1045
1046
    if (false === $onlyUploadFile) {
1047
        // Add all documents in the unzipped folder to the database
1048
        add_all_documents_in_folder_to_database(
1049
            $courseInfo,
1050
            $userInfo,
1051
            $base_work_dir,
1052
            $destinationDir,
1053
            $sessionId,
1054
            $groupId,
1055
            $output,
1056
            ['path' => $uploadPath],
1057
            $whatIfFileExists
1058
        );
1059
    } else {
1060
        // Copy result
1061
        $fs = new \Symfony\Component\Filesystem\Filesystem();
1062
        $fs->mirror($destinationDir, $base_work_dir.$uploadPath, null, ['overwrite']);
1063
    }
1064
1065
    if (is_dir($destinationDir)) {
1066
        rmdirr($destinationDir);
1067
    }
1068
1069
    return true;
1070
}
1071
1072
/**
1073
 * This function is a callback function that is used while extracting a zipfile
1074
 * http://www.phpconcept.net/pclzip/man/en/index.php?options-pclzip_cb_pre_extract.
1075
 *
1076
 * @param array $p_event
1077
 * @param array $p_header
1078
 *
1079
 * @return int (If the function returns 1, then the extraction is resumed, if 0 the path was skipped)
1080
 */
1081
function clean_up_files_in_zip($p_event, &$p_header)
1082
{
1083
    $originalStoredFileName = $p_header['stored_filename'];
1084
    $baseName = basename($originalStoredFileName);
1085
    // Skip files
1086
    $skipFiles = [
1087
        '__MACOSX',
1088
        '.Thumbs.db',
1089
        'Thumbs.db',
1090
    ];
1091
1092
    if (in_array($baseName, $skipFiles)) {
1093
        return 0;
1094
    }
1095
    $modifiedStoredFileName = clean_up_path($originalStoredFileName);
1096
    $p_header['filename'] = str_replace($originalStoredFileName, $modifiedStoredFileName, $p_header['filename']);
1097
1098
    return 1;
1099
}
1100
1101
function cleanZipFilesNoRename($p_event, &$p_header)
1102
{
1103
    $originalStoredFileName = $p_header['stored_filename'];
1104
    $baseName = basename($originalStoredFileName);
1105
    // Skip files
1106
    $skipFiles = [
1107
        '__MACOSX',
1108
        '.Thumbs.db',
1109
        'Thumbs.db',
1110
    ];
1111
1112
    if (in_array($baseName, $skipFiles)) {
1113
        return 0;
1114
    }
1115
    $modifiedStoredFileName = clean_up_path($originalStoredFileName, false);
1116
    $p_header['filename'] = str_replace($originalStoredFileName, $modifiedStoredFileName, $p_header['filename']);
1117
1118
    return 1;
1119
}
1120
1121
/**
1122
 * Allow .htaccess file.
1123
 *
1124
 * @param $p_event
1125
 * @param $p_header
1126
 *
1127
 * @return int
1128
 */
1129
function cleanZipFilesAllowHtaccess($p_event, &$p_header)
1130
{
1131
    $originalStoredFileName = $p_header['stored_filename'];
1132
    $baseName = basename($originalStoredFileName);
1133
1134
    $allowFiles = ['.htaccess'];
1135
    if (in_array($baseName, $allowFiles)) {
1136
        return 1;
1137
    }
1138
1139
    // Skip files
1140
    $skipFiles = [
1141
        '__MACOSX',
1142
        '.Thumbs.db',
1143
        'Thumbs.db',
1144
    ];
1145
1146
    if (in_array($baseName, $skipFiles)) {
1147
        return 0;
1148
    }
1149
    $modifiedStoredFileName = clean_up_path($originalStoredFileName);
1150
    $p_header['filename'] = str_replace($originalStoredFileName, $modifiedStoredFileName, $p_header['filename']);
1151
1152
    return 1;
1153
}
1154
1155
/**
1156
 * This function cleans up a given path
1157
 * by eliminating dangerous file names and cleaning them.
1158
 *
1159
 * @param string $path
1160
 * @param bool   $replaceName
1161
 *
1162
 * @return string
1163
 *
1164
 * @see disable_dangerous_file()
1165
 * @see api_replace_dangerous_char()
1166
 */
1167
function clean_up_path($path, $replaceName = true)
1168
{
1169
    // Split the path in folders and files
1170
    $path_array = explode('/', $path);
1171
    // Clean up every folder and filename in the path
1172
    foreach ($path_array as $key => &$val) {
1173
        // We don't want to lose the dots in ././folder/file (cfr. zipfile)
1174
        if ('.' != $val) {
1175
            if ($replaceName) {
1176
                $val = api_replace_dangerous_char($val);
1177
            }
1178
            $val = disable_dangerous_file($val);
1179
        }
1180
    }
1181
    // Join the "cleaned" path (modified in-place as passed by reference)
1182
    $path = implode('/', $path_array);
1183
    filter_extension($path);
1184
1185
    return $path;
1186
}
1187
1188
/**
1189
 * Checks if the file is dangerous, based on extension and/or mimetype.
1190
 * The list of extensions accepted/rejected can be found from
1191
 * api_get_setting('upload_extensions_exclude') and api_get_setting('upload_extensions_include').
1192
 *
1193
 * @param string $filename passed by reference. The filename will be modified
1194
 *                         if filter rules say so! (you can include path but the filename should look like 'abc.html')
1195
 *
1196
 * @return int 0 to skip file, 1 to keep file
1197
 */
1198
function filter_extension(&$filename)
1199
{
1200
    if ('/' == substr($filename, -1)) {
1201
        return 1; // Authorize directories
1202
    }
1203
    $blacklist = api_get_setting('upload_extensions_list_type');
1204
    if ('whitelist' != $blacklist) { // if = blacklist
1205
        $extensions = explode(';', strtolower(api_get_setting('upload_extensions_blacklist')));
1206
1207
        $skip = api_get_setting('upload_extensions_skip');
1208
        $ext = strrchr($filename, '.');
1209
        $ext = substr($ext, 1);
1210
        if (empty($ext)) {
1211
            return 1; // We're in blacklist mode, so accept empty extensions
1212
        }
1213
        if (in_array(strtolower($ext), $extensions)) {
1214
            if ('true' == $skip) {
1215
                return 0;
1216
            } else {
1217
                $new_ext = api_get_setting('upload_extensions_replace_by');
1218
                $filename = str_replace('.'.$ext, '.'.$new_ext, $filename);
1219
1220
                return 1;
1221
            }
1222
        } else {
1223
            return 1;
1224
        }
1225
    } else {
1226
        $extensions = explode(';', strtolower(api_get_setting('upload_extensions_whitelist')));
1227
        $skip = api_get_setting('upload_extensions_skip');
1228
        $ext = strrchr($filename, '.');
1229
        $ext = substr($ext, 1);
1230
        if (empty($ext)) {
1231
            return 1; // Accept empty extensions
1232
        }
1233
        if (!in_array(strtolower($ext), $extensions)) {
1234
            if ('true' == $skip) {
1235
                return 0;
1236
            } else {
1237
                $new_ext = api_get_setting('upload_extensions_replace_by');
1238
                $filename = str_replace('.'.$ext, '.'.$new_ext, $filename);
1239
1240
                return 1;
1241
            }
1242
        } else {
1243
            return 1;
1244
        }
1245
    }
1246
}
1247
1248
/**
1249
 * Updates an existing document in the database
1250
 * as the file exists, we only need to change the size.
1251
 *
1252
 * @param array $_course
1253
 * @param int   $documentId
1254
 * @param int   $filesize
1255
 * @param int   $readonly
1256
 *
1257
 * @return bool true /false
1258
 */
1259
function update_existing_document($_course, $documentId, $filesize, $readonly = 0)
1260
{
1261
    $document_table = Database::get_course_table(TABLE_DOCUMENT);
1262
    $documentId = intval($documentId);
1263
    $filesize = intval($filesize);
1264
    $readonly = intval($readonly);
1265
    $course_id = $_course['real_id'];
1266
1267
    $sql = "UPDATE $document_table SET
1268
            size = '$filesize',
1269
            readonly = '$readonly'
1270
			WHERE c_id = $course_id AND id = $documentId";
1271
    if (Database::query($sql)) {
1272
        return true;
1273
    } else {
1274
        return false;
1275
    }
1276
}
1277
1278
/**
1279
 * This function updates the last_edit_date, last edit user id on all folders in a given path.
1280
 *
1281
 * @param array  $_course
1282
 * @param string $path
1283
 * @param int    $user_id
1284
 */
1285
function item_property_update_on_folder($_course, $path, $user_id)
1286
{
1287
    // If we are in the root, just return... no need to update anything
1288
    if ('/' == $path) {
1289
        return;
1290
    }
1291
1292
    $user_id = intval($user_id);
1293
1294
    // If the given path ends with a / we remove it
1295
    $endchar = substr($path, strlen($path) - 1, 1);
1296
    if ('/' == $endchar) {
1297
        $path = substr($path, 0, strlen($path) - 1);
1298
    }
1299
1300
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1301
1302
    // Get the time
1303
    $time = api_get_utc_datetime();
1304
1305
    // Det all paths in the given path
1306
    // /folder/subfolder/subsubfolder/file
1307
    // if file is updated, subsubfolder, subfolder and folder are updated
1308
    $exploded_path = explode('/', $path);
1309
    $course_id = api_get_course_int_id();
1310
    $newpath = '';
1311
    foreach ($exploded_path as $key => &$value) {
1312
        // We don't want a slash before our first slash
1313
        if (0 != $key) {
1314
            $newpath .= '/'.$value;
1315
            // Select ID of given folder
1316
            $folder_id = DocumentManager::get_document_id($_course, $newpath);
1317
1318
            if ($folder_id) {
1319
                $sql = "UPDATE $table SET
1320
				        lastedit_date = '$time',
1321
				        lastedit_type = 'DocumentInFolderUpdated',
1322
				        lastedit_user_id='$user_id'
1323
						WHERE
1324
						    c_id = $course_id AND
1325
						    tool='".TOOL_DOCUMENT."' AND
1326
						    ref = '$folder_id'";
1327
                Database::query($sql);
1328
            }
1329
        }
1330
    }
1331
}
1332
1333
/**
1334
 * Adds file to document table in database
1335
 * deprecated: use file_set_default_settings instead.
1336
 *
1337
 * @author	Olivier Cauberghe <[email protected]>
1338
 *
1339
 * @param	path,filename
1340
 * action:	Adds an entry to the document table with the default settings
1341
 */
1342
function set_default_settings($upload_path, $filename, $filetype = 'file')
1343
{
1344
    $dbTable = Database::get_course_table(TABLE_DOCUMENT);
1345
    global $default_visibility;
1346
1347
    if (!$default_visibility) {
1348
        $default_visibility = 'v';
1349
    }
1350
    $filetype = Database::escape_string($filetype);
1351
1352
    $upload_path = str_replace('\\', '/', $upload_path);
1353
    $upload_path = str_replace('//', '/', $upload_path);
1354
1355
    if ('/' == $upload_path) {
1356
        $upload_path = '';
1357
    } elseif (!empty($upload_path) && '/' != $upload_path[0]) {
1358
        $upload_path = "/$upload_path";
1359
    }
1360
1361
    $endchar = substr($filename, strlen($filename) - 1, 1);
1362
1363
    if ('/' == $endchar) {
1364
        $filename = substr($filename, 0, -1);
1365
    }
1366
    $filename = Database::escape_string($filename);
1367
    $query = "SELECT count(*) as bestaat FROM $dbTable
1368
              WHERE path='$upload_path/$filename'";
1369
    $result = Database::query($query);
1370
    $row = Database::fetch_array($result);
1371
    if ($row['bestaat'] > 0) {
1372
        $query = "UPDATE $dbTable SET
1373
		            path='$upload_path/$filename',
1374
		            visibility='$default_visibility',
1375
		            filetype='$filetype'
1376
		          WHERE path='$upload_path/$filename'";
1377
    } else {
1378
        $query = "INSERT INTO $dbTable (path,visibility,filetype)
1379
		          VALUES('$upload_path/$filename','$default_visibility','$filetype')";
1380
    }
1381
    Database::query($query);
1382
}
1383
1384
/**
1385
 * Retrieves the image path list in a html file.
1386
 *
1387
 * @author Hugues Peeters <[email protected]>
1388
 *
1389
 * @param string $html_file
1390
 *
1391
 * @return array -  images path list
1392
 */
1393
function search_img_from_html($html_file)
1394
{
1395
    $img_path_list = [];
1396
1397
    if (!$fp = fopen($html_file, 'r')) {
1398
        return;
1399
    }
1400
1401
    // Aearch and store occurences of the <img> tag in an array
1402
    $size_file = (0 === filesize($html_file)) ? 1 : filesize($html_file);
1403
    if (isset($fp) && false !== $fp) {
1404
        $buffer = fread($fp, $size_file);
1405
        if (strlen($buffer) >= 0 && false !== $buffer) {
1406
        } else {
1407
            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...
1408
        }
1409
    } else {
1410
        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...
1411
    }
1412
    $matches = [];
1413
    if (preg_match_all('~<[[:space:]]*img[^>]*>~i', $buffer, $matches)) {
1414
        $img_tag_list = $matches[0];
1415
    }
1416
1417
    fclose($fp);
1418
    unset($buffer);
1419
1420
    // Search the image file path from all the <IMG> tag detected
1421
1422
    if (sizeof($img_tag_list) > 0) {
1423
        foreach ($img_tag_list as &$this_img_tag) {
1424
            if (preg_match('~src[[:space:]]*=[[:space:]]*[\"]{1}([^\"]+)[\"]{1}~i', $this_img_tag, $matches)) {
1425
                $img_path_list[] = $matches[1];
1426
            }
1427
        }
1428
        $img_path_list = array_unique($img_path_list); // Remove duplicate entries
1429
    }
1430
1431
    return $img_path_list;
1432
}
1433
1434
/**
1435
 * Creates a new directory trying to find a directory name
1436
 * that doesn't already exist.
1437
 *
1438
 * @author  Hugues Peeters <[email protected]>
1439
 * @author  Bert Vanderkimpen
1440
 *
1441
 * @param array  $_course                 current course information
1442
 * @param int    $user_id                 current user id
1443
 * @param int    $session_id
1444
 * @param int    $to_group_id             group.id
1445
 * @param int    $to_user_id
1446
 * @param string $base_work_dir           /var/www/chamilo/courses/ABC/document
1447
 * @param string $desired_dir_name        complete path of the desired name
1448
 *                                        Example: /folder1/folder2
1449
 * @param string $title                   "folder2"
1450
 * @param int    $visibility              (0 for invisible, 1 for visible, 2 for deleted)
1451
 * @param bool   $generateNewNameIfExists
1452
 * @param bool   $sendNotification        depends in conf setting "send_notification_when_document_added"
1453
 * @param array  $parentInfo
1454
 *
1455
 * @return CDocument|false
1456
 */
1457
function create_unexisting_directory(
1458
    $_course,
1459
    $user_id,
1460
    $session_id,
1461
    $to_group_id,
1462
    $to_user_id,
1463
    $base_work_dir,
1464
    $desired_dir_name,
1465
    $title = '',
1466
    $visibility = '',
1467
    $generateNewNameIfExists = false,
1468
    $sendNotification = true,
1469
    $parentInfo = null
1470
) {
1471
    $course_id = $_course['real_id'];
1472
    $session_id = (int) $session_id;
1473
1474
    $parentId = 0;
1475
    if (!empty($parentInfo)) {
1476
        if (is_array($parentInfo) && isset($parentInfo['iid'])) {
1477
            $parentId = $parentInfo['iid'];
1478
        }
1479
        if ($parentInfo instanceof CDocument) {
1480
            $parentId = $parentInfo->getIid();
1481
        }
1482
    }
1483
1484
    $document = DocumentManager::addDocument(
1485
        $_course,
1486
        $desired_dir_name,
1487
        'folder',
1488
        0,
1489
        $title,
1490
        null,
1491
        0,
1492
        true,
1493
        $to_group_id,
1494
        $session_id,
1495
        $user_id,
1496
        $sendNotification,
1497
        '',
1498
        $parentId
1499
    );
1500
1501
    if ($document) {
1502
        return $document;
1503
    }
1504
1505
    $folderExists = DocumentManager::folderExists(
1506
        $desired_dir_name,
1507
        $_course,
1508
        $session_id,
1509
        $to_group_id
1510
    );
1511
1512
    if (true === $folderExists) {
1513
        if ($generateNewNameIfExists) {
1514
            $counter = 1;
1515
            while (1) {
1516
                $folderExists = DocumentManager::folderExists(
1517
                    $desired_dir_name.'_'.$counter,
1518
                    $_course,
1519
                    $session_id,
1520
                    $to_group_id
1521
                );
1522
1523
                if (false === $folderExists) {
1524
                    break;
1525
                }
1526
                $counter++;
1527
            }
1528
            $desired_dir_name = $desired_dir_name.'_'.$counter;
1529
        }
1530
    }
1531
1532
    $systemFolderName = $desired_dir_name;
1533
1534
    // Adding suffix
1535
    $suffix = DocumentManager::getDocumentSuffix(
1536
        $_course,
1537
        $session_id,
1538
        $to_group_id
1539
    );
1540
1541
    $systemFolderName .= $suffix;
1542
1543
    if (null == $title) {
1544
        $title = basename($desired_dir_name);
1545
    }
1546
1547
    // Check if pathname already exists inside document table
1548
    $table = Database::get_course_table(TABLE_DOCUMENT);
1549
    $sql = "SELECT iid, path FROM $table
1550
            WHERE
1551
                c_id = $course_id AND
1552
                path = '".Database::escape_string($systemFolderName)."'";
1553
    $rs = Database::query($sql);
1554
1555
    $parentId = 0;
1556
    if (!empty($parentInfo) && isset($parentInfo['iid'])) {
1557
        $parentId = $parentInfo['iid'];
1558
    }
1559
1560
    if (0 == Database::num_rows($rs)) {
1561
        $document = DocumentManager::addDocument(
1562
            $_course,
1563
            $systemFolderName,
1564
            'folder',
1565
            0,
1566
            $title,
1567
            null,
1568
            0,
1569
            true,
1570
            $to_group_id,
1571
            $session_id,
1572
            $user_id,
1573
            $sendNotification,
1574
            '',
1575
            $parentId
1576
        );
1577
1578
        if ($document) {
1579
            return $document;
1580
        }
1581
    } else {
1582
        $document = Database::fetch_array($rs);
1583
        $documentData = DocumentManager::get_document_data_by_id(
1584
            $document['iid'],
1585
            $_course['code'],
1586
            false,
1587
            $session_id
1588
        );
1589
1590
        if ($documentData) {
1591
            $document = Container::getDocumentRepository()->find($documentData['iid']);
1592
1593
            return $document;
1594
        }
1595
    }
1596
1597
    return false;
1598
}
1599
1600
/**
1601
 * Handles uploaded missing images.
1602
 *
1603
 * @author Hugues Peeters <[email protected]>
1604
 * @author Bert Vanderkimpen
1605
 *
1606
 * @param array  $_course
1607
 * @param array  $uploaded_file_collection - follows the $_FILES Structure
1608
 * @param string $base_work_dir
1609
 * @param string $missing_files_dir
1610
 * @param int    $user_id
1611
 * @param int    $to_group_id              group.id
1612
 */
1613
function move_uploaded_file_collection_into_directory(
1614
    $_course,
1615
    $uploaded_file_collection,
1616
    $base_work_dir,
1617
    $missing_files_dir,
1618
    $user_id,
1619
    $to_group_id,
1620
    $to_user_id,
1621
    $max_filled_space
1622
) {
1623
    $number_of_uploaded_images = count($uploaded_file_collection['name']);
1624
    $list = [];
1625
    for ($i = 0; $i < $number_of_uploaded_images; $i++) {
1626
        $missing_file['name'] = $uploaded_file_collection['name'][$i];
1627
        $missing_file['type'] = $uploaded_file_collection['type'][$i];
1628
        $missing_file['tmp_name'] = $uploaded_file_collection['tmp_name'][$i];
1629
        $missing_file['error'] = $uploaded_file_collection['error'][$i];
1630
        $missing_file['size'] = $uploaded_file_collection['size'][$i];
1631
1632
        $upload_ok = process_uploaded_file($missing_file);
1633
        if ($upload_ok) {
1634
            $list[] = handle_uploaded_document(
1635
                $_course,
1636
                $missing_file,
1637
                $base_work_dir,
1638
                $missing_files_dir,
1639
                $user_id,
1640
                $to_group_id,
1641
                $to_user_id,
1642
                $max_filled_space,
1643
                0,
1644
                'overwrite'
1645
            );
1646
        }
1647
        unset($missing_file);
1648
    }
1649
1650
    return $list;
1651
}
1652
1653
/**
1654
 * Opens the old html file and replace the src path into the img tag
1655
 * This also works for files in subdirectories.
1656
 *
1657
 * @param $original_img_path is an array
1658
 * @param $new_img_path is an array
1659
 */
1660
function replace_img_path_in_html_file($original_img_path, $new_img_path, $html_file)
1661
{
1662
    // Open the file
1663
    $fp = fopen($html_file, 'r');
1664
    $buffer = fread($fp, filesize($html_file));
1665
    $new_html_content = '';
1666
1667
    // Fix the image tags
1668
    for ($i = 0, $fileNb = count($original_img_path); $i < $fileNb; $i++) {
1669
        $replace_what = $original_img_path[$i];
1670
        // We only need the directory and the filename /path/to/file_html_files/missing_file.gif -> file_html_files/missing_file.gif
1671
        $exploded_file_path = explode('/', $new_img_path[$i]);
1672
        $replace_by = $exploded_file_path[count($exploded_file_path) - 2].'/'.$exploded_file_path[count($exploded_file_path) - 1];
1673
        $buffer = str_replace($replace_what, $replace_by, $buffer);
1674
    }
1675
1676
    $new_html_content .= $buffer;
1677
1678
    @fclose($fp);
1679
1680
    // Write the resulted new file
1681
1682
    if (!$fp = fopen($html_file, 'w')) {
1683
        return;
1684
    }
1685
1686
    if (!fwrite($fp, $new_html_content)) {
1687
        return;
1688
    }
1689
}
1690
1691
/**
1692
 * Checks the extension of a file, if it's .htm or .html
1693
 * we use search_img_from_html to get all image paths in the file.
1694
 *
1695
 * @param string $file
1696
 *
1697
 * @return array paths
1698
 *
1699
 * @see check_for_missing_files() uses search_img_from_html()
1700
 */
1701
function check_for_missing_files($file)
1702
{
1703
    if ('.htm' == strrchr($file, '.') || '.html' == strrchr($file, '.')) {
1704
        $img_file_path = search_img_from_html($file);
1705
1706
        return $img_file_path;
1707
    }
1708
1709
    return false;
1710
}
1711
1712
/**
1713
 * This function builds a form that asks for the missing images in a html file
1714
 * maybe we should do this another way?
1715
 *
1716
 * @param array  $missing_files
1717
 * @param string $upload_path
1718
 * @param string $file_name
1719
 *
1720
 * @return string the form
1721
 */
1722
function build_missing_files_form($missing_files, $upload_path, $file_name)
1723
{
1724
    // Do we need a / or not?
1725
    $added_slash = ('/' == $upload_path) ? '' : '/';
1726
    $folder_id = DocumentManager::get_document_id(api_get_course_info(), $upload_path);
1727
    // Build the form
1728
    $form = "<p><strong>".get_lang('Missing images detected')."</strong></p>"
1729
        ."<form method=\"post\" action=\"".api_get_self()."\" enctype=\"multipart/form-data\">"
1730
        // Related_file is the path to the file that has missing images
1731
        ."<input type=\"hidden\" name=\"related_file\" value=\"".$upload_path.$added_slash.$file_name."\" />"
1732
        ."<input type=\"hidden\" name=\"upload_path\" value=\"".$upload_path."\" />"
1733
        ."<input type=\"hidden\" name=\"id\" value=\"".$folder_id."\" />"
1734
        ."<table border=\"0\">";
1735
    foreach ($missing_files as &$this_img_file_path) {
1736
        $form .= "<tr>"
1737
            ."<td>".basename($this_img_file_path)." : </td>"
1738
            ."<td>"
1739
            ."<input type=\"file\" name=\"img_file[]\"/>"
1740
            ."<input type=\"hidden\" name=\"img_file_path[]\" value=\"".$this_img_file_path."\" />"
1741
            ."</td>"
1742
            ."</tr>";
1743
    }
1744
    $form .= "</table>"
1745
        ."<button type='submit' name=\"cancel_submit_image\" value=\"".get_lang('Cancel')."\" class=\"cancel\">".get_lang('Cancel')."</button>"
1746
        ."<button type='submit' name=\"submit_image\" value=\"".get_lang('Validate')."\" class=\"save\">".get_lang('Validate')."</button>"
1747
        ."</form>";
1748
1749
    return $form;
1750
}
1751
1752
/**
1753
 * This recursive function can be used during the upgrade process form older
1754
 * versions of Chamilo
1755
 * It crawls the given directory, checks if the file is in the DB and adds
1756
 * it if it's not.
1757
 *
1758
 * @param array  $courseInfo
1759
 * @param array  $userInfo
1760
 * @param string $base_work_dir    course document dir
1761
 * @param string $folderPath       folder to read
1762
 * @param int    $sessionId
1763
 * @param int    $groupId          group.id
1764
 * @param bool   $output
1765
 * @param array  $parent
1766
 * @param string $whatIfFileExists
1767
 *
1768
 * @return bool
1769
 */
1770
function add_all_documents_in_folder_to_database(
1771
    $courseInfo,
1772
    $userInfo,
1773
    $base_work_dir,
1774
    $folderPath,
1775
    $sessionId = 0,
1776
    $groupId = 0,
1777
    $output = false,
1778
    $parent = [],
1779
    $whatIfFileExists = 'overwrite'
1780
) {
1781
    if (empty($userInfo) || empty($courseInfo)) {
1782
        return false;
1783
    }
1784
1785
    $userId = $userInfo['user_id'];
1786
1787
    // Open dir
1788
    $handle = opendir($folderPath);
1789
1790
    if (is_dir($folderPath)) {
1791
        // Run trough
1792
        while ($file = readdir($handle)) {
1793
            if ('.' == $file || '..' == $file) {
1794
                continue;
1795
            }
1796
1797
            $parentPath = '';
1798
            if (!empty($parent) && isset($parent['path'])) {
1799
                $parentPath = $parent['path'];
1800
                if ('/' == $parentPath) {
1801
                    $parentPath = '';
1802
                }
1803
            }
1804
1805
            $completePath = $parentPath.'/'.$file;
1806
            $sysFolderPath = $folderPath.'/'.$file;
1807
1808
            // Is directory?
1809
            if (is_dir($sysFolderPath)) {
1810
                $folderExists = DocumentManager::folderExists(
1811
                    $completePath,
1812
                    $courseInfo,
1813
                    $sessionId,
1814
                    $groupId
1815
                );
1816
1817
                if (true === $folderExists) {
1818
                    switch ($whatIfFileExists) {
1819
                        case 'overwrite':
1820
                            $documentId = DocumentManager::get_document_id($courseInfo, $completePath, $sessionId);
1821
                            if ($documentId) {
1822
                                $newFolderData = DocumentManager::get_document_data_by_id(
1823
                                    $documentId,
1824
                                    $courseInfo['code'],
1825
                                    false,
1826
                                    $sessionId
1827
                                );
1828
                            }
1829
                            break;
1830
                        case 'rename':
1831
                            $newFolderData = create_unexisting_directory(
1832
                                $courseInfo,
1833
                                $userId,
1834
                                $sessionId,
1835
                                $groupId,
1836
                                null,
1837
                                $base_work_dir,
1838
                                $completePath,
1839
                                null,
1840
                                null,
1841
                                true
1842
                            );
1843
                            break;
1844
                        case 'nothing':
1845
                            if ($output) {
1846
                                $documentId = DocumentManager::get_document_id($courseInfo, $completePath, $sessionId);
1847
                                if ($documentId) {
1848
                                    $folderData = DocumentManager::get_document_data_by_id(
1849
                                        $documentId,
1850
                                        $courseInfo['code'],
1851
                                        false,
1852
                                        $sessionId
1853
                                    );
1854
                                    Display::addFlash(
1855
                                        Display::return_message(
1856
                                            $folderData['path'].' '.get_lang(' already exists.'),
1857
                                            'warning'
1858
                                        )
1859
                                    );
1860
                                }
1861
                            }
1862
                            continue 2;
1863
                            break;
1864
                    }
1865
                } else {
1866
                    $newFolderData = create_unexisting_directory(
1867
                        $courseInfo,
1868
                        $userId,
1869
                        $sessionId,
1870
                        $groupId,
1871
                        null,
1872
                        $base_work_dir,
1873
                        $completePath,
1874
                        null,
1875
                        null,
1876
                        false
1877
                    );
1878
                }
1879
1880
                // Recursive
1881
                add_all_documents_in_folder_to_database(
1882
                    $courseInfo,
1883
                    $userInfo,
1884
                    $base_work_dir,
1885
                    $sysFolderPath,
1886
                    $sessionId,
1887
                    $groupId,
1888
                    $output,
1889
                    $newFolderData,
1890
                    $whatIfFileExists
1891
                );
1892
            } else {
1893
                // Rename
1894
                $uploadedFile = [
1895
                    'name' => $file,
1896
                    'tmp_name' => $sysFolderPath,
1897
                    'size' => filesize($sysFolderPath),
1898
                    'type' => null,
1899
                    'from_file' => true,
1900
                    'move_file' => true,
1901
                ];
1902
1903
                handle_uploaded_document(
1904
                    $courseInfo,
1905
                    $uploadedFile,
1906
                    $base_work_dir,
1907
                    $parentPath,
1908
                    $userId,
1909
                    $groupId,
1910
                    null,
1911
                    0,
1912
                    $whatIfFileExists,
1913
                    $output,
1914
                    false,
1915
                    null,
1916
                    $sessionId
1917
                );
1918
            }
1919
        }
1920
    }
1921
}
1922