Passed
Push — master ( 518cb9...ab560b )
by Julito
10:37
created

DocumentManager::addDocument()   F

Complexity

Conditions 20
Paths 2886

Size

Total Lines 196
Code Lines 113

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 113
nc 2886
nop 14
dl 0
loc 196
rs 0
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\Resource\ResourceFile;
5
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
6
use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
7
use Chamilo\CoreBundle\Framework\Container;
8
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
9
use Chamilo\CourseBundle\Entity\CDocument;
10
use Symfony\Component\HttpFoundation\File\UploadedFile;
11
use Chamilo\UserBundle\Entity\User;
12
use ChamiloSession as Session;
13
14
/**
15
 *  Class DocumentManager
16
 *  This is the document library for Chamilo.
17
 *  It is / will be used to provide a service layer to all document-using tools.
18
 *  and eliminate code duplication fro group documents, scorm documents, main documents.
19
 *  Include/require it in your code to use its functionality.
20
 *
21
 * @package chamilo.library
22
 */
23
class DocumentManager
24
{
25
    /**
26
     * Construct.
27
     */
28
    private function __construct()
29
    {
30
    }
31
32
    /**
33
     * @param string $course_code
34
     *
35
     * @return int the document folder quota for the current course in bytes
36
     *             or the default quota
37
     */
38
    public static function get_course_quota($course_code = null)
39
    {
40
        if (empty($course_code)) {
41
            $course_info = api_get_course_info();
42
        } else {
43
            $course_info = api_get_course_info($course_code);
44
        }
45
46
        $course_quota = null;
47
        if (empty($course_info)) {
48
            return DEFAULT_DOCUMENT_QUOTA;
49
        } else {
50
            $course_quota = $course_info['disk_quota'];
51
        }
52
        if (is_null($course_quota) || empty($course_quota)) {
53
            // Course table entry for quota was null, then use default value
54
            $course_quota = DEFAULT_DOCUMENT_QUOTA;
55
        }
56
57
        return $course_quota;
58
    }
59
60
    /**
61
     * Get the content type of a file by checking the extension
62
     * We could use mime_content_type() with php-versions > 4.3,
63
     * but this doesn't work as it should on Windows installations.
64
     *
65
     * @param string $filename or boolean TRUE to return complete array
66
     *
67
     * @author ? first version
68
     * @author Bert Vanderkimpen
69
     *
70
     * @return string
71
     */
72
    public static function file_get_mime_type($filename)
73
    {
74
        // All MIME types in an array (from 1.6, this is the authorative source)
75
        // Please, keep this alphabetical if you add something to this list!
76
        $mime_types = [
77
            'ai' => 'application/postscript',
78
            'aif' => 'audio/x-aiff',
79
            'aifc' => 'audio/x-aiff',
80
            'aiff' => 'audio/x-aiff',
81
            'asf' => 'video/x-ms-asf',
82
            'asc' => 'text/plain',
83
            'au' => 'audio/basic',
84
            'avi' => 'video/x-msvideo',
85
            'bcpio' => 'application/x-bcpio',
86
            'bin' => 'application/octet-stream',
87
            'bmp' => 'image/bmp',
88
            'cdf' => 'application/x-netcdf',
89
            'class' => 'application/octet-stream',
90
            'cpio' => 'application/x-cpio',
91
            'cpt' => 'application/mac-compactpro',
92
            'csh' => 'application/x-csh',
93
            'css' => 'text/css',
94
            'dcr' => 'application/x-director',
95
            'dir' => 'application/x-director',
96
            'djv' => 'image/vnd.djvu',
97
            'djvu' => 'image/vnd.djvu',
98
            'dll' => 'application/octet-stream',
99
            'dmg' => 'application/x-diskcopy',
100
            'dms' => 'application/octet-stream',
101
            'doc' => 'application/msword',
102
            'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
103
            'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
104
            'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
105
            'dvi' => 'application/x-dvi',
106
            'dwg' => 'application/vnd.dwg',
107
            'dwf' => 'application/vnd.dwf',
108
            'dxf' => 'application/vnd.dxf',
109
            'dxr' => 'application/x-director',
110
            'eps' => 'application/postscript',
111
            'epub' => 'application/epub+zip',
112
            'etx' => 'text/x-setext',
113
            'exe' => 'application/octet-stream',
114
            'ez' => 'application/andrew-inset',
115
            'flv' => 'video/flv',
116
            'gif' => 'image/gif',
117
            'gtar' => 'application/x-gtar',
118
            'gz' => 'application/x-gzip',
119
            'hdf' => 'application/x-hdf',
120
            'hqx' => 'application/mac-binhex40',
121
            'htm' => 'text/html',
122
            'html' => 'text/html',
123
            'ice' => 'x-conference-xcooltalk',
124
            'ief' => 'image/ief',
125
            'iges' => 'model/iges',
126
            'igs' => 'model/iges',
127
            'jar' => 'application/java-archiver',
128
            'jpe' => 'image/jpeg',
129
            'jpeg' => 'image/jpeg',
130
            'jpg' => 'image/jpeg',
131
            'js' => 'application/x-javascript',
132
            'kar' => 'audio/midi',
133
            'lam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
134
            'latex' => 'application/x-latex',
135
            'lha' => 'application/octet-stream',
136
            'log' => 'text/plain',
137
            'lzh' => 'application/octet-stream',
138
            'm1a' => 'audio/mpeg',
139
            'm2a' => 'audio/mpeg',
140
            'm3u' => 'audio/x-mpegurl',
141
            'man' => 'application/x-troff-man',
142
            'me' => 'application/x-troff-me',
143
            'mesh' => 'model/mesh',
144
            'mid' => 'audio/midi',
145
            'midi' => 'audio/midi',
146
            'mov' => 'video/quicktime',
147
            'movie' => 'video/x-sgi-movie',
148
            'mp2' => 'audio/mpeg',
149
            'mp3' => 'audio/mpeg',
150
            'mp4' => 'video/mp4',
151
            'mpa' => 'audio/mpeg',
152
            'mpe' => 'video/mpeg',
153
            'mpeg' => 'video/mpeg',
154
            'mpg' => 'video/mpeg',
155
            'mpga' => 'audio/mpeg',
156
            'ms' => 'application/x-troff-ms',
157
            'msh' => 'model/mesh',
158
            'mxu' => 'video/vnd.mpegurl',
159
            'nc' => 'application/x-netcdf',
160
            'oda' => 'application/oda',
161
            'oga' => 'audio/ogg',
162
            'ogg' => 'application/ogg',
163
            'ogx' => 'application/ogg',
164
            'ogv' => 'video/ogg',
165
            'pbm' => 'image/x-portable-bitmap',
166
            'pct' => 'image/pict',
167
            'pdb' => 'chemical/x-pdb',
168
            'pdf' => 'application/pdf',
169
            'pgm' => 'image/x-portable-graymap',
170
            'pgn' => 'application/x-chess-pgn',
171
            'pict' => 'image/pict',
172
            'png' => 'image/png',
173
            'pnm' => 'image/x-portable-anymap',
174
            'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
175
            'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
176
            'pps' => 'application/vnd.ms-powerpoint',
177
            'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
178
            'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
179
            'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
180
            'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
181
            'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
182
            'ppm' => 'image/x-portable-pixmap',
183
            'ppt' => 'application/vnd.ms-powerpoint',
184
            'pps' => 'application/vnd.ms-powerpoint',
185
            'ps' => 'application/postscript',
186
            'qt' => 'video/quicktime',
187
            'ra' => 'audio/x-realaudio',
188
            'ram' => 'audio/x-pn-realaudio',
189
            'rar' => 'image/x-rar-compressed',
190
            'ras' => 'image/x-cmu-raster',
191
            'rgb' => 'image/x-rgb',
192
            'rm' => 'audio/x-pn-realaudio',
193
            'roff' => 'application/x-troff',
194
            'rpm' => 'audio/x-pn-realaudio-plugin',
195
            'rtf' => 'text/rtf',
196
            'rtx' => 'text/richtext',
197
            'sgm' => 'text/sgml',
198
            'sgml' => 'text/sgml',
199
            'sh' => 'application/x-sh',
200
            'shar' => 'application/x-shar',
201
            'silo' => 'model/mesh',
202
            'sib' => 'application/X-Sibelius-Score',
203
            'sit' => 'application/x-stuffit',
204
            'skd' => 'application/x-koan',
205
            'skm' => 'application/x-koan',
206
            'skp' => 'application/x-koan',
207
            'skt' => 'application/x-koan',
208
            'smi' => 'application/smil',
209
            'smil' => 'application/smil',
210
            'snd' => 'audio/basic',
211
            'so' => 'application/octet-stream',
212
            'spl' => 'application/x-futuresplash',
213
            'src' => 'application/x-wais-source',
214
            'sv4cpio' => 'application/x-sv4cpio',
215
            'sv4crc' => 'application/x-sv4crc',
216
            'svf' => 'application/vnd.svf',
217
            'svg' => 'image/svg+xml',
218
            //'svgz' => 'image/svg+xml',
219
            'swf' => 'application/x-shockwave-flash',
220
            'sxc' => 'application/vnd.sun.xml.calc',
221
            'sxi' => 'application/vnd.sun.xml.impress',
222
            'sxw' => 'application/vnd.sun.xml.writer',
223
            't' => 'application/x-troff',
224
            'tar' => 'application/x-tar',
225
            'tcl' => 'application/x-tcl',
226
            'tex' => 'application/x-tex',
227
            'texi' => 'application/x-texinfo',
228
            'texinfo' => 'application/x-texinfo',
229
            'tga' => 'image/x-targa',
230
            'tif' => 'image/tif',
231
            'tiff' => 'image/tiff',
232
            'tr' => 'application/x-troff',
233
            'tsv' => 'text/tab-seperated-values',
234
            'txt' => 'text/plain',
235
            'ustar' => 'application/x-ustar',
236
            'vcd' => 'application/x-cdlink',
237
            'vrml' => 'model/vrml',
238
            'wav' => 'audio/x-wav',
239
            'wbmp' => 'image/vnd.wap.wbmp',
240
            'wbxml' => 'application/vnd.wap.wbxml',
241
            'wml' => 'text/vnd.wap.wml',
242
            'wmlc' => 'application/vnd.wap.wmlc',
243
            'wmls' => 'text/vnd.wap.wmlscript',
244
            'wmlsc' => 'application/vnd.wap.wmlscriptc',
245
            'wma' => 'audio/x-ms-wma',
246
            'wmv' => 'video/x-ms-wmv',
247
            'wrl' => 'model/vrml',
248
            'xbm' => 'image/x-xbitmap',
249
            'xht' => 'application/xhtml+xml',
250
            'xhtml' => 'application/xhtml+xml',
251
            'xls' => 'application/vnd.ms-excel',
252
            'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
253
            'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
254
            'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
255
            'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
256
            'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
257
            'xml' => 'text/xml',
258
            'xpm' => 'image/x-xpixmap',
259
            'xsl' => 'text/xml',
260
            'xwd' => 'image/x-windowdump',
261
            'xyz' => 'chemical/x-xyz',
262
            'zip' => 'application/zip',
263
        ];
264
265
        if ($filename === true) {
266
            return $mime_types;
267
        }
268
269
        //get the extension of the file
270
        $extension = explode('.', $filename);
271
272
        //$filename will be an array if a . was found
273
        if (is_array($extension)) {
274
            $extension = strtolower($extension[count($extension) - 1]);
275
        } else {
276
            //file without extension
277
            $extension = 'empty';
278
        }
279
280
        //if the extension is found, return the content type
281
        if (isset($mime_types[$extension])) {
282
            return $mime_types[$extension];
283
        }
284
285
        //else return octet-stream
286
        return 'application/octet-stream';
287
    }
288
289
    /**
290
     * This function streams a file to the client.
291
     *
292
     * @param string $full_file_name
293
     * @param bool   $forced
294
     * @param string $name
295
     * @param bool   $fixLinksHttpToHttps change file content from http to https
296
     *
297
     * @return false if file doesn't exist, true if stream succeeded
298
     */
299
    public static function file_send_for_download(
300
        $full_file_name,
301
        $forced = false,
302
        $name = '',
303
        $fixLinksHttpToHttps = false
304
    ) {
305
        session_write_close(); //we do not need write access to session anymore
306
        if (!is_file($full_file_name)) {
307
            return false;
308
        }
309
        $filename = $name == '' ? basename($full_file_name) : api_replace_dangerous_char($name);
310
        $len = filesize($full_file_name);
311
        // Fixing error when file name contains a ","
312
        $filename = str_replace(',', '', $filename);
313
        $sendFileHeaders = api_get_configuration_value('enable_x_sendfile_headers');
314
315
        // Allows chrome to make videos and audios seekable
316
        header('Accept-Ranges: bytes');
317
318
        if ($forced) {
319
            // Force the browser to save the file instead of opening it
320
            if (isset($sendFileHeaders) &&
321
                !empty($sendFileHeaders)) {
322
                header("X-Sendfile: $filename");
323
            }
324
325
            header('Content-type: application/octet-stream');
326
            header('Content-length: '.$len);
327
            if (preg_match("/MSIE 5.5/", $_SERVER['HTTP_USER_AGENT'])) {
328
                header('Content-Disposition: filename= '.$filename);
329
            } else {
330
                header('Content-Disposition: attachment; filename= '.$filename);
331
            }
332
            if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
333
                header('Pragma: ');
334
                header('Cache-Control: ');
335
                header('Cache-Control: public'); // IE cannot download from sessions without a cache
336
            }
337
            header('Content-Description: '.$filename);
338
            header('Content-Transfer-Encoding: binary');
339
340
            if (function_exists('ob_end_clean') && ob_get_length()) {
341
                // Use ob_end_clean() to avoid weird buffering situations
342
                // where file is sent broken/incomplete for download
343
                ob_end_clean();
344
            }
345
346
            $res = fopen($full_file_name, 'r');
347
            fpassthru($res);
348
349
            return true;
350
        } else {
351
            // no forced download, just let the browser decide what to do according to the mimetype
352
            $lpFixedEncoding = api_get_setting('lp.fixed_encoding') === 'true';
353
354
            // Commented to let courses content to be cached in order to improve performance:
355
            //header('Expires: Wed, 01 Jan 1990 00:00:00 GMT');
356
            //header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
357
358
            // Commented to avoid double caching declaration when playing with IE and HTTPS
359
            //header('Cache-Control: no-cache, must-revalidate');
360
            //header('Pragma: no-cache');
361
362
            $contentType = self::file_get_mime_type($filename);
363
364
            switch ($contentType) {
365
                case 'text/html':
366
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
367
                        $contentType .= '; charset=UTF-8';
368
                    } else {
369
                        $encoding = @api_detect_encoding_html(file_get_contents($full_file_name));
370
                        if (!empty($encoding)) {
371
                            $contentType .= '; charset='.$encoding;
372
                        }
373
                    }
374
                    break;
375
                case 'text/plain':
376
                    if (isset($lpFixedEncoding) && $lpFixedEncoding === 'true') {
377
                        $contentType .= '; charset=UTF-8';
378
                    } else {
379
                        $encoding = @api_detect_encoding(strip_tags(file_get_contents($full_file_name)));
380
                        if (!empty($encoding)) {
381
                            $contentType .= '; charset='.$encoding;
382
                        }
383
                    }
384
                    break;
385
                case 'application/vnd.dwg':
386
                case 'application/vnd.dwf':
387
                    header('Content-type: application/octet-stream');
388
                    break;
389
            }
390
391
            header('Content-type: '.$contentType);
392
            header('Content-Length: '.$len);
393
            $userAgent = strtolower($_SERVER['HTTP_USER_AGENT']);
394
395
            if (strpos($userAgent, 'msie')) {
396
                header('Content-Disposition: ; filename= '.$filename);
397
            } else {
398
                //header('Content-Disposition: inline');
399
                header('Content-Disposition: inline;');
400
            }
401
402
            if ($fixLinksHttpToHttps) {
403
                $content = file_get_contents($full_file_name);
404
                $content = str_replace(
405
                    ['http%3A%2F%2F', 'http://'],
406
                    ['https%3A%2F%2F', 'https://'],
407
                    $content
408
                );
409
                echo $content;
410
            } else {
411
                if (function_exists('ob_end_clean') && ob_get_length()) {
412
                    // Use ob_end_clean() to avoid weird buffering situations
413
                    // where file is sent broken/incomplete for download
414
                    ob_end_clean();
415
                }
416
417
                readfile($full_file_name);
418
            }
419
420
            return true;
421
        }
422
    }
423
424
    /**
425
     * Session folder filters.
426
     *
427
     * @param string $path
428
     * @param int    $sessionId
429
     *
430
     * @return null|string
431
     */
432
    public static function getSessionFolderFilters($path, $sessionId)
433
    {
434
        $sessionId = intval($sessionId);
435
        $condition = null;
436
437
        if (!empty($sessionId)) {
438
            // Chat folder filter
439
            if ($path == '/chat_files') {
440
                $condition .= " AND (docs.session_id = '$sessionId') ";
441
            }
442
            // share_folder filter
443
            $condition .= " AND docs.path != '/shared_folder' ";
444
        }
445
446
        return $condition;
447
    }
448
449
    /**
450
     * Fetches all document data for the given user/group.
451
     *
452
     * @param array     $courseInfo
453
     * @param string    $path
454
     * @param int       $toGroupId       iid
455
     * @param int       $toUserId
456
     * @param bool      $canSeeInvisible
457
     * @param bool      $search
458
     * @param int       $sessionId
459
     * @param User|null $currentUser
460
     *
461
     * @return array with all document data
462
     */
463
    public static function getAllDocumentData(
464
        $courseInfo,
465
        $path = '/',
466
        $toGroupId = 0,
467
        $toUserId = null,
468
        $canSeeInvisible = false,
469
        $search = false,
470
        $sessionId = 0,
471
        User $currentUser = null
472
    ) {
473
        $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
474
        $currentUser = $currentUser ?: api_get_current_user();
475
476
        $userGroupFilter = '';
477
        if (!is_null($toUserId)) {
478
            $toUserId = intval($toUserId);
479
            $userGroupFilter = "last.to_user_id = $toUserId";
480
            if (empty($toUserId)) {
481
                $userGroupFilter = " (last.to_user_id = 0 OR last.to_user_id IS NULL) ";
482
            }
483
        } else {
484
            $toGroupId = intval($toGroupId);
485
            $userGroupFilter = "last.to_group_id = $toGroupId";
486
            if (empty($toGroupId)) {
487
                $userGroupFilter = "( last.to_group_id = 0 OR last.to_group_id IS NULL) ";
488
            }
489
        }
490
491
        // Escape underscores in the path so they don't act as a wildcard
492
        $originalPath = $path;
493
        $path = str_replace('_', '\_', $path);
494
495
        $visibilityBit = ' <> 2';
496
497
        // The given path will not end with a slash, unless it's the root '/'
498
        // so no root -> add slash
499
        $addedSlash = $path == '/' ? '' : '/';
500
501
        // Condition for the session
502
        $sessionId = $sessionId ?: api_get_session_id();
503
        $conditionSession = " AND (last.session_id = '$sessionId' OR (last.session_id = '0' OR last.session_id IS NULL) )";
504
        $conditionSession .= self::getSessionFolderFilters($originalPath, $sessionId);
505
506
        $sharedCondition = null;
507
        if ($originalPath == '/shared_folder') {
508
            $students = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
509
            if (!empty($students)) {
510
                $conditionList = [];
511
                foreach ($students as $studentInfo) {
512
                    $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
513
                }
514
                $sharedCondition .= ' AND docs.path IN ("'.implode('","', $conditionList).'")';
515
            }
516
        }
517
518
        $sql = "SELECT
519
                    docs.id,
520
                    docs.filetype,
521
                    docs.path,
522
                    docs.title,
523
                    docs.comment,
524
                    docs.size,
525
                    docs.readonly,
526
                    docs.session_id,
527
                    creator_id,
528
                    visibility,
529
                    n.updated_at,
530
                    n.created_at,
531
                    n.creator_id                                     
532
                FROM resource_node AS n
533
                INNER JOIN $tblDocument AS docs
534
                ON (docs.resource_node_id = n.id)
535
                INNER JOIN resource_link l
536
                ON (l.resource_node_id = n.id)                
537
                WHERE
538
                    docs.c_id = {$courseInfo['real_id']} AND                    
539
                    docs.path LIKE '".Database::escape_string($path.$addedSlash.'%')."' AND
540
                    docs.path NOT LIKE '".Database::escape_string($path.$addedSlash.'%/%')."' AND
541
                    docs.path NOT LIKE '%_DELETED_%' AND
542
                    l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')
543
                    $sharedCondition               
544
                ";
545
        //$userGroupFilter AND
546
        //$conditionSession
547
        $result = Database::query($sql);
548
549
        $documentData = [];
550
        $isAllowedToEdit = api_is_allowed_to_edit(null, true);
551
        $isCoach = api_is_coach();
552
        if ($result !== false && Database::num_rows($result) != 0) {
553
            $rows = [];
554
555
            $hideInvisibleDocuments = api_get_configuration_value('hide_invisible_course_documents_in_sessions');
556
557
            while ($row = Database::fetch_array($result, 'ASSOC')) {
558
                if (isset($rows[$row['id']])) {
559
                    continue;
560
                }
561
562
                // If we are in session and hide_invisible_course_documents_in_sessions is enabled
563
                // Then we avoid the documents that have visibility in session but that they come from a base course
564
                if ($hideInvisibleDocuments && $sessionId) {
565
                    if ($row['item_property_session_id'] == $sessionId && empty($row['session_id'])) {
566
                        continue;
567
                    }
568
                }
569
570
                $rows[$row['id']] = $row;
571
            }
572
573
            // If we are in session and hide_invisible_course_documents_in_sessions is enabled
574
            // Or if we are students
575
            // Then don't list the invisible or deleted documents
576
            if (($sessionId && $hideInvisibleDocuments) || (!$isCoach && !$isAllowedToEdit)) {
577
                $rows = array_filter($rows, function ($row) {
578
                    if (in_array(
579
                        $row['visibility'],
580
                        [
581
                            ResourceLink::VISIBILITY_DELETED,
582
                            ResourceLink::VISIBILITY_DRAFT,
583
                        ]
584
                    )) {
585
                        return false;
586
                    }
587
588
                    return true;
589
                });
590
            }
591
592
            foreach ($rows as $row) {
593
                if ($row['filetype'] == 'file' &&
594
                    pathinfo($row['path'], PATHINFO_EXTENSION) == 'html'
595
                ) {
596
                    // Templates management
597
                    $tblTemplate = Database::get_main_table(TABLE_MAIN_TEMPLATES);
598
                    $sql = "SELECT id FROM $tblTemplate
599
                            WHERE
600
                                c_id = '".$courseInfo['real_id']."' AND
601
                                user_id = '".$currentUser->getId()."' AND
602
                                ref_doc = '".$row['id']."'";
603
                    $templateResult = Database::query($sql);
604
                    $row['is_template'] = (Database::num_rows($templateResult) > 0) ? 1 : 0;
605
                }
606
                $row['basename'] = basename($row['path']);
607
                // Just filling $document_data.
608
                $documentData[$row['id']] = $row;
609
            }
610
611
            // Only for the student we filter the results see BT#1652
612
            if (!$isCoach && !$isAllowedToEdit) {
613
                // Checking parents visibility.
614
                $finalDocumentData = [];
615
                foreach ($documentData as $row) {
616
                    $isVisible = self::check_visibility_tree(
617
                        $row['id'],
618
                        $courseInfo['code'],
619
                        $sessionId,
620
                        $currentUser->getId(),
621
                        $toGroupId
622
                    );
623
                    if ($isVisible) {
624
                        $finalDocumentData[$row['id']] = $row;
625
                    }
626
                }
627
            } else {
628
                $finalDocumentData = $documentData;
629
            }
630
631
            return $finalDocumentData;
632
        } else {
633
            return [];
634
        }
635
    }
636
637
    /**
638
     * Gets the paths of all folders in a course
639
     * can show all folders (except for the deleted ones) or only visible ones.
640
     *
641
     * @param array  $_course
642
     * @param int    $groupIid          iid
643
     * @param bool   $can_see_invisible
644
     * @param bool   $getInvisibleList
645
     * @param string $path              current path
646
     *
647
     * @return array with paths
648
     */
649
    public static function get_all_document_folders(
650
        $_course,
651
        $groupIid = 0,
652
        $can_see_invisible = false,
653
        $getInvisibleList = false,
654
        $path = ''
655
    ) {
656
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
657
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
658
        $groupIid = intval($groupIid);
659
        $document_folders = [];
660
661
        $students = CourseManager::get_user_list_from_course_code(
662
            $_course['code'],
663
            api_get_session_id()
664
        );
665
666
        $conditionList = [];
667
        if (!empty($students)) {
668
            foreach ($students as $studentId => $studentInfo) {
669
                $conditionList[] = '/shared_folder/sf_user_'.$studentInfo['user_id'];
670
            }
671
        }
672
673
        $groupCondition = " l.to_group_id = $groupIid";
674
        if (empty($groupIid)) {
675
            $groupCondition = " (l.group_id = 0 OR l.group_id IS NULL)";
676
        }
677
678
        $show_users_condition = '';
679
        if (api_get_setting('show_users_folders') === 'false') {
680
            $show_users_condition = " AND docs.path NOT LIKE '%shared_folder%'";
681
        }
682
683
        if ($can_see_invisible) {
684
            // condition for the session
685
            $session_id = api_get_session_id();
686
            $session_id = $session_id ?: api_get_session_id();
687
            $condition_session = " AND (l.session_id = '$session_id' OR (l.session_id = '0' OR l.session_id IS NULL) )";
688
            $condition_session .= self::getSessionFolderFilters($path, $session_id);
689
690
            if ($groupIid != 0) {
691
                $sql = "SELECT DISTINCT docs.id, path
692
                       FROM $TABLE_ITEMPROPERTY  AS last
693
                       INNER JOIN $TABLE_DOCUMENT  AS docs
694
                       ON (
695
                            docs.id = last.ref AND
696
                            docs.c_id = last.c_id
697
                       )
698
                       WHERE                       
699
                            last.tool = '".TOOL_DOCUMENT."' AND
700
                            last.c_id = {$_course['real_id']} AND
701
                            docs.c_id = {$_course['real_id']} AND
702
                            docs.filetype = 'folder' AND
703
                            $groupCondition AND
704
                            docs.path NOT LIKE '%shared_folder%' AND
705
                            docs.path NOT LIKE '%_DELETED_%' AND
706
                            last.visibility <> 2                            
707
                            $condition_session ";
708
            } else {
709
                $sql = "SELECT DISTINCT docs.id, docs.path
710
                        FROM resource_node AS n
711
                        INNER JOIN $TABLE_DOCUMENT  AS docs
712
                        ON (docs.resource_node_id = n.id)
713
                        INNER JOIN resource_link l
714
                        ON (l.resource_node_id = n.id)  
715
                        WHERE                            
716
                            docs.c_id = {$_course['real_id']} AND
717
                            docs.filetype = 'folder' AND
718
                            docs.path NOT LIKE '%_DELETED_%' AND
719
                            $groupCondition AND
720
                            l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')
721
                            $show_users_condition 
722
                            $condition_session 
723
                        ";
724
            }
725
726
            $result = Database::query($sql);
727
728
            if ($result && Database::num_rows($result) != 0) {
729
                while ($row = Database::fetch_array($result, 'ASSOC')) {
730
                    if (self::is_folder_to_avoid($row['path'])) {
731
                        continue;
732
                    }
733
734
                    if (strpos($row['path'], '/shared_folder/') !== false) {
735
                        if (!in_array($row['path'], $conditionList)) {
736
                            continue;
737
                        }
738
                    }
739
740
                    $document_folders[$row['id']] = $row['path'];
741
                }
742
743
                if (!empty($document_folders)) {
744
                    natsort($document_folders);
745
                }
746
747
                return $document_folders;
748
            } else {
749
                return false;
750
            }
751
        } else {
752
            // No invisible folders
753
            // Condition for the session
754
            $session_id = api_get_session_id();
755
            $condition_session = api_get_session_condition(
756
                $session_id,
757
                true,
758
                false,
759
                'docs.session_id'
760
            );
761
762
            $visibilityCondition = 'last.visibility = 1';
763
            $fileType = "docs.filetype = 'folder' AND";
764
            if ($getInvisibleList) {
765
                $visibilityCondition = 'last.visibility = 0';
766
                $fileType = '';
767
            }
768
769
            //get visible folders
770
            $sql = "SELECT DISTINCT docs.id, path
771
                    FROM
772
                    $TABLE_ITEMPROPERTY AS last 
773
                    INNER JOIN $TABLE_DOCUMENT AS docs
774
                    ON (docs.id = last.ref AND last.c_id = docs.c_id)
775
                    WHERE
776
                        $fileType
777
                        last.tool = '".TOOL_DOCUMENT."' AND
778
                        $groupCondition AND
779
                        $visibilityCondition
780
                        $show_users_condition
781
                        $condition_session AND
782
                        last.c_id = {$_course['real_id']}  AND
783
                        docs.c_id = {$_course['real_id']} ";
784
785
            $result = Database::query($sql);
786
787
            $visibleFolders = [];
788
            while ($row = Database::fetch_array($result, 'ASSOC')) {
789
                $visibleFolders[$row['id']] = $row['path'];
790
            }
791
792
            if ($getInvisibleList) {
793
                return $visibleFolders;
794
            }
795
796
            //get invisible folders
797
            $sql = "SELECT DISTINCT docs.id, path
798
                    FROM $TABLE_ITEMPROPERTY AS last 
799
                    INNER JOIN $TABLE_DOCUMENT AS docs
800
                    ON (docs.id = last.ref AND last.c_id = docs.c_id)
801
                    WHERE                        
802
                        docs.filetype = 'folder' AND
803
                        last.tool = '".TOOL_DOCUMENT."' AND
804
                        $groupCondition AND
805
                        last.visibility = 0 $condition_session AND
806
                        last.c_id = {$_course['real_id']} AND
807
                        docs.c_id = {$_course['real_id']} ";
808
            $result = Database::query($sql);
809
            $invisibleFolders = [];
810
            while ($row = Database::fetch_array($result, 'ASSOC')) {
811
                //get visible folders in the invisible ones -> they are invisible too
812
                $sql = "SELECT DISTINCT docs.id, path
813
                        FROM $TABLE_ITEMPROPERTY AS last 
814
                        INNER JOIN $TABLE_DOCUMENT AS docs
815
                        ON (docs.id = last.ref AND docs.c_id = last.c_id)
816
                        WHERE                            
817
                            docs.path LIKE '".Database::escape_string($row['path'].'/%')."' AND
818
                            docs.filetype = 'folder' AND
819
                            last.tool = '".TOOL_DOCUMENT."' AND
820
                            $groupCondition AND
821
                            last.visibility = 1 $condition_session AND
822
                            last.c_id = {$_course['real_id']} AND
823
                            docs.c_id = {$_course['real_id']}  ";
824
                $folder_in_invisible_result = Database::query($sql);
825
                while ($folders_in_invisible_folder = Database::fetch_array($folder_in_invisible_result, 'ASSOC')) {
826
                    $invisibleFolders[$folders_in_invisible_folder['id']] = $folders_in_invisible_folder['path'];
827
                }
828
            }
829
830
            // If both results are arrays -> //calculate the difference between the 2 arrays -> only visible folders are left :)
831
            if (is_array($visibleFolders) && is_array($invisibleFolders)) {
832
                $document_folders = array_diff($visibleFolders, $invisibleFolders);
833
                natsort($document_folders);
834
835
                return $document_folders;
836
            } elseif (is_array($visibleFolders)) {
837
                natsort($visibleFolders);
838
839
                return $visibleFolders;
840
            } else {
841
                //no visible folders found
842
                return false;
843
            }
844
        }
845
    }
846
847
    /**
848
     * This check if a document has the readonly property checked, then see if the user
849
     * is the owner of this file, if all this is true then return true.
850
     *
851
     * @param array  $_course
852
     * @param int    $user_id     id of the current user
853
     * @param string $file        path stored in the database (if not defined, $documentId must be used)
854
     * @param int    $document_id in case you dont have the file path ,
855
     *                            insert the id of the file here and leave $file in blank ''
856
     * @param bool   $to_delete
857
     * @param int    $sessionId
858
     *
859
     * @return bool true/false
860
     * */
861
    public static function check_readonly(
862
        $_course,
863
        $user_id,
864
        $file = null,
865
        $document_id = 0,
866
        $to_delete = false,
867
        $sessionId = null,
868
        $documentId = null
869
    ) {
870
        if (empty($sessionId)) {
871
            $sessionId = api_get_session_id();
872
        } else {
873
            $sessionId = intval($sessionId);
874
        }
875
876
        if (empty($document_id) || !is_numeric($document_id)) {
877
            $document_id = self::get_document_id($_course, $file, $sessionId);
878
        } else {
879
            $document_id = intval($document_id);
880
        }
881
882
        $TABLE_PROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
883
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
884
        $course_id = $_course['real_id'];
885
886
        if ($to_delete) {
887
            if (self::is_folder($_course, $document_id)) {
888
                if (!empty($file)) {
889
                    $path = Database::escape_string($file);
890
                    // Check
891
                    $sql = "SELECT td.id, readonly, tp.insert_user_id
892
                            FROM $TABLE_DOCUMENT td 
893
                            INNER JOIN $TABLE_PROPERTY tp
894
                            ON (td.c_id = tp.c_id AND tp.ref= td.id)
895
                            WHERE
896
                                td.c_id = $course_id AND
897
                                tp.c_id = $course_id AND
898
                                td.session_id = $sessionId AND                                
899
                                (path='".$path."' OR path LIKE BINARY '".$path."/%' ) ";
900
                    // Get all id's of documents that are deleted
901
                    $what_to_check_result = Database::query($sql);
902
903
                    if ($what_to_check_result && Database::num_rows($what_to_check_result) != 0) {
904
                        // file with readonly set to 1 exist?
905
                        $readonly_set = false;
906
                        while ($row = Database::fetch_array($what_to_check_result)) {
907
                            //query to delete from item_property table
908
                            if ($row['readonly'] == 1) {
909
                                if (!($row['insert_user_id'] == $user_id)) {
910
                                    $readonly_set = true;
911
                                    break;
912
                                }
913
                            }
914
                        }
915
916
                        if ($readonly_set) {
917
                            return true;
918
                        }
919
                    }
920
                }
921
922
                return false;
923
            }
924
        }
925
926
        if (!empty($document_id)) {
927
            $sql = "SELECT a.insert_user_id, b.readonly
928
                   FROM $TABLE_PROPERTY a 
929
                   INNER JOIN $TABLE_DOCUMENT b
930
                   ON (a.c_id = b.c_id AND a.ref= b.id)
931
                   WHERE
932
            			a.c_id = $course_id AND
933
                        b.c_id = $course_id AND
934
            			a.ref = $document_id 
935
                    LIMIT 1";
936
            $result = Database::query($sql);
937
            $doc_details = Database::fetch_array($result, 'ASSOC');
938
939
            if ($doc_details['readonly'] == 1) {
940
                return !($doc_details['insert_user_id'] == $user_id || api_is_platform_admin());
941
            }
942
        }
943
944
        return false;
945
    }
946
947
    /**
948
     * This check if a document is a folder or not.
949
     *
950
     * @param array $_course
951
     * @param int   $id      document id
952
     *
953
     * @return bool true/false
954
     * */
955
    public static function is_folder($_course, $id)
956
    {
957
        $table = Database::get_course_table(TABLE_DOCUMENT);
958
        if (empty($_course)) {
959
            return false;
960
        }
961
        $course_id = $_course['real_id'];
962
        $id = (int) $id;
963
        $sql = "SELECT filetype FROM $table
964
                WHERE c_id = $course_id AND id= $id";
965
        $result = Database::fetch_array(Database::query($sql), 'ASSOC');
966
967
        return $result['filetype'] == 'folder';
968
    }
969
970
    /**
971
     * @param int   $document_id
972
     * @param array $course_info
973
     * @param int   $session_id
974
     * @param bool  $remove_content_from_db
975
     */
976
    public static function deleteDocumentFromDb(
977
        $document_id,
978
        $course_info = [],
979
        $session_id = 0,
980
        $remove_content_from_db = false
981
    ) {
982
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
983
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
984
985
        // Deleting from the DB
986
        $user_id = api_get_user_id();
987
        $document_id = intval($document_id);
988
989
        if (empty($course_info)) {
990
            $course_info = api_get_course_info();
991
        }
992
993
        if (empty($session_id)) {
994
            $session_id = api_get_session_id();
995
        }
996
        // Soft DB delete
997
        api_item_property_update(
998
            $course_info,
999
            TOOL_DOCUMENT,
1000
            $document_id,
1001
            'delete',
1002
            $user_id,
1003
            null,
1004
            null,
1005
            null,
1006
            null,
1007
            $session_id
1008
        );
1009
        self::delete_document_from_search_engine($course_info['code'], $document_id);
1010
        self::unsetDocumentAsTemplate($document_id, $course_info['real_id'], $user_id);
1011
1012
        //Hard DB delete
1013
        if ($remove_content_from_db) {
1014
            $sql = "DELETE FROM $TABLE_ITEMPROPERTY
1015
                    WHERE
1016
                        c_id = {$course_info['real_id']} AND
1017
                        ref = ".$document_id." AND
1018
                        tool='".TOOL_DOCUMENT."'";
1019
            Database::query($sql);
1020
1021
            $sql = "DELETE FROM $TABLE_DOCUMENT
1022
                    WHERE c_id = {$course_info['real_id']} AND id = ".$document_id;
1023
            Database::query($sql);
1024
        }
1025
    }
1026
1027
    /**
1028
     * This deletes a document by changing visibility to 2, renaming it to filename_DELETED_#id
1029
     * Files/folders that are inside a deleted folder get visibility 2.
1030
     *
1031
     * @param array  $_course
1032
     * @param string $path          Path stored in the database
1033
     * @param string $base_work_dir Path to the documents folder (if not defined, $documentId must be used)
1034
     * @param int    $sessionId     The ID of the session, if any
1035
     * @param int    $documentId    The document id, if available
1036
     * @param int    $groupId       iid
1037
     *
1038
     * @return bool true/false
1039
     *
1040
     * @todo now only files/folders in a folder get visibility 2, we should rename them too.
1041
     * @todo We should be able to get rid of this later when using only documentId (check further usage)
1042
     */
1043
    public static function delete_document(
1044
        $_course,
1045
        $path = null,
1046
        $base_work_dir = null,
1047
        $sessionId = null,
1048
        $documentId = null,
1049
        $groupId = 0
1050
    ) {
1051
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1052
1053
        $groupId = (int) $groupId;
1054
        if (empty($groupId)) {
1055
            $groupId = api_get_group_id();
1056
        }
1057
1058
        $sessionId = (int) $sessionId;
1059
        if (empty($sessionId)) {
1060
            $sessionId = api_get_session_id();
1061
        }
1062
1063
        $course_id = $_course['real_id'];
1064
1065
        if (empty($course_id)) {
1066
            return false;
1067
        }
1068
1069
        if (empty($base_work_dir)) {
1070
            return false;
1071
        }
1072
1073
        if (empty($documentId)) {
1074
            $documentId = self::get_document_id($_course, $path, $sessionId);
1075
            $docInfo = self::get_document_data_by_id(
1076
                $documentId,
1077
                $_course['code'],
1078
                false,
1079
                $sessionId
1080
            );
1081
            $path = $docInfo['path'];
1082
        } else {
1083
            $docInfo = self::get_document_data_by_id(
1084
                $documentId,
1085
                $_course['code'],
1086
                false,
1087
                $sessionId
1088
            );
1089
            if (empty($docInfo)) {
1090
                return false;
1091
            }
1092
            $path = $docInfo['path'];
1093
        }
1094
1095
        $em = Database::getManager();
1096
        $documentId = (int) $documentId;
1097
1098
        if (empty($path) || empty($docInfo) || empty($documentId)) {
1099
            return false;
1100
        }
1101
1102
        /** @var CDocument $document */
1103
        $document = $em->getRepository('ChamiloCourseBundle:CDocument')->find($docInfo['iid']);
1104
        $document->setSoftDelete();
1105
        $em->persist($document);
1106
        $em->flush();
1107
1108
        return true;
1109
1110
        $itemInfo = api_get_item_property_info(
0 ignored issues
show
Unused Code introduced by
$itemInfo = api_get_item..., $sessionId, $groupId) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1111
            $_course['real_id'],
1112
            TOOL_DOCUMENT,
1113
            $documentId,
1114
            $sessionId,
1115
            $groupId
1116
        );
1117
1118
        if (empty($itemInfo)) {
1119
            return false;
1120
        }
1121
1122
        // File was already deleted.
1123
        if ($itemInfo['lastedit_type'] == 'DocumentDeleted' ||
1124
            $itemInfo['lastedit_type'] == 'delete' ||
1125
            $itemInfo['visibility'] == 2
1126
        ) {
1127
            return false;
1128
        }
1129
1130
        // Filtering by group.
1131
        if ($itemInfo['to_group_id'] != $groupId) {
1132
            return false;
1133
        }
1134
1135
        $document_exists_in_disk = file_exists($base_work_dir.$path);
1136
        $new_path = $path.'_DELETED_'.$documentId;
1137
1138
        $file_deleted_from_db = false;
1139
        $file_deleted_from_disk = false;
1140
        $file_renamed_from_disk = false;
1141
1142
        if ($documentId) {
1143
            // Deleting doc from the DB.
1144
            self::deleteDocumentFromDb($documentId, $_course, $sessionId);
1145
            // Checking
1146
            // $file_exists_in_db = self::get_document_data_by_id($documentId, $_course['code']);
1147
            $file_deleted_from_db = true;
1148
        }
1149
1150
        // Looking for children.
1151
        if ($docInfo['filetype'] == 'folder') {
1152
            $cleanPath = Database::escape_string($path);
1153
1154
            // Deleted files inside this folder.
1155
            $sql = "SELECT id FROM $TABLE_DOCUMENT
1156
                    WHERE
1157
                        c_id = $course_id AND
1158
                        session_id = $sessionId AND
1159
                        path LIKE BINARY '".$cleanPath."/%'";
1160
1161
            // Get all id's of documents that are deleted.
1162
            $result = Database::query($sql);
1163
1164
            if ($result && Database::num_rows($result) != 0) {
1165
                // Recursive delete.
1166
                while ($row = Database::fetch_array($result)) {
1167
                    self::delete_document(
1168
                        $_course,
1169
                        null,
1170
                        $base_work_dir,
1171
                        $sessionId,
1172
                        $row['id'],
1173
                        $groupId
1174
                    );
1175
                }
1176
            }
1177
        }
1178
1179
        if ($document_exists_in_disk) {
1180
            if (api_get_setting('permanently_remove_deleted_files') === 'true') {
1181
                // Delete documents, do it like this so metadata gets deleted too
1182
                my_delete($base_work_dir.$path);
1183
                // Hard delete.
1184
                self::deleteDocumentFromDb($documentId, $_course, $sessionId, true);
1185
                $file_deleted_from_disk = true;
1186
            } else {
1187
                // Set visibility to 2 and rename file/folder to xxx_DELETED_#id (soft delete)
1188
                if (is_file($base_work_dir.$path) || is_dir($base_work_dir.$path)) {
1189
                    if (rename($base_work_dir.$path, $base_work_dir.$new_path)) {
1190
                        $new_path = Database::escape_string($new_path);
1191
1192
                        $sql = "UPDATE $TABLE_DOCUMENT
1193
                                SET path = '".$new_path."'
1194
                                WHERE
1195
                                    c_id = $course_id AND
1196
                                    session_id = $sessionId AND
1197
                                    id = ".$documentId;
1198
                        Database::query($sql);
1199
1200
                        // Soft delete.
1201
                        self::deleteDocumentFromDb($documentId, $_course, $sessionId);
1202
1203
                        // Change path of sub folders and documents in database.
1204
                        $old_item_path = $docInfo['path'];
1205
                        $new_item_path = $new_path.substr($old_item_path, strlen($path));
1206
                        $new_item_path = Database::escape_string($new_item_path);
1207
1208
                        $sql = "UPDATE $TABLE_DOCUMENT
1209
                                SET path = '".$new_item_path."'
1210
                                WHERE
1211
                                    c_id = $course_id AND
1212
                                    session_id = $sessionId AND
1213
                                    id = ".$documentId;
1214
                        Database::query($sql);
1215
1216
                        $file_renamed_from_disk = true;
1217
                    } else {
1218
                        // Couldn't rename - file permissions problem?
1219
                        error_log(
1220
                            __FILE__.' '.__LINE__.': Error renaming '.$base_work_dir.$path.' to '.$base_work_dir.$new_path.'. This is probably due to file permissions',
1221
                            0
1222
                        );
1223
                    }
1224
                }
1225
            }
1226
        }
1227
        // Checking inconsistency
1228
        //error_log('Doc status: (1 del db :'.($file_deleted_from_db?'yes':'no').') - (2 del disk: '.($file_deleted_from_disk?'yes':'no').') - (3 ren disk: '.($file_renamed_from_disk?'yes':'no').')');
1229
        if ($file_deleted_from_db && $file_deleted_from_disk ||
1230
            $file_deleted_from_db && $file_renamed_from_disk
1231
        ) {
1232
            return true;
1233
        } else {
1234
            //Something went wrong
1235
            //The file or directory isn't there anymore (on the filesystem)
1236
            // This means it has been removed externally. To prevent a
1237
            // blocking error from happening, we drop the related items from the
1238
            // item_property and the document table.
1239
            error_log(
1240
                __FILE__.' '.__LINE__.': System inconsistency detected. The file or directory '.$base_work_dir.$path.' seems to have been removed from the filesystem independently from the web platform. To restore consistency, the elements using the same path will be removed from the database',
1241
                0
1242
            );
1243
1244
            return false;
1245
        }
1246
    }
1247
1248
    /**
1249
     * Removes documents from search engine database.
1250
     *
1251
     * @param string $course_id   Course code
1252
     * @param int    $document_id Document id to delete
1253
     */
1254
    public static function delete_document_from_search_engine($course_id, $document_id)
1255
    {
1256
        // remove from search engine if enabled
1257
        if (api_get_setting('search_enabled') === 'true') {
1258
            $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
1259
            $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1260
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1261
            $res = Database::query($sql);
1262
            if (Database::num_rows($res) > 0) {
1263
                $row2 = Database::fetch_array($res);
1264
                $di = new ChamiloIndexer();
1265
                $di->remove_document($row2['search_did']);
1266
            }
1267
            $sql = 'DELETE FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
1268
            $sql = sprintf($sql, $tbl_se_ref, $course_id, TOOL_DOCUMENT, $document_id);
1269
            Database::query($sql);
1270
1271
            // remove terms from db
1272
            require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1273
            delete_all_values_for_item($course_id, TOOL_DOCUMENT, $document_id);
1274
        }
1275
    }
1276
1277
    /**
1278
     * Gets the id of a document with a given path.
1279
     *
1280
     * @param array  $courseInfo
1281
     * @param string $path
1282
     * @param int    $sessionId
1283
     *
1284
     * @return int id of document / false if no doc found
1285
     */
1286
    public static function get_document_id($courseInfo, $path, $sessionId = 0)
1287
    {
1288
        $table = Database::get_course_table(TABLE_DOCUMENT);
1289
        $courseId = $courseInfo['real_id'];
1290
1291
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
1292
        $sessionCondition = api_get_session_condition($sessionId, true);
1293
1294
        $path = Database::escape_string($path);
1295
        if (!empty($courseId) && !empty($path)) {
1296
            $sql = "SELECT id FROM $table
1297
                    WHERE
1298
                        c_id = $courseId AND
1299
                        path LIKE BINARY '$path'
1300
                        $sessionCondition
1301
                    LIMIT 1";
1302
1303
            $result = Database::query($sql);
1304
            if (Database::num_rows($result)) {
1305
                $row = Database::fetch_array($result);
1306
1307
                return (int) $row['id'];
1308
            }
1309
        }
1310
1311
        return false;
1312
    }
1313
1314
    /**
1315
     * Gets the document data with a given id.
1316
     *
1317
     * @param int    $id            Document Id (id field in c_document table)
1318
     * @param string $course_code   Course code
1319
     * @param bool   $load_parents  load folder parents
1320
     * @param int    $session_id    The session ID,
1321
     *                              0 if requires context *out of* session, and null to use global context
1322
     * @param bool   $ignoreDeleted
1323
     *
1324
     * @return array document content
1325
     */
1326
    public static function get_document_data_by_id(
1327
        $id,
1328
        $course_code,
1329
        $load_parents = false,
1330
        $session_id = null,
1331
        $ignoreDeleted = false
1332
    ) {
1333
        $course_info = api_get_course_info($course_code);
1334
        $course_id = $course_info['real_id'];
1335
1336
        if (empty($course_info)) {
1337
            return false;
1338
        }
1339
1340
        $session_id = empty($session_id) ? api_get_session_id() : (int) $session_id;
1341
        $www = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/document';
1342
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
1343
        $id = (int) $id;
1344
        $sessionCondition = api_get_session_condition($session_id, true, true);
1345
1346
        $sql = "SELECT * FROM $TABLE_DOCUMENT
1347
                WHERE c_id = $course_id $sessionCondition AND id = $id";
1348
1349
        if ($ignoreDeleted) {
1350
            $sql .= " AND path NOT LIKE '%_DELETED_%' ";
1351
        }
1352
1353
        $result = Database::query($sql);
1354
        if ($result && Database::num_rows($result) == 1) {
1355
            $row = Database::fetch_array($result, 'ASSOC');
1356
            //@todo need to clarify the name of the URLs not nice right now
1357
            $url_path = urlencode($row['path']);
1358
            $path = str_replace('%2F', '/', $url_path);
1359
            $pathinfo = pathinfo($row['path']);
1360
            $row['url'] = api_get_path(WEB_CODE_PATH).'document/showinframes.php?cidReq='.$course_code.'&id='.$id;
1361
            $row['document_url'] = api_get_path(WEB_CODE_PATH).'document/document.php?cidReq='.$course_code.'&id='.$id;
1362
            $row['absolute_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$row['path'];
1363
            $row['absolute_path_from_document'] = '/document'.$row['path'];
1364
            $row['absolute_parent_path'] = api_get_path(SYS_COURSE_PATH).$course_info['path'].'/document'.$pathinfo['dirname'].'/';
1365
            $row['direct_url'] = $www.$path;
1366
            $row['basename'] = basename($row['path']);
1367
1368
            if (dirname($row['path']) == '.') {
1369
                $row['parent_id'] = '0';
1370
            } else {
1371
                $row['parent_id'] = self::get_document_id($course_info, dirname($row['path']), $session_id);
1372
            }
1373
            $parents = [];
1374
1375
            //Use to generate parents (needed for the breadcrumb)
1376
            //@todo sorry but this for is here because there's not a parent_id in the document table so we parsed the path!!
1377
            if ($load_parents) {
1378
                $dir_array = explode('/', $row['path']);
1379
                $dir_array = array_filter($dir_array);
1380
                $array_len = count($dir_array) + 1;
1381
                $real_dir = '';
1382
1383
                for ($i = 1; $i < $array_len; $i++) {
1384
                    $real_dir .= '/'.(isset($dir_array[$i]) ? $dir_array[$i] : '');
1385
                    $parent_id = self::get_document_id($course_info, $real_dir);
1386
                    if ($session_id != 0 && empty($parent_id)) {
1387
                        $parent_id = self::get_document_id($course_info, $real_dir, 0);
1388
                    }
1389
                    if (!empty($parent_id)) {
1390
                        $sub_document_data = self::get_document_data_by_id(
1391
                            $parent_id,
1392
                            $course_code,
1393
                            false,
1394
                            $session_id
1395
                        );
1396
                        if ($session_id != 0 and !$sub_document_data) {
1397
                            $sub_document_data = self::get_document_data_by_id(
1398
                                $parent_id,
1399
                                $course_code,
1400
                                false,
1401
                                0
1402
                            );
1403
                        }
1404
                        //@todo add visibility here
1405
                        $parents[] = $sub_document_data;
1406
                    }
1407
                }
1408
            }
1409
            $row['parents'] = $parents;
1410
1411
            return $row;
1412
        }
1413
1414
        return false;
1415
    }
1416
1417
    /**
1418
     * Allow to set a specific document as a new template for CKeditor
1419
     * for a particular user in a particular course.
1420
     *
1421
     * @param string $title
1422
     * @param string $description
1423
     * @param int    $document_id_for_template the document id
1424
     * @param int    $courseId
1425
     * @param int    $user_id
1426
     * @param string $image
1427
     *
1428
     * @return bool
1429
     */
1430
    public static function setDocumentAsTemplate(
1431
        $title,
1432
        $description,
1433
        $document_id_for_template,
1434
        $courseId,
1435
        $user_id,
1436
        $image
1437
    ) {
1438
        // Database table definition
1439
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1440
        $params = [
1441
            'title' => $title,
1442
            'description' => $description,
1443
            'c_id' => $courseId,
1444
            'user_id' => $user_id,
1445
            'ref_doc' => $document_id_for_template,
1446
            'image' => $image,
1447
        ];
1448
        Database::insert($table_template, $params);
1449
1450
        return true;
1451
    }
1452
1453
    /**
1454
     * Unset a document as template.
1455
     *
1456
     * @param int $document_id
1457
     * @param int $courseId
1458
     * @param int $user_id
1459
     */
1460
    public static function unsetDocumentAsTemplate(
1461
        $document_id,
1462
        $courseId,
1463
        $user_id
1464
    ) {
1465
        $table_template = Database::get_main_table(TABLE_MAIN_TEMPLATES);
1466
        $courseId = (int) $courseId;
1467
        $user_id = (int) $user_id;
1468
        $document_id = (int) $document_id;
1469
1470
        $sql = 'SELECT id FROM '.$table_template.'
1471
                WHERE
1472
                    c_id = "'.$courseId.'" AND
1473
                    user_id = "'.$user_id.'" AND
1474
                    ref_doc = "'.$document_id.'"';
1475
        $result = Database::query($sql);
1476
        $template_id = Database::result($result, 0, 0);
1477
1478
        my_delete(api_get_path(SYS_CODE_PATH).'upload/template_thumbnails/'.$template_id.'.jpg');
1479
1480
        $sql = 'DELETE FROM '.$table_template.'
1481
                WHERE
1482
                    c_id ="'.$courseId.'" AND
1483
                    user_id="'.$user_id.'" AND
1484
                    ref_doc="'.$document_id.'"';
1485
1486
        Database::query($sql);
1487
    }
1488
1489
    /**
1490
     * Return true if the documentpath have visibility=1 as
1491
     * item_property (you should use the is_visible_by_id).
1492
     *
1493
     * @param string $doc_path the relative complete path of the document
1494
     * @param array  $course   the _course array info of the document's course
1495
     * @param int
1496
     * @param string
1497
     *
1498
     * @return bool
1499
     */
1500
    public static function is_visible(
1501
        $doc_path,
1502
        $course,
1503
        $session_id = 0,
1504
        $file_type = 'file'
1505
    ) {
1506
        $docTable = Database::get_course_table(TABLE_DOCUMENT);
1507
        $propTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
1508
1509
        $course_id = $course['real_id'];
1510
        // note the extra / at the end of doc_path to match every path in
1511
        // the document table that is part of the document path
1512
1513
        $session_id = intval($session_id);
1514
        $condition = "AND d.session_id IN  ('$session_id', '0') ";
1515
        // The " d.filetype='file' " let the user see a file even if the folder is hidden see #2198
1516
1517
        /*
1518
          When using hotpotatoes files, a new html files are generated
1519
          in the hotpotatoes folder to display the test.
1520
          The genuine html file is copied to math4.htm(user_id).t.html
1521
          Images files are not copied, and keep same name.
1522
          To check the html file visibility, we don't have to check file math4.htm(user_id).t.html but file math4.htm
1523
          In this case, we have to remove (user_id).t.html to check the visibility of the file
1524
          For images, we just check the path of the image file.
1525
1526
          Exemple of hotpotatoes folder :
1527
          A.jpg
1528
          maths4-consigne.jpg
1529
          maths4.htm
1530
          maths4.htm1.t.html
1531
          maths4.htm52.t.html
1532
          maths4.htm654.t.html
1533
          omega.jpg
1534
          theta.jpg
1535
         */
1536
1537
        if (strpos($doc_path, 'HotPotatoes_files') && preg_match("/\.t\.html$/", $doc_path)) {
1538
            $doc_path = substr($doc_path, 0, strlen($doc_path) - 7 - strlen(api_get_user_id()));
1539
        }
1540
1541
        if (!in_array($file_type, ['file', 'folder'])) {
1542
            $file_type = 'file';
1543
        }
1544
        $doc_path = Database::escape_string($doc_path).'/';
1545
1546
        $sql = "SELECT visibility
1547
                FROM $docTable d
1548
                INNER JOIN $propTable ip
1549
                ON (d.id = ip.ref AND d.c_id = ip.c_id)
1550
        		WHERE
1551
        		    d.c_id  = $course_id AND 
1552
        		    ip.c_id = $course_id AND
1553
        		    ip.tool = '".TOOL_DOCUMENT."' $condition AND
1554
        			filetype = '$file_type' AND
1555
        			locate(concat(path,'/'), '$doc_path')=1
1556
                ";
1557
1558
        $result = Database::query($sql);
1559
        $is_visible = false;
1560
        if (Database::num_rows($result) > 0) {
1561
            $row = Database::fetch_array($result, 'ASSOC');
1562
            if ($row['visibility'] == 1) {
1563
                $is_visible = api_is_allowed_in_course() || api_is_platform_admin();
1564
            }
1565
        }
1566
1567
        /* improved protection of documents viewable directly through the url:
1568
            incorporates the same protections of the course at the url of
1569
            documents:
1570
            access allowed for the whole world Open, access allowed for
1571
            users registered on the platform Private access, document accessible
1572
            only to course members (see the Users list), Completely closed;
1573
            the document is only accessible to the course admin and
1574
            teaching assistants.*/
1575
        //return $_SESSION ['is_allowed_in_course'] || api_is_platform_admin();
1576
        return $is_visible;
1577
    }
1578
1579
    /**
1580
     * Return true if user can see a file.
1581
     *
1582
     * @param   int     document id
1583
     * @param   array   course info
1584
     * @param   int
1585
     * @param   int
1586
     * @param bool
1587
     *
1588
     * @return bool
1589
     */
1590
    public static function is_visible_by_id(
1591
        $doc_id,
1592
        $course_info,
1593
        $session_id,
1594
        $user_id,
1595
        $admins_can_see_everything = true,
1596
        $userIsSubscribed = null
1597
    ) {
1598
        $user_in_course = false;
1599
1600
        //1. Checking the course array
1601
        if (empty($course_info)) {
1602
            $course_info = api_get_course_info();
1603
            if (empty($course_info)) {
1604
                return false;
1605
            }
1606
        }
1607
1608
        $doc_id = (int) $doc_id;
1609
        $session_id = (int) $session_id;
1610
        // 2. Course and Session visibility are handle in local.inc.php/global.inc.php
1611
        // 3. Checking if user exist in course/session
1612
        if ($session_id == 0) {
1613
            if (is_null($userIsSubscribed)) {
1614
                $userIsSubscribed = CourseManager::is_user_subscribed_in_course(
1615
                    $user_id,
1616
                    $course_info['code']
1617
                );
1618
            }
1619
1620
            if ($userIsSubscribed === true || api_is_platform_admin()) {
1621
                $user_in_course = true;
1622
            }
1623
1624
            // Check if course is open then we can consider that the student is registered to the course
1625
            if (isset($course_info) &&
1626
                in_array(
1627
                    $course_info['visibility'],
1628
                    [COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD]
1629
                )
1630
            ) {
1631
                $user_in_course = true;
1632
            }
1633
        } else {
1634
            $user_status = SessionManager::get_user_status_in_course_session(
1635
                $user_id,
1636
                $course_info['real_id'],
1637
                $session_id
1638
            );
1639
1640
            if (in_array($user_status, ['0', '2', '6'])) {
1641
                //is true if is an student, course session teacher or coach
1642
                $user_in_course = true;
1643
            }
1644
1645
            if (api_is_platform_admin()) {
1646
                $user_in_course = true;
1647
            }
1648
        }
1649
1650
        $em = Database::getManager();
1651
1652
        // 4. Checking document visibility (i'm repeating the code in order to be more clear when reading ) - jm
1653
        if ($user_in_course) {
1654
            $repo = $em->getRepository('ChamiloCourseBundle:CDocument');
1655
            /** @var \Chamilo\CourseBundle\Entity\CDocument $document */
1656
            $document = $repo->find($doc_id);
1657
            $link = $document->getCourseSessionResourceLink();
1658
1659
            if ($link && $link->getVisibility() == ResourceLink::VISIBILITY_PUBLISHED) {
1660
                return true;
1661
            }
1662
1663
            return false;
1664
1665
            // 4.1 Checking document visibility for a Course
1666
            if ($session_id == 0) {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
1667
                $link = $document->getCourseSessionResourceLink();
1668
1669
                if ($link && $link->getVisibility() == ResourceLink::VISIBILITY_PUBLISHED) {
1670
                    return true;
1671
                }
1672
1673
                return false;
1674
1675
                $item_info = api_get_item_property_info(
1676
                    $course_info['real_id'],
1677
                    'document',
1678
                    $doc_id,
1679
                    0
1680
                );
1681
1682
                if (isset($item_info['visibility'])) {
1683
                    // True for admins if document exists
1684
                    if ($admins_can_see_everything && api_is_platform_admin()) {
1685
                        return true;
1686
                    }
1687
                    if ($item_info['visibility'] == 1) {
1688
                        return true;
1689
                    }
1690
                }
1691
            } else {
1692
                // 4.2 Checking document visibility for a Course in a Session
1693
                $item_info = api_get_item_property_info(
1694
                    $course_info['real_id'],
1695
                    'document',
1696
                    $doc_id,
1697
                    0
1698
                );
1699
1700
                $item_info_in_session = api_get_item_property_info(
1701
                    $course_info['real_id'],
1702
                    'document',
1703
                    $doc_id,
1704
                    $session_id
1705
                );
1706
1707
                // True for admins if document exists
1708
                if (isset($item_info['visibility'])) {
1709
                    if ($admins_can_see_everything && api_is_platform_admin()) {
1710
                        return true;
1711
                    }
1712
                }
1713
1714
                if (isset($item_info_in_session['visibility'])) {
1715
                    if ($item_info_in_session['visibility'] == 1) {
1716
                        return true;
1717
                    }
1718
                } else {
1719
                    if ($item_info['visibility'] == 1) {
1720
                        return true;
1721
                    }
1722
                }
1723
            }
1724
        } elseif ($admins_can_see_everything && api_is_platform_admin()) {
1725
            return true;
1726
        }
1727
1728
        return false;
1729
    }
1730
1731
    /**
1732
     * Allow attach a certificate to a course.
1733
     *
1734
     * @todo move to certificate.lib.php
1735
     *
1736
     * @param int $courseId
1737
     * @param int $document_id
1738
     * @param int $session_id
1739
     */
1740
    public static function attach_gradebook_certificate($courseId, $document_id, $session_id = 0)
1741
    {
1742
        $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1743
        $session_id = intval($session_id);
1744
        $courseId = (int) $courseId;
1745
        if (empty($session_id)) {
1746
            $session_id = api_get_session_id();
1747
        }
1748
1749
        if (empty($session_id)) {
1750
            $sql_session = 'AND (session_id = 0 OR isnull(session_id)) ';
1751
        } elseif ($session_id > 0) {
1752
            $sql_session = 'AND session_id='.$session_id;
1753
        } else {
1754
            $sql_session = '';
1755
        }
1756
        $sql = 'UPDATE '.$tbl_category.' SET document_id="'.intval($document_id).'"
1757
                WHERE c_id ="'.$courseId.'" '.$sql_session;
1758
        Database::query($sql);
1759
    }
1760
1761
    /**
1762
     * get the document id of default certificate.
1763
     *
1764
     * @todo move to certificate.lib.php
1765
     *
1766
     * @param int $courseId
1767
     * @param int $session_id
1768
     *
1769
     * @return int The default certificate id
1770
     */
1771
    public static function get_default_certificate_id($courseId, $session_id = 0)
1772
    {
1773
        $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
1774
        $session_id = (int) $session_id;
1775
        $courseId = (int) $courseId;
1776
        if (empty($session_id)) {
1777
            $session_id = api_get_session_id();
1778
        }
1779
1780
        if (empty($session_id)) {
1781
            $sql_session = 'AND (session_id = 0 OR isnull(session_id)) ';
1782
        } elseif ($session_id > 0) {
1783
            $sql_session = 'AND session_id='.$session_id;
1784
        } else {
1785
            $sql_session = '';
1786
        }
1787
1788
        $sql = 'SELECT document_id FROM '.$tbl_category.'
1789
                WHERE c_id ="'.$courseId.'" '.$sql_session;
1790
1791
        $rs = Database::query($sql);
1792
        $num = Database::num_rows($rs);
1793
        if ($num == 0) {
1794
            return null;
1795
        }
1796
        $row = Database::fetch_array($rs);
1797
1798
        return $row['document_id'];
1799
    }
1800
1801
    /**
1802
     * Allow replace user info in file html.
1803
     *
1804
     * @param int   $user_id
1805
     * @param array $courseInfo
1806
     * @param int   $sessionId
1807
     * @param bool  $is_preview
1808
     *
1809
     * @return array
1810
     */
1811
    public static function replace_user_info_into_html(
1812
        $user_id,
1813
        $courseInfo,
1814
        $sessionId,
1815
        $is_preview = false
1816
    ) {
1817
        $user_id = intval($user_id);
1818
        $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
1819
        $course_id = $courseInfo['real_id'];
1820
1821
        $document_id = self::get_default_certificate_id(
1822
            $course_id,
1823
            $sessionId
1824
        );
1825
1826
        $my_content_html = null;
1827
        if ($document_id) {
1828
            $sql = "SELECT path FROM $tbl_document
1829
                    WHERE c_id = $course_id AND id = $document_id";
1830
            $rs = Database::query($sql);
1831
            $new_content = '';
1832
            $all_user_info = [];
1833
            if (Database::num_rows($rs)) {
1834
                $row = Database::fetch_array($rs);
1835
                $filepath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document'.$row['path'];
1836
                if (is_file($filepath)) {
1837
                    $my_content_html = file_get_contents($filepath);
1838
                }
1839
                $all_user_info = self::get_all_info_to_certificate(
1840
                    $user_id,
1841
                    $courseInfo,
1842
                    $is_preview
1843
                );
1844
1845
                $info_to_be_replaced_in_content_html = $all_user_info[0];
1846
                $info_to_replace_in_content_html = $all_user_info[1];
1847
                $new_content = str_replace(
1848
                    $info_to_be_replaced_in_content_html,
1849
                    $info_to_replace_in_content_html,
1850
                    $my_content_html
1851
                );
1852
            }
1853
1854
            return [
1855
                'content' => $new_content,
1856
                'variables' => $all_user_info,
1857
            ];
1858
        }
1859
1860
        return [];
1861
    }
1862
1863
    /**
1864
     * Return all content to replace and all content to be replace.
1865
     *
1866
     * @param int  $user_id
1867
     * @param int  $course_id
1868
     * @param bool $is_preview
1869
     *
1870
     * @return array
1871
     */
1872
    public static function get_all_info_to_certificate($user_id, $course_id, $is_preview = false)
1873
    {
1874
        $info_list = [];
1875
        $user_id = intval($user_id);
1876
        $course_info = api_get_course_info($course_id);
1877
1878
        // Portal info
1879
        $organization_name = api_get_setting('Institution');
1880
        $portal_name = api_get_setting('siteName');
1881
1882
        // Extra user data information
1883
        $extra_user_info_data = UserManager::get_extra_user_data(
1884
            $user_id,
1885
            false,
1886
            false,
1887
            false,
1888
            true
1889
        );
1890
1891
        // get extra fields
1892
        $extraField = new ExtraField('user');
1893
        $extraFields = $extraField->get_all(['filter = ? AND visible_to_self = ?' => [1, 1]]);
1894
1895
        // Student information
1896
        $user_info = api_get_user_info($user_id);
1897
        $first_name = $user_info['firstname'];
1898
        $last_name = $user_info['lastname'];
1899
        $username = $user_info['username'];
1900
        $official_code = $user_info['official_code'];
1901
1902
        // Teacher information
1903
        $info_teacher_id = UserManager::get_user_id_of_course_admin_or_session_admin($course_info);
1904
        $teacher_info = api_get_user_info($info_teacher_id);
1905
        $teacher_first_name = $teacher_info['firstname'];
1906
        $teacher_last_name = $teacher_info['lastname'];
1907
1908
        // info gradebook certificate
1909
        $info_grade_certificate = UserManager::get_info_gradebook_certificate($course_id, $user_id);
1910
        $date_certificate = $info_grade_certificate['created_at'];
1911
        $date_long_certificate = '';
1912
1913
        $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
1914
        if (!empty($date_certificate)) {
1915
            $date_long_certificate = api_convert_and_format_date($date_certificate);
1916
            $date_no_time = api_convert_and_format_date($date_certificate, DATE_FORMAT_LONG_NO_DAY);
1917
        }
1918
1919
        if ($is_preview) {
1920
            $date_long_certificate = api_convert_and_format_date(api_get_utc_datetime());
1921
            $date_no_time = api_convert_and_format_date(api_get_utc_datetime(), DATE_FORMAT_LONG_NO_DAY);
1922
        }
1923
1924
        $url = api_get_path(WEB_PATH).'certificates/index.php?id='.$info_grade_certificate['id'];
1925
        $externalStyleFile = api_get_path(SYS_CSS_PATH).'themes/'.api_get_visual_theme().'/certificate.css';
1926
        $externalStyle = '';
1927
        if (is_file($externalStyleFile)) {
1928
            $externalStyle = file_get_contents($externalStyleFile);
1929
        }
1930
1931
        // Replace content
1932
        $info_to_replace_in_content_html = [
1933
            $first_name,
1934
            $last_name,
1935
            $username,
1936
            $organization_name,
1937
            $portal_name,
1938
            $teacher_first_name,
1939
            $teacher_last_name,
1940
            $official_code,
1941
            $date_long_certificate,
1942
            $date_no_time,
1943
            $course_id,
1944
            $course_info['name'],
1945
            $info_grade_certificate['grade'],
1946
            $url,
1947
            '<a href="'.$url.'" target="_blank">'.get_lang('CertificateOnlineLink').'</a>',
1948
            '((certificate_barcode))',
1949
            $externalStyle,
1950
        ];
1951
1952
        $tags = [
1953
            '((user_firstname))',
1954
            '((user_lastname))',
1955
            '((user_username))',
1956
            '((gradebook_institution))',
1957
            '((gradebook_sitename))',
1958
            '((teacher_firstname))',
1959
            '((teacher_lastname))',
1960
            '((official_code))',
1961
            '((date_certificate))',
1962
            '((date_certificate_no_time))',
1963
            '((course_code))',
1964
            '((course_title))',
1965
            '((gradebook_grade))',
1966
            '((certificate_link))',
1967
            '((certificate_link_html))',
1968
            '((certificate_barcode))',
1969
            '((external_style))',
1970
        ];
1971
1972
        if (!empty($extraFields)) {
1973
            foreach ($extraFields as $extraField) {
1974
                $valueExtra = isset($extra_user_info_data[$extraField['variable']]) ? $extra_user_info_data[$extraField['variable']] : '';
1975
                $tags[] = '(('.strtolower($extraField['variable']).'))';
1976
                $info_to_replace_in_content_html[] = $valueExtra;
1977
            }
1978
        }
1979
1980
        $info_list[] = $tags;
1981
        $info_list[] = $info_to_replace_in_content_html;
1982
1983
        return $info_list;
1984
    }
1985
1986
    /**
1987
     * Remove default certificate.
1988
     *
1989
     * @param int $course_id              The course code
1990
     * @param int $default_certificate_id The document id of the default certificate
1991
     */
1992
    public static function remove_attach_certificate($course_id, $default_certificate_id)
1993
    {
1994
        if (empty($default_certificate_id)) {
1995
            return false;
1996
        }
1997
1998
        $default_certificate = self::get_default_certificate_id($course_id);
1999
        if ((int) $default_certificate == (int) $default_certificate_id) {
2000
            $tbl_category = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY);
2001
            $session_id = api_get_session_id();
2002
            if ($session_id == 0 || is_null($session_id)) {
2003
                $sql_session = 'AND (session_id='.intval($session_id).' OR isnull(session_id)) ';
2004
            } elseif ($session_id > 0) {
2005
                $sql_session = 'AND session_id='.intval($session_id);
2006
            } else {
2007
                $sql_session = '';
2008
            }
2009
2010
            $sql = 'UPDATE '.$tbl_category.' SET document_id = null
2011
                    WHERE
2012
                        c_id = "'.Database::escape_string($course_id).'" AND
2013
                        document_id="'.$default_certificate_id.'" '.$sql_session;
2014
            Database::query($sql);
2015
        }
2016
    }
2017
2018
    /**
2019
     * Create directory certificate.
2020
     *
2021
     * @param array $courseInfo
2022
     */
2023
    public static function create_directory_certificate_in_course($courseInfo)
2024
    {
2025
        if (!empty($courseInfo)) {
2026
            $to_group_id = 0;
2027
            $to_user_id = null;
2028
            $course_dir = $courseInfo['path']."/document/";
2029
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
2030
            $base_work_dir = $sys_course_path.$course_dir;
2031
            $dir_name = '/certificates';
2032
            $post_dir_name = get_lang('CertificatesFiles');
2033
            $visibility_command = 'invisible';
2034
2035
            $id = self::get_document_id_of_directory_certificate();
2036
2037
            if (empty($id)) {
2038
                create_unexisting_directory(
2039
                    $courseInfo,
2040
                    api_get_user_id(),
2041
                    api_get_session_id(),
2042
                    $to_group_id,
2043
                    $to_user_id,
2044
                    $base_work_dir,
2045
                    $dir_name,
2046
                    $post_dir_name,
2047
                    null,
2048
                    false,
2049
                    false
2050
                );
2051
2052
                $id = self::get_document_id_of_directory_certificate();
2053
2054
                if (empty($id)) {
2055
                    self::addDocument(
2056
                        $courseInfo,
2057
                        $dir_name,
2058
                        'folder',
2059
                        0,
2060
                        $post_dir_name,
2061
                        null,
2062
                        0,
2063
                        true,
2064
                        $to_group_id,
2065
                        0,
2066
                        0,
2067
                        false
2068
                    );
2069
                }
2070
            }
2071
        }
2072
    }
2073
2074
    /**
2075
     * Get the document id of the directory certificate.
2076
     *
2077
     * @return int The document id of the directory certificate
2078
     *
2079
     * @todo move to certificate.lib.php
2080
     */
2081
    public static function get_document_id_of_directory_certificate()
2082
    {
2083
        $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
2084
        $course_id = api_get_course_int_id();
2085
        $sql = "SELECT id FROM $tbl_document 
2086
                WHERE c_id = $course_id AND path='/certificates' ";
2087
        $rs = Database::query($sql);
2088
        $row = Database::fetch_array($rs);
2089
2090
        return $row['id'];
2091
    }
2092
2093
    /**
2094
     * Check if a directory given is for certificate.
2095
     *
2096
     * @todo move to certificate.lib.php
2097
     *
2098
     * @param string $dir path of directory
2099
     *
2100
     * @return bool true if is a certificate or false otherwise
2101
     */
2102
    public static function is_certificate_mode($dir)
2103
    {
2104
        // I'm in the certification module?
2105
        $is_certificate_mode = false;
2106
        $is_certificate_array = explode('/', $dir);
2107
        array_shift($is_certificate_array);
2108
        if (isset($is_certificate_array[0]) && $is_certificate_array[0] == 'certificates') {
2109
            $is_certificate_mode = true;
2110
        }
2111
2112
        return $is_certificate_mode || (isset($_GET['certificate']) && $_GET['certificate'] === 'true');
2113
    }
2114
2115
    /**
2116
     * Gets the list of included resources as a list of absolute or relative paths from a html file or string html
2117
     * This allows for a better SCORM export or replace urls inside content html from copy course
2118
     * The list will generally include pictures, flash objects, java applets, or any other
2119
     * stuff included in the source of the current item. The current item is expected
2120
     * to be an HTML file or string html. If it is not, then the function will return and empty list.
2121
     *
2122
     * @param    string  source html (content or path)
2123
     * @param    bool    is file or string html
2124
     * @param    string    type (one of the app tools) - optional (otherwise takes the current item's type)
2125
     * @param    int        level of recursivity we're in
2126
     *
2127
     * @return array List of file paths. An additional field containing 'local' or 'remote' helps determine
2128
     *               if the file should be copied into the zip or just linked
2129
     */
2130
    public static function get_resources_from_source_html(
2131
        $source_html,
2132
        $is_file = false,
2133
        $type = null,
2134
        $recursivity = 1
2135
    ) {
2136
        $max = 5;
2137
        $attributes = [];
2138
        $wanted_attributes = [
2139
            'src',
2140
            'url',
2141
            '@import',
2142
            'href',
2143
            'value',
2144
            'flashvars',
2145
            'poster',
2146
        ];
2147
        $explode_attributes = ['flashvars' => 'file'];
2148
        $abs_path = '';
2149
2150
        if ($recursivity > $max) {
2151
            return [];
2152
        }
2153
2154
        if (!isset($type)) {
2155
            $type = TOOL_DOCUMENT;
2156
        }
2157
2158
        if (!$is_file) {
2159
            $attributes = self::parse_HTML_attributes(
2160
                $source_html,
2161
                $wanted_attributes,
2162
                $explode_attributes
2163
            );
2164
        } else {
2165
            if (is_file($source_html)) {
2166
                $abs_path = $source_html;
2167
                //for now, read the whole file in one go (that's gonna be a problem when the file is too big)
2168
                $info = pathinfo($abs_path);
2169
                $ext = $info['extension'];
2170
                switch (strtolower($ext)) {
2171
                    case 'html':
2172
                    case 'htm':
2173
                    case 'shtml':
2174
                    case 'css':
2175
                        $file_content = file_get_contents($abs_path);
2176
                        // get an array of attributes from the HTML source
2177
                        $attributes = self::parse_HTML_attributes(
2178
                            $file_content,
2179
                            $wanted_attributes,
2180
                            $explode_attributes
2181
                        );
2182
                        break;
2183
                    default:
2184
                        break;
2185
                }
2186
            } else {
2187
                return false;
2188
            }
2189
        }
2190
2191
        $files_list = [];
2192
        switch ($type) {
2193
            case TOOL_DOCUMENT:
2194
            case TOOL_QUIZ:
2195
            case 'sco':
2196
                foreach ($wanted_attributes as $attr) {
2197
                    if (isset($attributes[$attr])) {
2198
                        //find which kind of path these are (local or remote)
2199
                        $sources = $attributes[$attr];
2200
                        foreach ($sources as $source) {
2201
                            //skip what is obviously not a resource
2202
                            if (strpos($source, '+this.')) {
2203
                                continue; //javascript code - will still work unaltered
2204
                            }
2205
                            if (strpos($source, '.') === false) {
2206
                                continue; //no dot, should not be an external file anyway
2207
                            }
2208
                            if (strpos($source, 'mailto:')) {
2209
                                continue; //mailto link
2210
                            }
2211
                            if (strpos($source, ';') && !strpos($source, '&amp;')) {
2212
                                continue; //avoid code - that should help
2213
                            }
2214
2215
                            if ($attr == 'value') {
2216
                                if (strpos($source, 'mp3file')) {
2217
                                    $files_list[] = [
2218
                                        substr($source, 0, strpos($source, '.swf') + 4),
2219
                                        'local',
2220
                                        'abs',
2221
                                    ];
2222
                                    $mp3file = substr($source, strpos($source, 'mp3file=') + 8);
2223
                                    if (substr($mp3file, 0, 1) == '/') {
2224
                                        $files_list[] = [$mp3file, 'local', 'abs'];
2225
                                    } else {
2226
                                        $files_list[] = [$mp3file, 'local', 'rel'];
2227
                                    }
2228
                                } elseif (strpos($source, 'flv=') === 0) {
2229
                                    $source = substr($source, 4);
2230
                                    if (strpos($source, '&') > 0) {
2231
                                        $source = substr($source, 0, strpos($source, '&'));
2232
                                    }
2233
                                    if (strpos($source, '://') > 0) {
2234
                                        if (strpos($source, api_get_path(WEB_PATH)) !== false) {
2235
                                            //we found the current portal url
2236
                                            $files_list[] = [$source, 'local', 'url'];
2237
                                        } else {
2238
                                            //we didn't find any trace of current portal
2239
                                            $files_list[] = [$source, 'remote', 'url'];
2240
                                        }
2241
                                    } else {
2242
                                        $files_list[] = [$source, 'local', 'abs'];
2243
                                    }
2244
                                    /* skipping anything else to avoid two entries
2245
                                    (while the others can have sub-files in their url, flv's can't)*/
2246
                                    continue;
2247
                                }
2248
                            }
2249
                            if (strpos($source, '://') > 0) {
2250
                                //cut at '?' in a URL with params
2251
                                if (strpos($source, '?') > 0) {
2252
                                    $second_part = substr($source, strpos($source, '?'));
2253
                                    if (strpos($second_part, '://') > 0) {
2254
                                        //if the second part of the url contains a url too, treat the second one before cutting
2255
                                        $pos1 = strpos($second_part, '=');
2256
                                        $pos2 = strpos($second_part, '&');
2257
                                        $second_part = substr($second_part, $pos1 + 1, $pos2 - ($pos1 + 1));
2258
                                        if (strpos($second_part, api_get_path(WEB_PATH)) !== false) {
2259
                                            //we found the current portal url
2260
                                            $files_list[] = [$second_part, 'local', 'url'];
2261
                                            $in_files_list[] = self::get_resources_from_source_html(
2262
                                                $second_part,
2263
                                                true,
2264
                                                TOOL_DOCUMENT,
2265
                                                $recursivity + 1
2266
                                            );
2267
                                            if (count($in_files_list) > 0) {
2268
                                                $files_list = array_merge($files_list, $in_files_list);
2269
                                            }
2270
                                        } else {
2271
                                            //we didn't find any trace of current portal
2272
                                            $files_list[] = [$second_part, 'remote', 'url'];
2273
                                        }
2274
                                    } elseif (strpos($second_part, '=') > 0) {
2275
                                        if (substr($second_part, 0, 1) === '/') {
2276
                                            //link starts with a /, making it absolute (relative to DocumentRoot)
2277
                                            $files_list[] = [$second_part, 'local', 'abs'];
2278
                                            $in_files_list[] = self::get_resources_from_source_html(
2279
                                                $second_part,
2280
                                                true,
2281
                                                TOOL_DOCUMENT,
2282
                                                $recursivity + 1
2283
                                            );
2284
                                            if (count($in_files_list) > 0) {
2285
                                                $files_list = array_merge($files_list, $in_files_list);
2286
                                            }
2287
                                        } elseif (strstr($second_part, '..') === 0) {
2288
                                            //link is relative but going back in the hierarchy
2289
                                            $files_list[] = [$second_part, 'local', 'rel'];
2290
                                            //$dir = api_get_path(SYS_CODE_PATH);//dirname($abs_path);
2291
                                            //$new_abs_path = realpath($dir.'/'.$second_part);
2292
                                            $dir = '';
2293
                                            if (!empty($abs_path)) {
2294
                                                $dir = dirname($abs_path).'/';
2295
                                            }
2296
                                            $new_abs_path = realpath($dir.$second_part);
2297
                                            $in_files_list[] = self::get_resources_from_source_html(
2298
                                                $new_abs_path,
2299
                                                true,
2300
                                                TOOL_DOCUMENT,
2301
                                                $recursivity + 1
2302
                                            );
2303
                                            if (count($in_files_list) > 0) {
2304
                                                $files_list = array_merge($files_list, $in_files_list);
2305
                                            }
2306
                                        } else {
2307
                                            //no starting '/', making it relative to current document's path
2308
                                            if (substr($second_part, 0, 2) == './') {
2309
                                                $second_part = substr($second_part, 2);
2310
                                            }
2311
                                            $files_list[] = [$second_part, 'local', 'rel'];
2312
                                            $dir = '';
2313
                                            if (!empty($abs_path)) {
2314
                                                $dir = dirname($abs_path).'/';
2315
                                            }
2316
                                            $new_abs_path = realpath($dir.$second_part);
2317
                                            $in_files_list[] = self::get_resources_from_source_html(
2318
                                                $new_abs_path,
2319
                                                true,
2320
                                                TOOL_DOCUMENT,
2321
                                                $recursivity + 1
2322
                                            );
2323
                                            if (count($in_files_list) > 0) {
2324
                                                $files_list = array_merge($files_list, $in_files_list);
2325
                                            }
2326
                                        }
2327
                                    }
2328
                                    //leave that second part behind now
2329
                                    $source = substr($source, 0, strpos($source, '?'));
2330
                                    if (strpos($source, '://') > 0) {
2331
                                        if (strpos($source, api_get_path(WEB_PATH)) !== false) {
2332
                                            //we found the current portal url
2333
                                            $files_list[] = [$source, 'local', 'url'];
2334
                                            $in_files_list[] = self::get_resources_from_source_html(
2335
                                                $source,
2336
                                                true,
2337
                                                TOOL_DOCUMENT,
2338
                                                $recursivity + 1
2339
                                            );
2340
                                            if (count($in_files_list) > 0) {
2341
                                                $files_list = array_merge($files_list, $in_files_list);
2342
                                            }
2343
                                        } else {
2344
                                            //we didn't find any trace of current portal
2345
                                            $files_list[] = [$source, 'remote', 'url'];
2346
                                        }
2347
                                    } else {
2348
                                        //no protocol found, make link local
2349
                                        if (substr($source, 0, 1) === '/') {
2350
                                            //link starts with a /, making it absolute (relative to DocumentRoot)
2351
                                            $files_list[] = [$source, 'local', 'abs'];
2352
                                            $in_files_list[] = self::get_resources_from_source_html(
2353
                                                $source,
2354
                                                true,
2355
                                                TOOL_DOCUMENT,
2356
                                                $recursivity + 1
2357
                                            );
2358
                                            if (count($in_files_list) > 0) {
2359
                                                $files_list = array_merge($files_list, $in_files_list);
2360
                                            }
2361
                                        } elseif (strstr($source, '..') === 0) {
2362
                                            //link is relative but going back in the hierarchy
2363
                                            $files_list[] = [$source, 'local', 'rel'];
2364
                                            $dir = '';
2365
                                            if (!empty($abs_path)) {
2366
                                                $dir = dirname($abs_path).'/';
2367
                                            }
2368
                                            $new_abs_path = realpath($dir.$source);
2369
                                            $in_files_list[] = self::get_resources_from_source_html(
2370
                                                $new_abs_path,
2371
                                                true,
2372
                                                TOOL_DOCUMENT,
2373
                                                $recursivity + 1
2374
                                            );
2375
                                            if (count($in_files_list) > 0) {
2376
                                                $files_list = array_merge($files_list, $in_files_list);
2377
                                            }
2378
                                        } else {
2379
                                            //no starting '/', making it relative to current document's path
2380
                                            if (substr($source, 0, 2) == './') {
2381
                                                $source = substr($source, 2);
2382
                                            }
2383
                                            $files_list[] = [$source, 'local', 'rel'];
2384
                                            $dir = '';
2385
                                            if (!empty($abs_path)) {
2386
                                                $dir = dirname($abs_path).'/';
2387
                                            }
2388
                                            $new_abs_path = realpath($dir.$source);
2389
                                            $in_files_list[] = self::get_resources_from_source_html(
2390
                                                $new_abs_path,
2391
                                                true,
2392
                                                TOOL_DOCUMENT,
2393
                                                $recursivity + 1
2394
                                            );
2395
                                            if (count($in_files_list) > 0) {
2396
                                                $files_list = array_merge($files_list, $in_files_list);
2397
                                            }
2398
                                        }
2399
                                    }
2400
                                }
2401
                                //found some protocol there
2402
                                if (strpos($source, api_get_path(WEB_PATH)) !== false) {
2403
                                    //we found the current portal url
2404
                                    $files_list[] = [$source, 'local', 'url'];
2405
                                    $in_files_list[] = self::get_resources_from_source_html(
2406
                                        $source,
2407
                                        true,
2408
                                        TOOL_DOCUMENT,
2409
                                        $recursivity + 1
2410
                                    );
2411
                                    if (count($in_files_list) > 0) {
2412
                                        $files_list = array_merge($files_list, $in_files_list);
2413
                                    }
2414
                                } else {
2415
                                    //we didn't find any trace of current portal
2416
                                    $files_list[] = [$source, 'remote', 'url'];
2417
                                }
2418
                            } else {
2419
                                //no protocol found, make link local
2420
                                if (substr($source, 0, 1) === '/') {
2421
                                    //link starts with a /, making it absolute (relative to DocumentRoot)
2422
                                    $files_list[] = [$source, 'local', 'abs'];
2423
                                    $in_files_list[] = self::get_resources_from_source_html(
2424
                                        $source,
2425
                                        true,
2426
                                        TOOL_DOCUMENT,
2427
                                        $recursivity + 1
2428
                                    );
2429
                                    if (count($in_files_list) > 0) {
2430
                                        $files_list = array_merge($files_list, $in_files_list);
2431
                                    }
2432
                                } elseif (strpos($source, '..') === 0) {
2433
                                    //link is relative but going back in the hierarchy
2434
                                    $files_list[] = [$source, 'local', 'rel'];
2435
                                    $dir = '';
2436
                                    if (!empty($abs_path)) {
2437
                                        $dir = dirname($abs_path).'/';
2438
                                    }
2439
                                    $new_abs_path = realpath($dir.$source);
2440
                                    $in_files_list[] = self::get_resources_from_source_html(
2441
                                        $new_abs_path,
2442
                                        true,
2443
                                        TOOL_DOCUMENT,
2444
                                        $recursivity + 1
2445
                                    );
2446
                                    if (count($in_files_list) > 0) {
2447
                                        $files_list = array_merge($files_list, $in_files_list);
2448
                                    }
2449
                                } else {
2450
                                    //no starting '/', making it relative to current document's path
2451
                                    if (substr($source, 0, 2) == './') {
2452
                                        $source = substr($source, 2);
2453
                                    }
2454
                                    $files_list[] = [$source, 'local', 'rel'];
2455
                                    $dir = '';
2456
                                    if (!empty($abs_path)) {
2457
                                        $dir = dirname($abs_path).'/';
2458
                                    }
2459
                                    $new_abs_path = realpath($dir.$source);
2460
                                    $in_files_list[] = self::get_resources_from_source_html(
2461
                                        $new_abs_path,
2462
                                        true,
2463
                                        TOOL_DOCUMENT,
2464
                                        $recursivity + 1
2465
                                    );
2466
                                    if (count($in_files_list) > 0) {
2467
                                        $files_list = array_merge($files_list, $in_files_list);
2468
                                    }
2469
                                }
2470
                            }
2471
                        }
2472
                    }
2473
                }
2474
                break;
2475
            default: //ignore
2476
                break;
2477
        }
2478
2479
        $checked_files_list = [];
2480
        $checked_array_list = [];
2481
2482
        if (count($files_list) > 0) {
2483
            foreach ($files_list as $idx => $file) {
2484
                if (!empty($file[0])) {
2485
                    if (!in_array($file[0], $checked_files_list)) {
2486
                        $checked_files_list[] = $files_list[$idx][0];
2487
                        $checked_array_list[] = $files_list[$idx];
2488
                    }
2489
                }
2490
            }
2491
        }
2492
2493
        return $checked_array_list;
2494
    }
2495
2496
    /**
2497
     * Parses the HTML attributes given as string.
2498
     *
2499
     * @param string HTML attribute string
2500
     * @param array List of attributes that we want to get back
2501
     * @param array
2502
     *
2503
     * @return array An associative array of attributes
2504
     *
2505
     * @author Based on a function from the HTML_Common2 PEAR module     *
2506
     */
2507
    public static function parse_HTML_attributes($attrString, $wanted = [], $explode_variables = [])
2508
    {
2509
        $attributes = [];
2510
        $regs = [];
2511
        $reduced = false;
2512
        if (count($wanted) > 0) {
2513
            $reduced = true;
2514
        }
2515
        try {
2516
            //Find all occurences of something that looks like a URL
2517
            // The structure of this regexp is:
2518
            // (find protocol) then
2519
            // (optionally find some kind of space 1 or more times) then
2520
            // find (either an equal sign or a bracket) followed by an optional space
2521
            // followed by some text without quotes (between quotes itself or not)
2522
            // then possible closing brackets if we were in the opening bracket case
2523
            // OR something like @import()
2524
            $res = preg_match_all(
2525
                '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]*))'.
2526
                // '/(((([A-Za-z_:])([A-Za-z0-9_:\.-]|[^\x00-\x7F])*)' . -> seems to be taking too much
2527
                // '/(((([A-Za-z_:])([^\x00-\x7F])*)' . -> takes only last letter of parameter name
2528
                '([ \n\t\r]+)?('.
2529
                // '(=([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+))' . -> doesn't restrict close enough to the url itself
2530
                '(=([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+))'.
2531
                '|'.
2532
                // '(\(([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)\))' . -> doesn't restrict close enough to the url itself
2533
                '(\(([ \n\t\r]+)?("[^"\)]+"|\'[^\'\)]+\'|[^ \n\t\r\)]+)\))'.
2534
                '))'.
2535
                '|'.
2536
                // '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))?/', -> takes a lot (like 100's of thousands of empty possibilities)
2537
                '(@import([ \n\t\r]+)?("[^"]+"|\'[^\']+\'|[^ \n\t\r]+)))/',
2538
                $attrString,
2539
                $regs
2540
            );
2541
        } catch (Exception $e) {
2542
            error_log('Caught exception: '.$e->getMessage(), 0);
2543
        }
2544
        if ($res) {
2545
            for ($i = 0; $i < count($regs[1]); $i++) {
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...
2546
                $name = trim($regs[3][$i]);
2547
                $check = trim($regs[0][$i]);
2548
                $value = trim($regs[10][$i]);
2549
                if (empty($value) and !empty($regs[13][$i])) {
2550
                    $value = $regs[13][$i];
2551
                }
2552
                if (empty($name) && !empty($regs[16][$i])) {
2553
                    $name = '@import';
2554
                    $value = trim($regs[16][$i]);
2555
                }
2556
                if (!empty($name)) {
2557
                    if (!$reduced || in_array(strtolower($name), $wanted)) {
2558
                        if ($name == $check) {
2559
                            $attributes[strtolower($name)][] = strtolower($name);
2560
                        } else {
2561
                            if (!empty($value) && ($value[0] == '\'' || $value[0] == '"')) {
2562
                                $value = substr($value, 1, -1);
2563
                            }
2564
2565
                            if ($value == 'API.LMSGetValue(name') {
2566
                                $value = 'API.LMSGetValue(name)';
2567
                            }
2568
                            //Gets the xx.flv value from the string flashvars="width=320&height=240&autostart=false&file=xxx.flv&repeat=false"
2569
                            if (isset($explode_variables[$name])) {
2570
                                $value_modified = str_replace('&amp;', '&', $value);
2571
                                $value_array = explode('&', $value_modified);
2572
                                foreach ($value_array as $item) {
2573
                                    $itemParts = explode('=', $item);
2574
                                    $key = $itemParts[0];
2575
                                    $item_value = !empty($itemParts[1]) ? $itemParts[1] : '';
2576
                                    if ($key == $explode_variables[$name]) {
2577
                                        $attributes[strtolower($name)][] = $item_value;
2578
                                    }
2579
                                }
2580
                            }
2581
                            $attributes[strtolower($name)][] = $value;
2582
                        }
2583
                    }
2584
                }
2585
            }
2586
        }
2587
2588
        return $attributes;
2589
    }
2590
2591
    /**
2592
     * Replace urls inside content html from a copy course.
2593
     *
2594
     * @param string $content_html
2595
     * @param string $origin_course_code
2596
     * @param string $destination_course_directory
2597
     * @param string $origin_course_path_from_zip
2598
     * @param string $origin_course_info_path
2599
     *
2600
     * @return string new content html with replaced urls or return false if content is not a string
2601
     */
2602
    public static function replaceUrlWithNewCourseCode(
2603
        $content_html,
2604
        $origin_course_code,
2605
        $destination_course_directory,
2606
        $origin_course_path_from_zip = null,
2607
        $origin_course_info_path = null
2608
    ) {
2609
        if (empty($content_html)) {
2610
            return false;
2611
        }
2612
2613
        $orig_source_html = self::get_resources_from_source_html($content_html);
2614
        $orig_course_info = api_get_course_info($origin_course_code);
2615
2616
        // Course does not exist in the current DB probably this came from a zip file?
2617
        if (empty($orig_course_info)) {
2618
            if (!empty($origin_course_path_from_zip)) {
2619
                $orig_course_path = $origin_course_path_from_zip.'/';
2620
                $orig_course_info_path = $origin_course_info_path;
2621
            }
2622
        } else {
2623
            $orig_course_path = api_get_path(SYS_COURSE_PATH).$orig_course_info['path'].'/';
2624
            $orig_course_info_path = $orig_course_info['path'];
2625
        }
2626
2627
        $destination_course_code = CourseManager::getCourseCodeFromDirectory($destination_course_directory);
2628
        $destination_course_info = api_get_course_info($destination_course_code);
2629
        $dest_course_path = api_get_path(SYS_COURSE_PATH).$destination_course_directory.'/';
2630
        $dest_course_path_rel = api_get_path(REL_COURSE_PATH).$destination_course_directory.'/';
2631
2632
        $user_id = api_get_user_id();
2633
2634
        if (!empty($orig_source_html)) {
2635
            foreach ($orig_source_html as $source) {
2636
                // Get information about source url
2637
                $real_orig_url = $source[0]; // url
2638
                $scope_url = $source[1]; // scope (local, remote)
2639
                $type_url = $source[2]; // type (rel, abs, url)
2640
2641
                // Get path and query from origin url
2642
                $orig_parse_url = parse_url($real_orig_url);
2643
                $real_orig_path = isset($orig_parse_url['path']) ? $orig_parse_url['path'] : null;
2644
                $real_orig_query = isset($orig_parse_url['query']) ? $orig_parse_url['query'] : null;
2645
2646
                // Replace origin course code by destination course code from origin url query
2647
                $dest_url_query = '';
2648
2649
                if (!empty($real_orig_query)) {
2650
                    $dest_url_query = '?'.$real_orig_query;
2651
                    if (strpos($dest_url_query, $origin_course_code) !== false) {
2652
                        $dest_url_query = str_replace($origin_course_code, $destination_course_code, $dest_url_query);
2653
                    }
2654
                }
2655
2656
                if ($scope_url == 'local') {
2657
                    if ($type_url == 'abs' || $type_url == 'rel') {
2658
                        $document_file = strstr($real_orig_path, 'document');
2659
2660
                        if (strpos($real_orig_path, $document_file) !== false) {
2661
                            $origin_filepath = $orig_course_path.$document_file;
2662
                            $destination_filepath = $dest_course_path.$document_file;
2663
2664
                            // copy origin file inside destination course
2665
                            if (file_exists($origin_filepath)) {
2666
                                $filepath_dir = dirname($destination_filepath);
2667
2668
                                if (!is_dir($filepath_dir)) {
2669
                                    $perm = api_get_permissions_for_new_directories();
2670
                                    $result = @mkdir($filepath_dir, $perm, true);
2671
                                    if ($result) {
2672
                                        $filepath_to_add = str_replace(
2673
                                            [$dest_course_path, 'document'],
2674
                                            '',
2675
                                            $filepath_dir
2676
                                        );
2677
2678
                                        // Add to item properties to the new folder
2679
                                        self::addDocument(
2680
                                            $destination_course_info,
2681
                                            $filepath_to_add,
2682
                                            'folder',
2683
                                            0,
2684
                                            basename($filepath_to_add)
2685
                                        );
2686
                                    }
2687
                                }
2688
2689
                                if (!file_exists($destination_filepath)) {
2690
                                    $result = @copy($origin_filepath, $destination_filepath);
2691
                                    if ($result) {
2692
                                        $filepath_to_add = str_replace(
2693
                                            [$dest_course_path, 'document'],
2694
                                            '',
2695
                                            $destination_filepath
2696
                                        );
2697
                                        $size = filesize($destination_filepath);
2698
2699
                                        // Add to item properties to the file
2700
                                        self::addDocument(
2701
                                            $destination_course_info,
2702
                                            $filepath_to_add,
2703
                                            'file',
2704
                                            $size,
2705
                                            basename($filepath_to_add)
2706
                                        );
2707
                                    }
2708
                                }
2709
                            }
2710
2711
                            // Replace origin course path by destination course path.
2712
                            if (strpos($content_html, $real_orig_url) !== false) {
2713
                                $url_course_path = str_replace(
2714
                                    $orig_course_info_path.'/'.$document_file,
2715
                                    '',
2716
                                    $real_orig_path
2717
                                );
2718
                                // See BT#7780
2719
                                $destination_url = $dest_course_path_rel.$document_file.$dest_url_query;
2720
                                // If the course code doesn't exist in the path? what we do? Nothing! see BT#1985
2721
                                if (strpos($real_orig_path, $origin_course_code) === false) {
2722
                                    $url_course_path = $real_orig_path;
2723
                                    $destination_url = $real_orig_path;
2724
                                }
2725
                                $content_html = str_replace($real_orig_url, $destination_url, $content_html);
2726
                            }
2727
                        }
2728
2729
                        // replace origin course code by destination course code  from origin url
2730
                        if (strpos($real_orig_url, '?') === 0) {
2731
                            $dest_url = str_replace($origin_course_code, $destination_course_code, $real_orig_url);
2732
                            $content_html = str_replace($real_orig_url, $dest_url, $content_html);
2733
                        }
2734
                    }
2735
                }
2736
            }
2737
        }
2738
2739
        return $content_html;
2740
    }
2741
2742
    /**
2743
     * Export document to PDF.
2744
     *
2745
     * @param int    $document_id
2746
     * @param string $courseCode
2747
     * @param string $orientation
2748
     * @param bool   $showHeaderAndFooter
2749
     */
2750
    public static function export_to_pdf(
2751
        $document_id,
2752
        $courseCode,
2753
        $orientation = 'landscape',
2754
        $showHeaderAndFooter = true
2755
    ) {
2756
        $course_data = api_get_course_info($courseCode);
2757
        $document_data = self::get_document_data_by_id($document_id, $courseCode);
2758
        $file_path = api_get_path(SYS_COURSE_PATH).$course_data['path'].'/document'.$document_data['path'];
2759
        if ($orientation == 'landscape') {
2760
            $pageFormat = 'A4-L';
2761
            $pdfOrientation = 'L';
2762
        } else {
2763
            $pageFormat = 'A4';
2764
            $pdfOrientation = 'P';
2765
        }
2766
        $pdf = new PDF(
2767
            $pageFormat,
2768
            $pdfOrientation,
2769
            $showHeaderAndFooter ? [] : ['top' => 0, 'left' => 0, 'bottom' => 0, 'right' => 0]
2770
        );
2771
2772
        if (api_get_configuration_value('use_alternative_document_pdf_footer')) {
2773
            $view = new Template('', false, false, false, true, false, false);
2774
            $template = $view->get_template('export/alt_pdf_footer.tpl');
2775
2776
            $pdf->set_custom_footer([
2777
                'html' => $view->fetch($template),
2778
            ]);
2779
        }
2780
2781
        $pdf->html_to_pdf(
2782
            $file_path,
2783
            $document_data['title'],
2784
            $courseCode,
2785
            false,
2786
            $showHeaderAndFooter
2787
        );
2788
    }
2789
2790
    /**
2791
     * Uploads a document.
2792
     *
2793
     * @param array  $files                   the $_FILES variable
2794
     * @param string $path
2795
     * @param string $title
2796
     * @param string $comment
2797
     * @param int    $unzip                   unzip or not the file
2798
     * @param string $ifExists                overwrite, rename or warn (default)
2799
     * @param bool   $index_document          index document (search xapian module)
2800
     * @param bool   $show_output             print html messages
2801
     * @param string $fileKey
2802
     * @param bool   $treat_spaces_as_hyphens
2803
     * @param int    $parentId
2804
     *
2805
     * @return CDocument|false
2806
     */
2807
    public static function upload_document(
2808
        $files,
2809
        $path,
2810
        $title = '',
2811
        $comment = '',
2812
        $unzip = 0,
2813
        $ifExists = '',
2814
        $index_document = false,
2815
        $show_output = false,
2816
        $fileKey = 'file',
2817
        $treat_spaces_as_hyphens = true,
2818
        $parentId = 0
2819
    ) {
2820
        $course_info = api_get_course_info();
2821
        $sessionId = api_get_session_id();
2822
        $course_dir = $course_info['path'].'/document';
2823
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
2824
        $base_work_dir = $sys_course_path.$course_dir;
2825
2826
        if (isset($files[$fileKey])) {
2827
            $uploadOk = process_uploaded_file($files[$fileKey], $show_output);
2828
            if ($uploadOk) {
2829
                $document = handle_uploaded_document(
2830
                    $course_info,
2831
                    $files[$fileKey],
2832
                    $base_work_dir,
2833
                    $path,
2834
                    api_get_user_id(),
2835
                    api_get_group_id(),
2836
                    null,
2837
                    $unzip,
2838
                    $ifExists,
2839
                    $show_output,
2840
                    false,
2841
                    null,
2842
                    $sessionId,
2843
                    $treat_spaces_as_hyphens,
2844
                    $fileKey,
2845
                    $parentId
2846
                );
2847
2848
                // Showing message when sending zip files
2849
                if ($document && $unzip == 1) {
2850
                    if ($show_output) {
2851
                        echo Display::return_message(
2852
                            get_lang('UplUploadSucceeded').'<br />',
2853
                            'confirm',
2854
                            false
2855
                        );
2856
                    }
2857
2858
                    return $document;
2859
                }
2860
2861
                if ($document) {
2862
                    /*
2863
                        $table_document = Database::get_course_table(TABLE_DOCUMENT);
2864
                        $params = [];
2865
2866
                        if (!empty($title)) {
2867
                            $params['title'] = $title;
2868
                        }
2869
2870
                        if (!empty($comment)) {
2871
                            $params['comment'] = trim($comment);
2872
                        }
2873
2874
                        Database::update(
2875
                            $table_document,
2876
                            $params,
2877
                            [
2878
                                'id = ? AND c_id = ? ' => [
2879
                                    $documentId,
2880
                                    $course_info['real_id'],
2881
                                ],
2882
                            ]
2883
                        );
2884
                    }*/
2885
2886
                    if ($index_document) {
2887
                        self::index_document(
2888
                            $document->getId(),
2889
                            $course_info['code'],
2890
                            null,
2891
                            $_POST['language'] ?? '',
2892
                            $_REQUEST,
2893
                            $ifExists
2894
                        );
2895
                    }
2896
2897
                    return $document;
2898
                }
2899
            }
2900
        }
2901
2902
        return false;
2903
    }
2904
2905
    /**
2906
     * Obtains the text inside the file with the right parser.
2907
     */
2908
    public static function get_text_content($doc_path, $doc_mime)
2909
    {
2910
        // TODO: review w$ compatibility
2911
        // Use usual exec output lines array to store stdout instead of a temp file
2912
        // because we need to store it at RAM anyway before index on ChamiloIndexer object
2913
        $ret_val = null;
2914
        switch ($doc_mime) {
2915
            case 'text/plain':
2916
                $handle = fopen($doc_path, 'r');
2917
                $output = [fread($handle, filesize($doc_path))];
2918
                fclose($handle);
2919
                break;
2920
            case 'application/pdf':
2921
                exec("pdftotext $doc_path -", $output, $ret_val);
2922
                break;
2923
            case 'application/postscript':
2924
                $temp_file = tempnam(sys_get_temp_dir(), 'chamilo');
2925
                exec("ps2pdf $doc_path $temp_file", $output, $ret_val);
2926
                if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
2927
                    return false;
2928
                }
2929
                exec("pdftotext $temp_file -", $output, $ret_val);
2930
                unlink($temp_file);
2931
                break;
2932
            case 'application/msword':
2933
                exec("catdoc $doc_path", $output, $ret_val);
2934
                break;
2935
            case 'text/html':
2936
                exec("html2text $doc_path", $output, $ret_val);
2937
                break;
2938
            case 'text/rtf':
2939
                // Note: correct handling of code pages in unrtf
2940
                // on debian lenny unrtf v0.19.2 can not, but unrtf v0.20.5 can
2941
                exec("unrtf --text $doc_path", $output, $ret_val);
2942
                if ($ret_val == 127) { // command not found
2943
                    return false;
2944
                }
2945
                // Avoid index unrtf comments
2946
                if (is_array($output) && count($output) > 1) {
2947
                    $parsed_output = [];
2948
                    foreach ($output as &$line) {
2949
                        if (!preg_match('/^###/', $line, $matches)) {
2950
                            if (!empty($line)) {
2951
                                $parsed_output[] = $line;
2952
                            }
2953
                        }
2954
                    }
2955
                    $output = $parsed_output;
2956
                }
2957
                break;
2958
            case 'application/vnd.ms-powerpoint':
2959
                exec("catppt $doc_path", $output, $ret_val);
2960
                break;
2961
            case 'application/vnd.ms-excel':
2962
                exec("xls2csv -c\" \" $doc_path", $output, $ret_val);
2963
                break;
2964
        }
2965
2966
        $content = '';
2967
        if (!is_null($ret_val)) {
2968
            if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
2969
                return false;
2970
            }
2971
        }
2972
        if (isset($output)) {
2973
            foreach ($output as &$line) {
2974
                $content .= $line."\n";
2975
            }
2976
2977
            return $content;
2978
        } else {
2979
            return false;
2980
        }
2981
    }
2982
2983
    /**
2984
     * Calculates the total size of all documents in a course.
2985
     *
2986
     * @author Bert vanderkimpen
2987
     *
2988
     * @param int $course_id
2989
     * @param int $group_id   (to calculate group document space)
2990
     * @param int $session_id
2991
     *
2992
     * @return int total size
2993
     */
2994
    public static function documents_total_space($course_id = null, $group_id = null, $session_id = null)
2995
    {
2996
        $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
2997
        $TABLE_DOCUMENT = Database::get_course_table(TABLE_DOCUMENT);
2998
2999
        $session_id = (int) $session_id;
3000
        $group_id = (int) $group_id;
3001
        $course_id = (int) $course_id;
3002
3003
        if (!$course_id) {
3004
            $course_id = api_get_course_int_id();
3005
        }
3006
3007
        $group_condition = '';
3008
        if ($group_id) {
3009
            $group_condition = " AND props.to_group_id='".$group_id."' ";
3010
        }
3011
3012
        $session_condition = '';
3013
        if ($session_id) {
3014
            $session_condition = " AND props.session_id='".$session_id."' ";
3015
        }
3016
3017
        $sql = "SELECT SUM(size)
3018
                FROM $TABLE_ITEMPROPERTY AS props
3019
                INNER JOIN $TABLE_DOCUMENT AS docs
3020
                ON (docs.id = props.ref AND props.c_id = docs.c_id)
3021
                WHERE
3022
                    props.c_id = $course_id AND
3023
                    docs.c_id = $course_id AND
3024
                    props.tool = '".TOOL_DOCUMENT."' AND
3025
                    props.visibility <> 2
3026
                    $group_condition
3027
                    $session_condition
3028
                ";
3029
        $result = Database::query($sql);
3030
3031
        if ($result && Database::num_rows($result) != 0) {
3032
            $row = Database::fetch_row($result);
3033
3034
            return (int) $row[0];
3035
        } else {
3036
            return 0;
3037
        }
3038
    }
3039
3040
    /**
3041
     * Display the document quota in a simple way.
3042
     *
3043
     *  Here we count 1 Kilobyte = 1024 Bytes, 1 Megabyte = 1048576 Bytes
3044
     */
3045
    public static function displaySimpleQuota($course_quota, $already_consumed_space)
3046
    {
3047
        $course_quota_m = round($course_quota / 1048576);
3048
        $already_consumed_space_m = round($already_consumed_space / 1048576, 2);
3049
        $percentage = $already_consumed_space / $course_quota * 100;
3050
        $percentage = round($percentage, 1);
3051
        $message = get_lang('YouAreCurrentlyUsingXOfYourX');
3052
        $message = sprintf($message, $already_consumed_space_m, $percentage.'%', $course_quota_m.' ');
3053
3054
        return Display::div($message, ['id' => 'document_quota']);
3055
    }
3056
3057
    /**
3058
     * Checks if there is enough place to add a file on a directory
3059
     * on the base of a maximum directory size allowed.
3060
     *
3061
     * @author Bert Vanderkimpen
3062
     *
3063
     * @param int $file_size     size of the file in byte
3064
     * @param int $max_dir_space maximum size
3065
     *
3066
     * @return bool true if there is enough space, false otherwise
3067
     *
3068
     * @see enough_space() uses  documents_total_space() function
3069
     */
3070
    public static function enough_space($file_size, $max_dir_space)
3071
    {
3072
        if ($max_dir_space) {
3073
            $already_filled_space = self::documents_total_space();
3074
            if (($file_size + $already_filled_space) > $max_dir_space) {
3075
                return false;
3076
            }
3077
        }
3078
3079
        return true;
3080
    }
3081
3082
    /**
3083
     * @param array $params count, url, extension
3084
     *
3085
     * @return string
3086
     */
3087
    public static function generateAudioJavascript($params = [])
3088
    {
3089
        $js = '
3090
            $(\'audio.audio_preview\').mediaelementplayer({
3091
                features: [\'playpause\'],
3092
                audioWidth: 30,
3093
                audioHeight: 30,
3094
                success: function(mediaElement, originalNode, instance) {                
3095
                }
3096
            });';
3097
3098
        return $js;
3099
    }
3100
3101
    /**
3102
     * Shows a play icon next to the document title in the document list.
3103
     *
3104
     * @param string $documentWebPath
3105
     * @param array  $documentInfo
3106
     *
3107
     * @return string
3108
     */
3109
    public static function generateAudioPreview($documentWebPath, $documentInfo)
3110
    {
3111
        $filePath = $documentWebPath.$documentInfo['path'];
3112
        $extension = $documentInfo['file_extension'];
3113
        $html = '<span class="preview"> <audio class="audio_preview skip" src="'.$filePath.'" type="audio/'.$extension.'" > </audio></span>';
3114
3115
        return $html;
3116
    }
3117
3118
    /**
3119
     * @param string $file
3120
     * @param string $extension
3121
     *
3122
     * @return string
3123
     */
3124
    public static function generateVideoPreview($file, $extension)
3125
    {
3126
        $type = '';
3127
        /*if ($extension != 'flv') {
3128
3129
        }*/
3130
        //$type = "video/$extension";
3131
        //$fileInfo = parse_url($file);
3132
        //$type = self::file_get_mime_type(basename($fileInfo['path']));
3133
3134
        $html = '<video id="myvideo" controls>';
3135
        $html .= '<source src="'.$file.'" >';
3136
        $html .= '</video>';
3137
3138
        return $html;
3139
    }
3140
3141
    /**
3142
     * @param array  $course_info
3143
     * @param bool   $lp_id
3144
     * @param string $target
3145
     * @param int    $session_id
3146
     * @param bool   $add_move_button
3147
     * @param string $filter_by_folder
3148
     * @param string $overwrite_url
3149
     * @param bool   $showInvisibleFiles
3150
     * @param bool   $showOnlyFolders
3151
     * @param int    $folderId
3152
     *
3153
     * @return string
3154
     */
3155
    public static function get_document_preview(
3156
        $course_info,
3157
        $lp_id = false,
3158
        $target = '',
3159
        $session_id = 0,
3160
        $add_move_button = false,
3161
        $filter_by_folder = null,
3162
        $overwrite_url = '',
3163
        $showInvisibleFiles = false,
3164
        $showOnlyFolders = false,
3165
        $folderId = false
3166
    ) {
3167
        if (empty($course_info['real_id']) || empty($course_info['code']) || !is_array($course_info)) {
3168
            return '';
3169
        }
3170
3171
        $user_id = api_get_user_id();
3172
        $userInfo = api_get_user_info();
3173
3174
        $user_in_course = false;
3175
        if (api_is_platform_admin()) {
3176
            $user_in_course = true;
3177
        }
3178
3179
        if (!$user_in_course) {
3180
            if (CourseManager::is_course_teacher($user_id, $course_info['code'])) {
3181
                $user_in_course = true;
3182
            }
3183
        }
3184
3185
        // Condition for the session
3186
        $session_id = intval($session_id);
3187
3188
        if (!$user_in_course) {
3189
            if (empty($session_id)) {
3190
                if (CourseManager::is_user_subscribed_in_course($user_id, $course_info['code'])) {
3191
                    $user_in_course = true;
3192
                }
3193
                // Check if course is open then we can consider that the student is registered to the course
3194
                if (isset($course_info) && in_array($course_info['visibility'], [2, 3])) {
3195
                    $user_in_course = true;
3196
                }
3197
            } else {
3198
                $user_status = SessionManager::get_user_status_in_course_session(
3199
                    $user_id,
3200
                    $course_info['real_id'],
3201
                    $session_id
3202
                );
3203
                //is true if is an student, course session teacher or coach
3204
                if (in_array($user_status, ['0', '2', '6'])) {
3205
                    $user_in_course = true;
3206
                }
3207
            }
3208
        }
3209
3210
        $tbl_doc = Database::get_course_table(TABLE_DOCUMENT);
3211
        $tbl_item_prop = Database::get_course_table(TABLE_ITEM_PROPERTY);
3212
        $condition_session = " AND (l.session_id = '$session_id' OR l.session_id = '0' OR l.session_id IS NULL)";
3213
3214
        $add_folder_filter = null;
3215
        if (!empty($filter_by_folder)) {
3216
            $add_folder_filter = " AND docs.path LIKE '".Database::escape_string($filter_by_folder)."%'";
3217
        }
3218
3219
        // If we are in LP display hidden folder https://support.chamilo.org/issues/6679
3220
        $lp_visibility_condition = null;
3221
        if ($lp_id) {
3222
            // $lp_visibility_condition = " OR filetype='folder'";
3223
            if ($showInvisibleFiles) {
3224
                $lp_visibility_condition .= ' OR l.visibility = 0';
3225
            }
3226
        }
3227
3228
        $showOnlyFoldersCondition = null;
3229
        if ($showOnlyFolders) {
3230
            //$showOnlyFoldersCondition = " AND docs.filetype = 'folder' ";
3231
        }
3232
3233
        $folderCondition = " AND docs.path LIKE '/%' ";
3234
3235
        if (!api_is_allowed_to_edit()) {
3236
            $protectedFolders = self::getProtectedFolderFromStudent();
3237
            foreach ($protectedFolders as $folder) {
3238
                $folderCondition .= " AND docs.path NOT LIKE '$folder' ";
3239
            }
3240
        }
3241
3242
        $parentData = [];
3243
        if ($folderId !== false) {
3244
            $parentData = self::get_document_data_by_id(
3245
                $folderId,
3246
                $course_info['code'],
3247
                false,
3248
                $session_id
3249
            );
3250
            if (!empty($parentData)) {
3251
                $cleanedPath = $parentData['path'];
3252
                $num = substr_count($cleanedPath, '/');
3253
3254
                $notLikeCondition = '';
3255
                for ($i = 1; $i <= $num; $i++) {
3256
                    $repeat = str_repeat('/%', $i + 1);
3257
                    $notLikeCondition .= " AND docs.path NOT LIKE '".Database::escape_string($cleanedPath.$repeat)."' ";
3258
                }
3259
3260
                $folderId = (int) $folderId;
3261
                $folderCondition = " AND
3262
                    docs.id <> $folderId AND
3263
                    docs.path LIKE '".$cleanedPath."/%'
3264
                    $notLikeCondition
3265
                ";
3266
            } else {
3267
                $folderCondition = " AND docs.filetype = 'file' ";
3268
            }
3269
        }
3270
3271
        $levelCondition = null;
3272
        if ($folderId === false) {
3273
            $levelCondition = " AND docs.path NOT LIKE'/%/%'";
3274
        }
3275
3276
        $sql = "SELECT DISTINCT l.visibility, docs.*
3277
                FROM resource_node AS n
3278
                INNER JOIN $tbl_doc AS docs
3279
                ON (docs.resource_node_id = n.id)
3280
                INNER JOIN resource_link l
3281
                ON (l.resource_node_id = n.id)    
3282
                WHERE                    
3283
                    docs.path NOT LIKE '%_DELETED_%' AND                    
3284
                    docs.c_id = {$course_info['real_id']} AND
3285
                    l.visibility NOT IN ('".ResourceLink::VISIBILITY_DELETED."')                    
3286
                    $showOnlyFoldersCondition
3287
                    $folderCondition
3288
                    $levelCondition
3289
                    $add_folder_filter
3290
                ORDER BY docs.filetype DESC, docs.title ASC";
3291
3292
        $res_doc = Database::query($sql);
3293
        $resources = Database::store_result($res_doc, 'ASSOC');
3294
3295
        $return = '';
3296
        if ($lp_id) {
3297
            if ($folderId === false) {
3298
                /*$return .= '<div class="lp_resource_element">';
3299
                $return .= Display::return_icon('new_doc.gif', '', [], ICON_SIZE_SMALL);
3300
                $return .= Display::url(
3301
                    get_lang('CreateTheDocument'),
3302
                    api_get_self().'?'.api_get_cidreq().'&action=add_item&type='.TOOL_DOCUMENT.'&lp_id='.$_SESSION['oLP']->lp_id
3303
                );
3304
                $return .= '</div>';*/
3305
            }
3306
        } else {
3307
            $return .= Display::div(
3308
                Display::url(
3309
                    Display::return_icon('close.png', get_lang('Close'), [], ICON_SIZE_SMALL),
3310
                    ' javascript:void(0);',
3311
                    ['id' => 'close_div_'.$course_info['real_id'].'_'.$session_id, 'class' => 'close_div']
3312
                ),
3313
                ['style' => 'position:absolute;right:10px']
3314
            );
3315
        }
3316
3317
        // If you want to debug it, I advise you to do "echo" on the eval statements.
3318
        $newResources = [];
3319
        if (!empty($resources) && $user_in_course) {
3320
            foreach ($resources as $resource) {
3321
                $is_visible = self::is_visible_by_id(
3322
                    $resource['id'],
3323
                    $course_info,
3324
                    $session_id,
3325
                    api_get_user_id()
3326
                );
3327
3328
                if ($showInvisibleFiles === false) {
3329
                    if (!$is_visible) {
3330
                        continue;
3331
                    }
3332
                }
3333
3334
                $newResources[] = $resource;
3335
            }
3336
        }
3337
3338
        $label = get_lang('Documents');
3339
3340
        $documents = [];
3341
        if ($folderId === false) {
3342
            $documents[$label] = [
3343
                'id' => 0,
3344
                'files' => $newResources,
3345
            ];
3346
        } else {
3347
            if (is_array($parentData)) {
3348
                $documents[$parentData['title']] = [
3349
                    'id' => (int) $folderId,
3350
                    'files' => $newResources,
3351
                ];
3352
            }
3353
        }
3354
3355
        $write_result = self::write_resources_tree(
3356
            $userInfo,
3357
            $course_info,
3358
            $session_id,
3359
            $documents,
3360
            $lp_id,
3361
            $target,
3362
            $add_move_button,
3363
            $overwrite_url,
3364
            $folderId
3365
        );
3366
3367
        $return .= $write_result;
3368
        if ($lp_id === false) {
3369
            $url = api_get_path(WEB_AJAX_PATH).
3370
                'lp.ajax.php?a=get_documents&url='.$overwrite_url.'&lp_id='.$lp_id.'&cidReq='.$course_info['code'];
3371
            $return .= "<script>
3372
            $('.doc_folder').click(function() {
3373
                var realId = this.id;
3374
                var my_id = this.id.split('_')[2];
3375
                var tempId = 'temp_'+my_id;
3376
                $('#res_'+my_id).show();
3377
                var tempDiv = $('#'+realId).find('#'+tempId);
3378
                if (tempDiv.length == 0) {
3379
                    $.ajax({
3380
                        async: false,
3381
                        type: 'GET',
3382
                        url:  '".$url."',
3383
                        data: 'folder_id='+my_id,
3384
                        success: function(data) {
3385
                            $('#'+realId).append('<div id='+tempId+'>'+data+'</div>');
3386
                        }
3387
                    });
3388
                }
3389
            });
3390
3391
            $('.close_div').click(function() {
3392
                var course_id = this.id.split('_')[2];
3393
                var session_id = this.id.split('_')[3];
3394
                $('#document_result_'+course_id+'_'+session_id).hide();
3395
                $('.lp_resource').remove();
3396
                $('.document_preview_container').html('');
3397
            });
3398
            </script>";
3399
        } else {
3400
            //For LPs
3401
            $url = api_get_path(WEB_AJAX_PATH).'lp.ajax.php?a=get_documents&lp_id='.$lp_id.'&'.api_get_cidreq();
3402
            $return .= "<script>
3403
3404
            function testResources(id, img) {
3405
                var numericId = id.split('_')[1];
3406
                var parentId = 'doc_id_'+numericId;
3407
                var tempId = 'temp_'+numericId;
3408
                var image = $('#'+img);
3409
3410
                if (image.hasClass('open')) {
3411
                    image.removeClass('open');
3412
                    image.attr('src', '".Display::returnIconPath('nolines_plus.gif')."');
3413
                    $('#'+id).show();
3414
                    $('#'+tempId).hide();
3415
                } else {
3416
                    image.addClass('open');
3417
                    image.attr('src', '".Display::returnIconPath('nolines_minus.gif')."');
3418
                    $('#'+id).hide();
3419
                    $('#'+tempId).show();
3420
                    var tempDiv = $('#'+parentId).find('#'+tempId);
3421
                    if (tempDiv.length == 0) {
3422
                        $.ajax({
3423
                            type: 'GET',
3424
                            async: false,
3425
                            url:  '".$url."',
3426
                            data: 'folder_id='+numericId,
3427
                            success: function(data) {
3428
                                tempDiv = $('#doc_id_'+numericId).append('<div id='+tempId+'>'+data+'</div>');
3429
                            }
3430
                        });
3431
                    }
3432
                }
3433
            }
3434
            </script>";
3435
        }
3436
3437
        if (!$user_in_course) {
3438
            $return = '';
3439
        }
3440
3441
        return $return;
3442
    }
3443
3444
    /**
3445
     * Generate and return an HTML list of resources based on a given array.
3446
     * This list is used to show the course creator a list of available resources to choose from
3447
     * when creating a learning path.
3448
     *
3449
     * @param array  $userInfo        current user info
3450
     * @param array  $course_info
3451
     * @param int    $session_id
3452
     * @param array  $documents
3453
     * @param bool   $lp_id
3454
     * @param string $target
3455
     * @param bool   $add_move_button
3456
     * @param string $overwrite_url
3457
     * @param int    $folderId
3458
     *
3459
     * @return string
3460
     */
3461
    public static function write_resources_tree(
3462
        $userInfo,
3463
        $course_info,
3464
        $session_id,
3465
        $documents,
3466
        $lp_id = false,
3467
        $target = '',
3468
        $add_move_button = false,
3469
        $overwrite_url = '',
3470
        $folderId = false
3471
    ) {
3472
        $return = '';
3473
        if (!empty($documents)) {
3474
            foreach ($documents as $key => $resource) {
3475
                if (isset($resource['id']) && is_int($resource['id'])) {
3476
                    $mainFolderResource = [
3477
                        'id' => $resource['id'],
3478
                        'title' => $key,
3479
                    ];
3480
3481
                    if ($folderId === false) {
3482
                        $return .= self::parseFolder($folderId, $mainFolderResource, $lp_id);
3483
                    }
3484
3485
                    if (isset($resource['files'])) {
3486
                        $return .= self::write_resources_tree(
3487
                            $userInfo,
3488
                            $course_info,
3489
                            $session_id,
3490
                            $resource['files'],
3491
                            $lp_id,
3492
                            $target,
3493
                            $add_move_button,
3494
                            $overwrite_url
3495
                        );
3496
                    }
3497
                    $return .= '</div>';
3498
                    $return .= '</ul>';
3499
                } else {
3500
                    if ($resource['filetype'] === 'folder') {
3501
                        $return .= self::parseFolder($folderId, $resource, $lp_id);
3502
                    } else {
3503
                        $return .= self::parseFile(
3504
                            $userInfo,
3505
                            $course_info,
3506
                            $session_id,
3507
                            $resource,
3508
                            $lp_id,
3509
                            $add_move_button,
3510
                            $target,
3511
                            $overwrite_url
3512
                        );
3513
                    }
3514
                }
3515
            }
3516
        }
3517
3518
        return $return;
3519
    }
3520
3521
    /**
3522
     * @param int    $doc_id
3523
     * @param string $course_code
3524
     * @param int    $session_id
3525
     * @param int    $user_id
3526
     * @param int    $groupId     iid
3527
     *
3528
     * @return bool
3529
     */
3530
    public static function check_visibility_tree(
3531
        $doc_id,
3532
        $course_code,
3533
        $session_id,
3534
        $user_id,
3535
        $groupId = 0
3536
    ) {
3537
        $document_data = self::get_document_data_by_id(
3538
            $doc_id,
3539
            $course_code,
3540
            null,
3541
            $session_id
3542
        );
3543
        if ($session_id != 0 && !$document_data) {
3544
            $document_data = self::get_document_data_by_id(
3545
                $doc_id,
3546
                $course_code,
3547
                null,
3548
                0
3549
            );
3550
        }
3551
3552
        if (!empty($document_data)) {
3553
            // If admin or course teacher, allow anyway
3554
            if (api_is_platform_admin() || CourseManager::is_course_teacher($user_id, $course_code)) {
3555
                return true;
3556
            }
3557
            $course_info = api_get_course_info($course_code);
3558
            if ($document_data['parent_id'] == false || empty($document_data['parent_id'])) {
3559
                if (!empty($groupId)) {
3560
                    return true;
3561
                }
3562
                $visible = self::is_visible_by_id($doc_id, $course_info, $session_id, $user_id);
3563
3564
                return $visible;
3565
            } else {
3566
                $visible = self::is_visible_by_id($doc_id, $course_info, $session_id, $user_id);
3567
3568
                if (!$visible) {
3569
                    return false;
3570
                } else {
3571
                    return self::check_visibility_tree(
3572
                        $document_data['parent_id'],
3573
                        $course_code,
3574
                        $session_id,
3575
                        $user_id,
3576
                        $groupId
3577
                    );
3578
                }
3579
            }
3580
        } else {
3581
            return false;
3582
        }
3583
    }
3584
3585
    /**
3586
     * Index a given document.
3587
     *
3588
     * @param   int     Document ID inside its corresponding course
3589
     * @param   string  Course code
3590
     * @param   int     Session ID (not used yet)
3591
     * @param   string  Language of document's content (defaults to course language)
3592
     * @param   array   Array of specific fields (['code'=>'value',...])
3593
     * @param   string  What to do if the file already exists (default or overwrite)
3594
     * @param   bool    When set to true, this runs the indexer without actually saving anything to any database
3595
     *
3596
     * @return bool Returns true on presumed success, false on failure
3597
     */
3598
    public static function index_document(
3599
        $docid,
3600
        $course_code,
3601
        $session_id = 0,
3602
        $lang = 'english',
3603
        $specific_fields_values = [],
3604
        $if_exists = '',
3605
        $simulation = false
3606
    ) {
3607
        if (api_get_setting('search_enabled') !== 'true') {
3608
            return false;
3609
        }
3610
        if (empty($docid) or $docid != intval($docid)) {
3611
            return false;
3612
        }
3613
        if (empty($session_id)) {
3614
            $session_id = api_get_session_id();
3615
        }
3616
        $course_info = api_get_course_info($course_code);
3617
        $course_dir = $course_info['path'].'/document';
3618
        $sys_course_path = api_get_path(SYS_COURSE_PATH);
3619
        $base_work_dir = $sys_course_path.$course_dir;
3620
3621
        $course_id = $course_info['real_id'];
3622
        $table_document = Database::get_course_table(TABLE_DOCUMENT);
3623
3624
        $qry = "SELECT path, title FROM $table_document WHERE c_id = $course_id AND id = '$docid' LIMIT 1";
3625
        $result = Database::query($qry);
3626
        if (Database::num_rows($result) == 1) {
3627
            $row = Database::fetch_array($result);
3628
            $doc_path = api_get_path(SYS_COURSE_PATH).$course_dir.$row['path'];
3629
            //TODO: mime_content_type is deprecated, fileinfo php extension is enabled by default as of PHP 5.3.0
3630
            // now versions of PHP on Debian testing(5.2.6-5) and Ubuntu(5.2.6-2ubuntu) are lower, so wait for a while
3631
            $doc_mime = mime_content_type($doc_path);
3632
            $allowed_mime_types = self::file_get_mime_type(true);
3633
3634
            // mime_content_type does not detect correctly some formats that
3635
            // are going to be supported for index, so an extensions array is used for the moment
3636
            if (empty($doc_mime)) {
3637
                $allowed_extensions = [
3638
                    'doc',
3639
                    'docx',
3640
                    'ppt',
3641
                    'pptx',
3642
                    'pps',
3643
                    'ppsx',
3644
                    'xls',
3645
                    'xlsx',
3646
                    'odt',
3647
                    'odp',
3648
                    'ods',
3649
                    'pdf',
3650
                    'txt',
3651
                    'rtf',
3652
                    'msg',
3653
                    'csv',
3654
                    'html',
3655
                    'htm',
3656
                ];
3657
                $extensions = preg_split("/[\/\\.]/", $doc_path);
3658
                $doc_ext = strtolower($extensions[count($extensions) - 1]);
3659
                if (in_array($doc_ext, $allowed_extensions)) {
3660
                    switch ($doc_ext) {
3661
                        case 'ppt':
3662
                        case 'pps':
3663
                            $doc_mime = 'application/vnd.ms-powerpoint';
3664
                            break;
3665
                        case 'xls':
3666
                            $doc_mime = 'application/vnd.ms-excel';
3667
                            break;
3668
                    }
3669
                }
3670
            }
3671
3672
            //@todo move this nightmare in a search controller or something like that!!! J.M
3673
3674
            if (in_array($doc_mime, $allowed_mime_types)) {
3675
                $file_title = $row['title'];
3676
                $file_content = self::get_text_content($doc_path, $doc_mime);
3677
                $course_code = Database::escape_string($course_code);
3678
                $ic_slide = new IndexableChunk();
3679
                $ic_slide->addValue('title', $file_title);
3680
                $ic_slide->addCourseId($course_code);
3681
                $ic_slide->addToolId(TOOL_DOCUMENT);
3682
                $xapian_data = [
3683
                    SE_COURSE_ID => $course_code,
3684
                    SE_TOOL_ID => TOOL_DOCUMENT,
3685
                    SE_DATA => ['doc_id' => $docid],
3686
                    SE_USER => api_get_user_id(),
3687
                ];
3688
3689
                $ic_slide->xapian_data = serialize($xapian_data);
3690
                $di = new ChamiloIndexer();
3691
                $return = $di->connectDb(null, null, $lang);
3692
3693
                require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
3694
                $specific_fields = get_specific_field_list();
3695
3696
                // process different depending on what to do if file exists
3697
                /**
3698
                 * @TODO Find a way to really verify if the file had been
3699
                 * overwriten. Now all work is done at
3700
                 * handle_uploaded_document() and it's difficult to verify it
3701
                 */
3702
                if (!empty($if_exists) && $if_exists == 'overwrite') {
3703
                    // Overwrite the file on search engine
3704
                    // Actually, it consists on a delete of terms from db,
3705
                    // insert new ones, create a new search engine document,
3706
                    // and remove the old one
3707
                    // Get search_did
3708
                    $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
3709
                    $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
3710
                    $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid);
3711
3712
                    $res = Database::query($sql);
3713
3714
                    if (Database::num_rows($res) > 0) {
3715
                        $se_ref = Database::fetch_array($res);
3716
                        if (!$simulation) {
3717
                            $di->remove_document($se_ref['search_did']);
3718
                        }
3719
                        $all_specific_terms = '';
3720
                        foreach ($specific_fields as $specific_field) {
3721
                            if (!$simulation) {
3722
                                delete_all_specific_field_value($course_code, $specific_field['id'], TOOL_DOCUMENT, $docid);
3723
                            }
3724
                            // Update search engine
3725
                            if (isset($specific_fields_values[$specific_field['code']])) {
3726
                                $sterms = trim($specific_fields_values[$specific_field['code']]);
3727
                            } else { //if the specific field is not defined, force an empty one
3728
                                $sterms = '';
3729
                            }
3730
                            $all_specific_terms .= ' '.$sterms;
3731
                            $sterms = explode(',', $sterms);
3732
                            foreach ($sterms as $sterm) {
3733
                                $sterm = trim($sterm);
3734
                                if (!empty($sterm)) {
3735
                                    $ic_slide->addTerm($sterm, $specific_field['code']);
3736
                                    // updated the last param here from $value to $sterm without being sure - see commit15464
3737
                                    if (!$simulation) {
3738
                                        add_specific_field_value(
3739
                                            $specific_field['id'],
3740
                                            $course_code,
3741
                                            TOOL_DOCUMENT,
3742
                                            $docid,
3743
                                            $sterm
3744
                                        );
3745
                                    }
3746
                                }
3747
                            }
3748
                        }
3749
                        // Add terms also to content to make terms findable by probabilistic search
3750
                        $file_content = $all_specific_terms.' '.$file_content;
3751
3752
                        if (!$simulation) {
3753
                            $ic_slide->addValue('content', $file_content);
3754
                            $di->addChunk($ic_slide);
3755
                            // Index and return a new search engine document id
3756
                            $did = $di->index();
3757
3758
                            if ($did) {
3759
                                // update the search_did on db
3760
                                $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
3761
                                $sql = 'UPDATE %s SET search_did=%d WHERE id=%d LIMIT 1';
3762
                                $sql = sprintf($sql, $tbl_se_ref, (int) $did, (int) $se_ref['id']);
3763
                                Database::query($sql);
3764
                            }
3765
                        }
3766
                    }
3767
                } else {
3768
                    // Add all terms
3769
                    $all_specific_terms = '';
3770
                    foreach ($specific_fields as $specific_field) {
3771
                        if (isset($specific_fields_values[$specific_field['code']])) {
3772
                            $sterms = trim($specific_fields_values[$specific_field['code']]);
3773
                        } else { //if the specific field is not defined, force an empty one
3774
                            $sterms = '';
3775
                        }
3776
                        $all_specific_terms .= ' '.$sterms;
3777
                        if (!empty($sterms)) {
3778
                            $sterms = explode(',', $sterms);
3779
                            foreach ($sterms as $sterm) {
3780
                                if (!$simulation) {
3781
                                    $ic_slide->addTerm(trim($sterm), $specific_field['code']);
3782
                                    add_specific_field_value(
3783
                                        $specific_field['id'],
3784
                                        $course_code,
3785
                                        TOOL_DOCUMENT,
3786
                                        $docid,
3787
                                        $sterm
3788
                                    );
3789
                                }
3790
                            }
3791
                        }
3792
                    }
3793
                    // Add terms also to content to make terms findable by probabilistic search
3794
                    $file_content = $all_specific_terms.' '.$file_content;
3795
                    if (!$simulation) {
3796
                        $ic_slide->addValue('content', $file_content);
3797
                        $di->addChunk($ic_slide);
3798
                        // Index and return search engine document id
3799
                        $did = $di->index();
3800
                        if ($did) {
3801
                            // Save it to db
3802
                            $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
3803
                            $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
3804
                            VALUES (NULL , \'%s\', \'%s\', %s, %s)';
3805
                            $sql = sprintf($sql, $tbl_se_ref, $course_code, TOOL_DOCUMENT, $docid, $did);
3806
                            Database::query($sql);
3807
                        } else {
3808
                            return false;
3809
                        }
3810
                    }
3811
                }
3812
            } else {
3813
                return false;
3814
            }
3815
        }
3816
3817
        return true;
3818
    }
3819
3820
    /**
3821
     * @return array
3822
     */
3823
    public static function get_web_odf_extension_list()
3824
    {
3825
        return ['ods', 'odt', 'odp'];
3826
    }
3827
3828
    /**
3829
     * Set of extension allowed to use Jodconverter.
3830
     *
3831
     * @param $mode 'from'
0 ignored issues
show
Documentation Bug introduced by
The doc comment 'from' at position 0 could not be parsed: Unknown type name ''from'' at position 0 in 'from'.
Loading history...
3832
     *              'to'
3833
     *              'all'
3834
     * @param $format   'text'
3835
     *                  'spreadsheet'
3836
     *                  'presentation'
3837
     *                  'drawing'
3838
     *                  'all'
3839
     *
3840
     * @return array
3841
     */
3842
    public static function getJodconverterExtensionList($mode, $format)
3843
    {
3844
        $extensionList = [];
3845
        $extensionListFromText = [
3846
            'odt',
3847
            'sxw',
3848
            'rtf',
3849
            'doc',
3850
            'docx',
3851
            'wpd',
3852
            'txt',
3853
        ];
3854
        $extensionListToText = [
3855
            'pdf',
3856
            'odt',
3857
            'sxw',
3858
            'rtf',
3859
            'doc',
3860
            'docx',
3861
            'txt',
3862
        ];
3863
        $extensionListFromSpreadsheet = [
3864
            'ods',
3865
            'sxc',
3866
            'xls',
3867
            'xlsx',
3868
            'csv',
3869
            'tsv',
3870
        ];
3871
        $extensionListToSpreadsheet = [
3872
            'pdf',
3873
            'ods',
3874
            'sxc',
3875
            'xls',
3876
            'xlsx',
3877
            'csv',
3878
            'tsv',
3879
        ];
3880
        $extensionListFromPresentation = [
3881
            'odp',
3882
            'sxi',
3883
            'ppt',
3884
            'pptx',
3885
        ];
3886
        $extensionListToPresentation = [
3887
            'pdf',
3888
            'swf',
3889
            'odp',
3890
            'sxi',
3891
            'ppt',
3892
            'pptx',
3893
        ];
3894
        $extensionListFromDrawing = ['odg'];
3895
        $extensionListToDrawing = ['svg', 'swf'];
3896
3897
        if ($mode === 'from') {
3898
            if ($format === 'text') {
3899
                $extensionList = array_merge($extensionList, $extensionListFromText);
3900
            } elseif ($format === 'spreadsheet') {
3901
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3902
            } elseif ($format === 'presentation') {
3903
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3904
            } elseif ($format === 'drawing') {
3905
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3906
            } elseif ($format === 'all') {
3907
                $extensionList = array_merge($extensionList, $extensionListFromText);
3908
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3909
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3910
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3911
            }
3912
        } elseif ($mode === 'to') {
3913
            if ($format === 'text') {
3914
                $extensionList = array_merge($extensionList, $extensionListToText);
3915
            } elseif ($format === 'spreadsheet') {
3916
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3917
            } elseif ($format === 'presentation') {
3918
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3919
            } elseif ($format === 'drawing') {
3920
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3921
            } elseif ($format === 'all') {
3922
                $extensionList = array_merge($extensionList, $extensionListToText);
3923
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3924
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3925
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3926
            }
3927
        } elseif ($mode === 'all') {
3928
            if ($format === 'text') {
3929
                $extensionList = array_merge($extensionList, $extensionListFromText);
3930
                $extensionList = array_merge($extensionList, $extensionListToText);
3931
            } elseif ($format === 'spreadsheet') {
3932
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3933
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3934
            } elseif ($format === 'presentation') {
3935
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3936
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3937
            } elseif ($format === 'drawing') {
3938
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3939
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3940
            } elseif ($format === 'all') {
3941
                $extensionList = array_merge($extensionList, $extensionListFromText);
3942
                $extensionList = array_merge($extensionList, $extensionListToText);
3943
                $extensionList = array_merge($extensionList, $extensionListFromSpreadsheet);
3944
                $extensionList = array_merge($extensionList, $extensionListToSpreadsheet);
3945
                $extensionList = array_merge($extensionList, $extensionListFromPresentation);
3946
                $extensionList = array_merge($extensionList, $extensionListToPresentation);
3947
                $extensionList = array_merge($extensionList, $extensionListFromDrawing);
3948
                $extensionList = array_merge($extensionList, $extensionListToDrawing);
3949
            }
3950
        }
3951
3952
        return $extensionList;
3953
    }
3954
3955
    /**
3956
     * Get Format type list by extension and mode.
3957
     *
3958
     * @param string $mode Mode to search format type list
3959
     *
3960
     * @example 'from'
3961
     * @example 'to'
3962
     *
3963
     * @param string $extension file extension to check file type
3964
     *
3965
     * @return array
3966
     */
3967
    public static function getFormatTypeListConvertor($mode = 'from', $extension)
3968
    {
3969
        $formatTypesList = [];
3970
        $formatTypes = ['text', 'spreadsheet', 'presentation', 'drawing'];
3971
        foreach ($formatTypes as $formatType) {
3972
            if (in_array($extension, self::getJodconverterExtensionList($mode, $formatType))) {
3973
                $formatTypesList[] = $formatType;
3974
            }
3975
        }
3976
3977
        return $formatTypesList;
3978
    }
3979
3980
    /**
3981
     * @param string $path
3982
     * @param bool   $is_certificate_mode
3983
     *
3984
     * @return bool
3985
     */
3986
    public static function is_folder_to_avoid($path, $is_certificate_mode = false)
3987
    {
3988
        $foldersToAvoid = [
3989
            '/HotPotatoes_files',
3990
            '/certificates',
3991
        ];
3992
        $systemFolder = api_get_course_setting('show_system_folders');
3993
3994
        if ($systemFolder == 1) {
3995
            $foldersToAvoid = [];
3996
        }
3997
3998
        if (basename($path) == 'css') {
3999
            return true;
4000
        }
4001
4002
        if ($is_certificate_mode == false) {
4003
            //Certificate results
4004
            if (strstr($path, 'certificates')) {
4005
                return true;
4006
            }
4007
        }
4008
4009
        // Admin setting for Hide/Show the folders of all users
4010
        if (api_get_setting('show_users_folders') == 'false') {
4011
            $foldersToAvoid[] = '/shared_folder';
4012
4013
            if (strstr($path, 'shared_folder_session_')) {
4014
                return true;
4015
            }
4016
        }
4017
4018
        // Admin setting for Hide/Show Default folders to all users
4019
        if (api_get_setting('show_default_folders') == 'false') {
4020
            $foldersToAvoid[] = '/images';
4021
            $foldersToAvoid[] = '/flash';
4022
            $foldersToAvoid[] = '/audio';
4023
            $foldersToAvoid[] = '/video';
4024
        }
4025
4026
        // Admin setting for Hide/Show chat history folder
4027
        if (api_get_setting('show_chat_folder') == 'false') {
4028
            $foldersToAvoid[] = '/chat_files';
4029
        }
4030
4031
        if (is_array($foldersToAvoid)) {
4032
            return in_array($path, $foldersToAvoid);
4033
        } else {
4034
            return false;
4035
        }
4036
    }
4037
4038
    /**
4039
     * @return array
4040
     */
4041
    public static function get_system_folders()
4042
    {
4043
        return [
4044
            '/certificates',
4045
            '/HotPotatoes_files',
4046
            '/chat_files',
4047
            '/images',
4048
            '/flash',
4049
            '/audio',
4050
            '/video',
4051
            '/shared_folder',
4052
            '/learning_path',
4053
        ];
4054
    }
4055
4056
    /**
4057
     * @return array
4058
     */
4059
    public static function getProtectedFolderFromStudent()
4060
    {
4061
        return [
4062
            '/certificates',
4063
            '/HotPotatoes_files',
4064
            '/chat_files',
4065
            '/shared_folder',
4066
            '/learning_path',
4067
        ];
4068
    }
4069
4070
    /**
4071
     * @param string $courseCode
4072
     *
4073
     * @return string 'visible' or 'invisible' string
4074
     */
4075
    public static function getDocumentDefaultVisibility($courseCode)
4076
    {
4077
        $settings = api_get_setting('tool_visible_by_default_at_creation');
4078
        $defaultVisibility = 'visible';
4079
4080
        if (isset($settings['documents'])) {
4081
            $portalDefaultVisibility = 'invisible';
4082
            if ($settings['documents'] == 'true') {
4083
                $portalDefaultVisibility = 'visible';
4084
            }
4085
4086
            $defaultVisibility = $portalDefaultVisibility;
4087
        }
4088
4089
        if (api_get_setting('documents_default_visibility_defined_in_course') == 'true') {
4090
            $courseVisibility = api_get_course_setting('documents_default_visibility', $courseCode);
4091
            if (!empty($courseVisibility) && in_array($courseVisibility, ['visible', 'invisible'])) {
4092
                $defaultVisibility = $courseVisibility;
4093
            }
4094
        }
4095
4096
        return $defaultVisibility;
4097
    }
4098
4099
    /**
4100
     * @param array  $courseInfo
4101
     * @param int    $id         doc id
4102
     * @param string $visibility visible/invisible
4103
     * @param int    $userId
4104
     */
4105
    public static function updateVisibilityFromAllSessions($courseInfo, $id, $visibility, $userId)
4106
    {
4107
        $sessionList = SessionManager::get_session_by_course($courseInfo['real_id']);
4108
4109
        if (!empty($sessionList)) {
4110
            foreach ($sessionList as $session) {
4111
                $sessionId = $session['id'];
4112
                api_item_property_update(
4113
                    $courseInfo,
4114
                    TOOL_DOCUMENT,
4115
                    $id,
4116
                    $visibility,
4117
                    $userId,
4118
                    null,
4119
                    null,
4120
                    null,
4121
                    null,
4122
                    $sessionId
4123
                );
4124
            }
4125
        }
4126
    }
4127
4128
    /**
4129
     * @param string $file
4130
     *
4131
     * @return string
4132
     */
4133
    public static function readNanogongFile($file)
4134
    {
4135
        $nanoGongJarFile = api_get_path(WEB_LIBRARY_PATH).'nanogong/nanogong.jar';
4136
        $html = '<applet id="applet" archive="'.$nanoGongJarFile.'" code="gong.NanoGong" width="160" height="95">';
4137
        $html .= '<param name="SoundFileURL" value="'.$file.'" />';
4138
        $html .= '<param name="ShowSaveButton" value="false" />';
4139
        $html .= '<param name="ShowTime" value="true" />';
4140
        $html .= '<param name="ShowRecordButton" value="false" />';
4141
        $html .= '</applet>';
4142
4143
        return $html;
4144
    }
4145
4146
    /**
4147
     * @param string $filePath
4148
     * @param string $path
4149
     * @param array  $courseInfo
4150
     * @param int    $sessionId
4151
     * @param string $whatIfFileExists overwrite|rename
4152
     * @param int    $userId
4153
     * @param int    $groupId
4154
     * @param int    $toUserId
4155
     * @param string $comment
4156
     *
4157
     * @return bool|path
4158
     */
4159
    public static function addFileToDocumentTool(
4160
        $filePath,
4161
        $path,
4162
        $courseInfo,
4163
        $sessionId,
4164
        $userId,
4165
        $whatIfFileExists = 'overwrite',
4166
        $groupId = null,
4167
        $toUserId = null,
4168
        $comment = null
4169
    ) {
4170
        if (!file_exists($filePath)) {
4171
            return false;
4172
        }
4173
4174
        $fileInfo = pathinfo($filePath);
4175
4176
        $file = [
4177
            'name' => $fileInfo['basename'],
4178
            'tmp_name' => $filePath,
4179
            'size' => filesize($filePath),
4180
            'from_file' => true,
4181
        ];
4182
4183
        $course_dir = $courseInfo['path'].'/document';
4184
        $baseWorkDir = api_get_path(SYS_COURSE_PATH).$course_dir;
4185
4186
        $filePath = handle_uploaded_document(
4187
            $courseInfo,
4188
            $file,
4189
            $baseWorkDir,
4190
            $path,
4191
            $userId,
4192
            $groupId,
4193
            $toUserId,
4194
            false,
4195
            $whatIfFileExists,
4196
            false,
4197
            false,
4198
            $comment,
4199
            $sessionId
4200
        );
4201
4202
        if ($filePath) {
4203
            return self::get_document_id(
4204
                $courseInfo,
4205
                $filePath,
4206
                $sessionId
4207
            );
4208
        }
4209
4210
        return false;
4211
    }
4212
4213
    /**
4214
     * Converts wav to mp3 file.
4215
     * Requires the ffmpeg lib. In ubuntu: sudo apt-get install ffmpeg.
4216
     *
4217
     * @param string $wavFile
4218
     * @param bool   $removeWavFileIfSuccess
4219
     *
4220
     * @return bool
4221
     */
4222
    public static function convertWavToMp3($wavFile, $removeWavFileIfSuccess = false)
4223
    {
4224
        if (file_exists($wavFile)) {
4225
            try {
4226
                $ffmpeg = \FFMpeg\FFMpeg::create();
4227
                $video = $ffmpeg->open($wavFile);
4228
4229
                $mp3File = str_replace('wav', 'mp3', $wavFile);
4230
                $result = $video->save(new FFMpeg\Format\Audio\Mp3(), $mp3File);
4231
                if ($result && $removeWavFileIfSuccess) {
4232
                    unlink($wavFile);
4233
                }
4234
4235
                if (file_exists($mp3File)) {
4236
                    return $mp3File;
4237
                }
4238
            } catch (Exception $e) {
4239
                error_log($e->getMessage());
4240
                error_log($e->getPrevious()->getMessage());
4241
            }
4242
        }
4243
4244
        return false;
4245
    }
4246
4247
    /**
4248
     * @param string $documentData     wav document information
4249
     * @param array  $courseInfo
4250
     * @param int    $sessionId
4251
     * @param int    $userId           user that adds the document
4252
     * @param string $whatIfFileExists
4253
     * @param bool   $deleteWavFile
4254
     *
4255
     * @return bool
4256
     */
4257
    public static function addAndConvertWavToMp3(
4258
        $documentData,
4259
        $courseInfo,
4260
        $sessionId,
4261
        $userId,
4262
        $whatIfFileExists = 'overwrite',
4263
        $deleteWavFile = false
4264
    ) {
4265
        if (empty($documentData)) {
4266
            return false;
4267
        }
4268
4269
        if (isset($documentData['absolute_path']) &&
4270
            file_exists($documentData['absolute_path'])
4271
        ) {
4272
            $mp3FilePath = self::convertWavToMp3($documentData['absolute_path']);
4273
            error_log($mp3FilePath);
4274
4275
            if (!empty($mp3FilePath) && file_exists($mp3FilePath)) {
4276
                $documentId = self::addFileToDocumentTool(
4277
                    $mp3FilePath,
4278
                    dirname($documentData['path']),
4279
                    $courseInfo,
4280
                    $sessionId,
4281
                    $userId,
4282
                    $whatIfFileExists,
4283
                    null,
4284
                    null,
4285
                    $documentData['comment']
4286
                );
4287
4288
                if (!empty($documentId)) {
4289
                    if ($deleteWavFile) {
4290
                        $coursePath = $courseInfo['directory'].'/document';
4291
                        $documentPath = api_get_path(SYS_COURSE_PATH).$coursePath;
4292
                        self::delete_document(
4293
                            $courseInfo,
4294
                            null,
4295
                            $documentPath,
4296
                            $sessionId,
4297
                            $documentData['id']
4298
                        );
4299
                    }
4300
4301
                    return $documentId;
4302
                }
4303
            }
4304
        }
4305
4306
        return false;
4307
    }
4308
4309
    /**
4310
     * Sets.
4311
     *
4312
     * @param string $file         ($document_data['path'])
4313
     * @param string $file_url_sys
4314
     *
4315
     * @return string
4316
     */
4317
    public static function generateAudioTempFile($file, $file_url_sys)
4318
    {
4319
        //make temp audio
4320
        $temp_folder = api_get_path(SYS_ARCHIVE_PATH).'temp/audio';
4321
        if (!file_exists($temp_folder)) {
4322
            @mkdir($temp_folder, api_get_permissions_for_new_directories(), true);
4323
        }
4324
4325
        //make htaccess with allow from all, and file index.html into temp/audio
4326
        $htaccess = api_get_path(SYS_ARCHIVE_PATH).'temp/audio/.htaccess';
4327
        if (!file_exists($htaccess)) {
4328
            $htaccess_content = "order deny,allow\r\nallow from all\r\nOptions -Indexes";
4329
            $fp = @fopen(api_get_path(SYS_ARCHIVE_PATH).'temp/audio/.htaccess', 'w');
4330
            if ($fp) {
4331
                fwrite($fp, $htaccess_content);
4332
                fclose($fp);
4333
            }
4334
        }
4335
4336
        //encript temp name file
4337
        $name_crip = sha1(uniqid()); //encript
4338
        $findext = explode(".", $file);
4339
        $extension = $findext[count($findext) - 1];
4340
        $file_crip = $name_crip.'.'.$extension;
4341
4342
        //copy file to temp/audio directory
4343
        $from_sys = $file_url_sys;
4344
        $to_sys = api_get_path(SYS_ARCHIVE_PATH).'temp/audio/'.$file_crip;
4345
4346
        if (file_exists($from_sys)) {
4347
            copy($from_sys, $to_sys);
4348
        }
4349
4350
        // get file from tmp directory
4351
        Session::write('temp_audio_nanogong', $to_sys);
4352
4353
        return api_get_path(WEB_ARCHIVE_PATH).'temp/audio/'.$file_crip;
4354
    }
4355
4356
    /**
4357
     * Erase temp nanogong audio.
4358
     */
4359
    public static function removeGeneratedAudioTempFile()
4360
    {
4361
        $tempAudio = Session::read('temp_audio_nanogong');
4362
        if (!empty(isset($tempAudio)) && is_file($tempAudio)) {
4363
            unlink($tempAudio);
4364
            Session::erase('temp_audio_nanogong');
4365
        }
4366
    }
4367
4368
    /**
4369
     * Check if the past is used in this course.
4370
     *
4371
     * @param array  $courseInfo
4372
     * @param string $path
4373
     *
4374
     * @return array
4375
     */
4376
    public static function getDocumentByPathInCourse($courseInfo, $path)
4377
    {
4378
        $table = Database::get_course_table(TABLE_DOCUMENT);
4379
        $path = Database::escape_string($path);
4380
        $courseId = $courseInfo['real_id'];
4381
        if (empty($courseId)) {
4382
            return false;
4383
        }
4384
        $sql = "SELECT * FROM $table WHERE c_id = $courseId AND path = '$path'";
4385
        $result = Database::query($sql);
4386
4387
        return Database::store_result($result, 'ASSOC');
4388
    }
4389
4390
    /**
4391
     * @param array $_course
4392
     *
4393
     * @return int
4394
     */
4395
    public static function createDefaultAudioFolder($_course)
4396
    {
4397
        if (!isset($_course['path'])) {
4398
            return false;
4399
        }
4400
4401
        $audioId = null;
4402
        $path = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document/';
4403
        if (!is_dir($path.'audio')) {
4404
            mkdir($path.'audio', api_get_permissions_for_new_directories());
4405
            self::addDocument($_course, '/audio', 'folder', 0, 'Audio');
4406
        }
4407
4408
        return $audioId;
4409
    }
4410
4411
    /**
4412
     * Generate a default certificate for a courses.
4413
     *
4414
     * @todo move to certificate lib
4415
     *
4416
     * @global string $css CSS directory
4417
     * @global string $img_dir image directory
4418
     * @global string $default_course_dir Course directory
4419
     * @global string $js JS directory
4420
     *
4421
     * @param array $courseData     The course info
4422
     * @param bool  $fromBaseCourse
4423
     * @param int   $sessionId
4424
     */
4425
    public static function generateDefaultCertificate(
4426
        $courseData,
4427
        $fromBaseCourse = false,
4428
        $sessionId = 0
4429
    ) {
4430
        if (empty($courseData)) {
4431
            return false;
4432
        }
4433
4434
        global $css, $img_dir, $default_course_dir, $js;
4435
        $codePath = api_get_path(REL_CODE_PATH);
4436
        $dir = '/certificates';
4437
        $comment = null;
4438
        $title = get_lang('DefaultCertificate');
4439
        $fileName = api_replace_dangerous_char($title);
4440
        $filePath = api_get_path(SYS_COURSE_PATH)."{$courseData['directory']}/document$dir";
4441
4442
        if (!is_dir($filePath)) {
4443
            mkdir($filePath, api_get_permissions_for_new_directories());
4444
        }
4445
4446
        $fileFullPath = "$filePath/$fileName.html";
4447
        $fileType = 'file';
4448
        $templateContent = file_get_contents(api_get_path(SYS_CODE_PATH).'gradebook/certificate_template/template.html');
4449
4450
        $search = ['{CSS}', '{IMG_DIR}', '{REL_CODE_PATH}', '{COURSE_DIR}'];
4451
        $replace = [$css.$js, $img_dir, $codePath, $default_course_dir];
4452
4453
        $fileContent = str_replace($search, $replace, $templateContent);
4454
        $saveFilePath = "$dir/$fileName.html";
4455
4456
        if ($fromBaseCourse) {
4457
            $defaultCertificateId = self::get_default_certificate_id($courseData['real_id'], 0);
4458
            if (!empty($defaultCertificateId)) {
4459
                // We have a certificate from the course base
4460
                $documentData = self::get_document_data_by_id(
4461
                    $defaultCertificateId,
4462
                    $courseData['code'],
4463
                    false,
4464
                    0
4465
                );
4466
4467
                if ($documentData) {
4468
                    $fileContent = file_get_contents($documentData['absolute_path']);
4469
                }
4470
            }
4471
        }
4472
4473
        $document = self::addDocument(
4474
            $courseData,
4475
            $saveFilePath,
4476
            $fileType,
4477
            '',
4478
            $title,
4479
            $comment,
4480
            0, //$readonly = 0,
4481
            true, //$save_visibility = true,
4482
            null, //$group_id = null,
4483
            $sessionId,
4484
            0,
4485
            false,
4486
            $fileContent
4487
        );
4488
4489
        /*api_item_property_update(
4490
            $courseData,
4491
            TOOL_DOCUMENT,
4492
            $documentId,
4493
            'DocumentAdded',
4494
            api_get_user_id(),
4495
            null,
4496
            null,
4497
            null,
4498
            null,
4499
            $sessionId
4500
        );*/
4501
4502
        $defaultCertificateId = self::get_default_certificate_id($courseData['real_id'], $sessionId);
4503
4504
        if (!isset($defaultCertificateId)) {
4505
            self::attach_gradebook_certificate(
4506
                $courseData['real_id'],
4507
                $document->getId(),
4508
                $sessionId
4509
            );
4510
        }
4511
    }
4512
4513
    /**
4514
     * Update the document name.
4515
     *
4516
     * @param int    $documentId The document id
4517
     * @param string $newName    The new name
4518
     */
4519
    public static function renameDocument($documentId, $newName)
4520
    {
4521
        $documentId = intval($documentId);
4522
        $newName = Database::escape_string($newName);
4523
        $docuentTable = Database::get_course_table(TABLE_DOCUMENT);
4524
4525
        $values = [
4526
            'title' => $newName,
4527
        ];
4528
4529
        $whereConditions = [
4530
            'id = ?' => $documentId,
4531
        ];
4532
4533
        Database::update($docuentTable, $values, $whereConditions);
4534
    }
4535
4536
    /**
4537
     * Get folder/file suffix.
4538
     *
4539
     * @param array $courseInfo
4540
     * @param int   $sessionId
4541
     * @param int   $groupId
4542
     *
4543
     * @return string
4544
     */
4545
    public static function getDocumentSuffix($courseInfo, $sessionId, $groupId)
4546
    {
4547
        // If no session or group, then no suffix.
4548
        if (empty($sessionId) && empty($groupId)) {
4549
            return '';
4550
        }
4551
4552
        return '__'.intval($sessionId).'__'.intval($groupId);
4553
    }
4554
4555
    /**
4556
     * Fix a document name adding session id and group id
4557
     * Turns picture.jpg -> picture__1__2.jpg
4558
     * Where 1 = session id and 2 group id
4559
     * Of session id and group id are empty then the function returns:
4560
     * picture.jpg ->  picture.jpg.
4561
     *
4562
     * @param string $name       folder or file name
4563
     * @param string $type       'folder' or 'file'
4564
     * @param array  $courseInfo
4565
     * @param int    $sessionId
4566
     * @param int    $groupId
4567
     *
4568
     * @return string
4569
     */
4570
    public static function fixDocumentName($name, $type, $courseInfo, $sessionId, $groupId)
4571
    {
4572
        $suffix = self::getDocumentSuffix($courseInfo, $sessionId, $groupId);
4573
4574
        switch ($type) {
4575
            case 'folder':
4576
                $name = $name.$suffix;
4577
                break;
4578
            case 'file':
4579
                $name = self::addSuffixToFileName($name, $suffix);
4580
                break;
4581
        }
4582
4583
        return $name;
4584
    }
4585
4586
    /**
4587
     * Add a suffix to a file Example:
4588
     * /folder/picture.jpg => to /folder/picture_this.jpg
4589
     * where "_this" is the suffix.
4590
     *
4591
     * @param string $name
4592
     * @param string $suffix
4593
     *
4594
     * @return string
4595
     */
4596
    public static function addSuffixToFileName($name, $suffix)
4597
    {
4598
        $extension = pathinfo($name, PATHINFO_EXTENSION);
4599
        $fileName = pathinfo($name, PATHINFO_FILENAME);
4600
        $dir = pathinfo($name, PATHINFO_DIRNAME);
4601
4602
        if ($dir == '.') {
4603
            $dir = null;
4604
        }
4605
4606
        if (!empty($dir) && $dir != '/') {
4607
            $dir = $dir.'/';
4608
        }
4609
4610
        $name = $dir.$fileName.$suffix.'.'.$extension;
4611
4612
        return $name;
4613
    }
4614
4615
    /**
4616
     * Check if folder exist in the course base or in the session course.
4617
     *
4618
     * @param string $folder     Example: /folder/folder2
4619
     * @param array  $courseInfo
4620
     * @param int    $sessionId
4621
     * @param int    $groupId    group.id
4622
     *
4623
     * @return bool
4624
     */
4625
    public static function folderExists(
4626
        $folder,
4627
        $courseInfo,
4628
        $sessionId,
4629
        $groupId
4630
    ) {
4631
        $courseId = $courseInfo['real_id'];
4632
4633
        if (empty($courseId)) {
4634
            return false;
4635
        }
4636
4637
        $sessionId = intval($sessionId);
4638
        $folderWithSuffix = self::fixDocumentName(
4639
            $folder,
4640
            'folder',
4641
            $courseInfo,
4642
            $sessionId,
4643
            $groupId
4644
        );
4645
4646
        $folder = Database::escape_string($folder);
4647
        $folderWithSuffix = Database::escape_string($folderWithSuffix);
4648
4649
        // Check if pathname already exists inside document table
4650
        $tbl_document = Database::get_course_table(TABLE_DOCUMENT);
4651
        $sql = "SELECT id, path FROM $tbl_document
4652
                WHERE
4653
                    filetype = 'folder' AND
4654
                    c_id = $courseId AND
4655
                    (path = '$folder' OR path = '$folderWithSuffix') AND
4656
                    (session_id = 0 OR session_id = $sessionId)
4657
        ";
4658
4659
        $rs = Database::query($sql);
4660
        if (Database::num_rows($rs)) {
4661
            return true;
4662
        }
4663
4664
        return false;
4665
    }
4666
4667
    /**
4668
     * Check if file exist in the course base or in the session course.
4669
     *
4670
     * @param string $fileName   Example: /folder/picture.jpg
4671
     * @param array  $courseInfo
4672
     * @param int    $sessionId
4673
     * @param int    $groupId
4674
     *
4675
     * @return bool
4676
     */
4677
    public static function documentExists(
4678
        $fileName,
4679
        $courseInfo,
4680
        $sessionId,
4681
        $groupId
4682
    ) {
4683
        $courseId = $courseInfo['real_id'];
4684
4685
        if (empty($courseId)) {
4686
            return false;
4687
        }
4688
4689
        $sessionId = intval($sessionId);
4690
        $fileNameEscape = Database::escape_string($fileName);
4691
4692
        $fileNameWithSuffix = self::fixDocumentName(
4693
            $fileName,
4694
            'file',
4695
            $courseInfo,
4696
            $sessionId,
4697
            $groupId
4698
        );
4699
4700
        $fileNameWithSuffix = Database::escape_string($fileNameWithSuffix);
4701
4702
        // Check if pathname already exists inside document table
4703
        $table = Database::get_course_table(TABLE_DOCUMENT);
4704
        $sql = "SELECT id, path FROM $table
4705
                WHERE
4706
                    filetype = 'file' AND
4707
                    c_id = $courseId AND
4708
                    (
4709
                        path = '".$fileNameEscape."' OR
4710
                        path = '$fileNameWithSuffix'
4711
                    ) AND
4712
                    (session_id = 0 OR session_id = $sessionId)
4713
        ";
4714
        $rs = Database::query($sql);
4715
        if (Database::num_rows($rs)) {
4716
            return true;
4717
        }
4718
4719
        return false;
4720
    }
4721
4722
    /**
4723
     * Undo the suffix applied to a file example:
4724
     * turns picture__1__1.jpg to picture.jpg.
4725
     *
4726
     * @param string $name
4727
     * @param int    $courseId
4728
     * @param int    $sessionId
4729
     * @param int    $groupId
4730
     *
4731
     * @return string
4732
     */
4733
    public static function undoFixDocumentName(
4734
        $name,
4735
        $courseId,
4736
        $sessionId,
4737
        $groupId
4738
    ) {
4739
        if (empty($sessionId) && empty($groupId)) {
4740
            return $name;
4741
        }
4742
4743
        $suffix = self::getDocumentSuffix(
4744
            ['real_id' => $courseId],
4745
            $sessionId,
4746
            $groupId
4747
        );
4748
4749
        $name = str_replace($suffix, '', $name);
4750
4751
        return $name;
4752
    }
4753
4754
    /**
4755
     * @param string $path
4756
     * @param string $name
4757
     * @param array  $courseInfo
4758
     * @param int    $sessionId
4759
     * @param int    $groupId
4760
     *
4761
     * @return string
4762
     */
4763
    public static function getUniqueFileName($path, $name, $courseInfo, $sessionId, $groupId)
4764
    {
4765
        $counter = 1;
4766
        $filePath = $path.$name;
4767
        $uniqueName = $name;
4768
        while ($documentExists = self::documentExists(
4769
            $filePath,
4770
            $courseInfo,
4771
            $sessionId,
4772
            $groupId
4773
        )) {
4774
            $uniqueName = self::addSuffixToFileName($name, '_'.$counter);
4775
            $filePath = $path.$uniqueName;
4776
            $counter++;
4777
        }
4778
4779
        return $uniqueName;
4780
    }
4781
4782
    /**
4783
     * Builds the form that enables the user to
4784
     * select a directory to browse/upload in.
4785
     *
4786
     * @param array    An array containing the folders we want to be able to select
4787
     * @param string    The current folder (path inside of the "document" directory, including the prefix "/")
4788
     * @param string    Group directory, if empty, prevents documents to be uploaded
4789
     * (because group documents cannot be uploaded in root)
4790
     * @param bool    Whether to change the renderer (this will add a template <span>
4791
     * to the QuickForm object displaying the form)
4792
     *
4793
     * @return string html form
4794
     */
4795
    public static function build_directory_selector(
4796
        $folders,
4797
        $document_id,
4798
        $group_dir = '',
4799
        $change_renderer = false,
4800
        &$form = null,
4801
        $selectName = 'id'
4802
    ) {
4803
        $doc_table = Database::get_course_table(TABLE_DOCUMENT);
4804
        $course_id = api_get_course_int_id();
4805
        $folder_titles = [];
4806
4807
        if (is_array($folders)) {
4808
            $escaped_folders = [];
4809
            foreach ($folders as $key => &$val) {
4810
                $escaped_folders[$key] = Database::escape_string($val);
4811
            }
4812
            $folder_sql = implode("','", $escaped_folders);
4813
4814
            $sql = "SELECT path, title 
4815
                    FROM $doc_table
4816
                    WHERE 
4817
                        filetype = 'folder' AND 
4818
                        c_id = $course_id AND 
4819
                        path IN ('".$folder_sql."')";
4820
            $res = Database::query($sql);
4821
            $folder_titles = [];
4822
            while ($obj = Database::fetch_object($res)) {
4823
                $folder_titles[$obj->path] = $obj->title;
4824
            }
4825
        }
4826
4827
        $attributes = [];
4828
        if (empty($form)) {
4829
            $form = new FormValidator('selector', 'GET', api_get_self().'?'.api_get_cidreq());
4830
            $attributes = ['onchange' => 'javascript: document.selector.submit();'];
4831
        }
4832
        $form->addElement('hidden', 'cidReq', api_get_course_id());
4833
        $parent_select = $form->addSelect(
4834
            $selectName,
4835
            get_lang('CurrentDirectory'),
4836
            '',
4837
            $attributes
4838
        );
4839
4840
        // Group documents cannot be uploaded in the root
4841
        if (empty($group_dir)) {
4842
            $parent_select->addOption(get_lang('Documents'), '/');
4843
4844
            if (is_array($folders)) {
4845
                foreach ($folders as $folder_id => &$folder) {
4846
                    $selected = ($document_id == $folder_id) ? ' selected="selected"' : '';
4847
                    $path_parts = explode('/', $folder);
4848
                    $folder_titles[$folder] = cut($folder_titles[$folder], 80);
4849
                    $counter = count($path_parts) - 2;
4850
                    if ($counter > 0) {
4851
                        $label = str_repeat('&nbsp;&nbsp;&nbsp;', $counter).' &mdash; '.$folder_titles[$folder];
4852
                    } else {
4853
                        $label = ' &mdash; '.$folder_titles[$folder];
4854
                    }
4855
                    $parent_select->addOption($label, $folder_id);
4856
                    if ($selected != '') {
4857
                        $parent_select->setSelected($folder_id);
4858
                    }
4859
                }
4860
            }
4861
        } else {
4862
            if (!empty($folders)) {
4863
                foreach ($folders as $folder_id => &$folder) {
4864
                    $selected = ($document_id == $folder_id) ? ' selected="selected"' : '';
4865
                    $label = $folder_titles[$folder];
4866
                    if ($folder == $group_dir) {
4867
                        $label = get_lang('Documents');
4868
                    } else {
4869
                        $path_parts = explode('/', str_replace($group_dir, '', $folder));
4870
                        $label = cut($label, 80);
4871
                        $label = str_repeat('&nbsp;&nbsp;&nbsp;', count($path_parts) - 2).' &mdash; '.$label;
4872
                    }
4873
                    $parent_select->addOption($label, $folder_id);
4874
                    if ($selected != '') {
4875
                        $parent_select->setSelected($folder_id);
4876
                    }
4877
                }
4878
            }
4879
        }
4880
4881
        $html = $form->toHtml();
4882
4883
        return $html;
4884
    }
4885
4886
    /**
4887
     * Create a html hyperlink depending on if it's a folder or a file.
4888
     *
4889
     * @param string $documentWebPath
4890
     * @param array  $document_data
4891
     * @param bool   $show_as_icon      - if it is true, only a clickable icon will be shown
4892
     * @param int    $visibility        (1/0)
4893
     * @param int    $counter
4894
     * @param int    $size
4895
     * @param bool   $isAllowedToEdit
4896
     * @param bool   $isCertificateMode
4897
     *
4898
     * @return string url
4899
     */
4900
    public static function create_document_link(
4901
        $documentWebPath,
4902
        $document_data,
4903
        $show_as_icon = false,
4904
        $counter = null,
4905
        $visibility,
4906
        $size = 0,
4907
        $isAllowedToEdit = false,
4908
        $isCertificateMode = false
4909
    ) {
4910
        global $dbl_click_id;
4911
        $www = $documentWebPath;
4912
4913
        $sessionId = api_get_session_id();
4914
        $courseParams = api_get_cidreq();
4915
        $webODFList = self::get_web_odf_extension_list();
4916
4917
        // Get the title or the basename depending on what we're using
4918
        if ($document_data['title'] != '') {
4919
            $title = $document_data['title'];
4920
        } else {
4921
            $title = basename($document_data['path']);
4922
        }
4923
4924
        $filetype = $document_data['filetype'];
4925
        $path = $document_data['path'];
4926
        $url_path = urlencode($document_data['path']);
4927
4928
        // Add class="invisible" on invisible files
4929
        $visibility_class = $visibility == false ? ' class="muted"' : '';
4930
        $forcedownload_link = '';
4931
        $forcedownload_icon = '';
4932
        $prevent_multiple_click = '';
4933
        $force_download_html = '';
4934
4935
        if (!$show_as_icon) {
4936
            // Build download link (icon)
4937
            $forcedownload_link = $filetype == 'folder' ? api_get_self().'?'.$courseParams.'&action=downloadfolder&id='.$document_data['id'] : api_get_self().'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
4938
            // Folder download or file download?
4939
            $forcedownload_icon = $filetype == 'folder' ? 'save_pack.png' : 'save.png';
4940
            // Prevent multiple clicks on zipped folder download
4941
            $prevent_multiple_click = $filetype == 'folder' ? " onclick=\"javascript: if(typeof clic_$dbl_click_id == 'undefined' || !clic_$dbl_click_id) { clic_$dbl_click_id=true; window.setTimeout('clic_".($dbl_click_id++)."=false;',10000); } else { return false; }\"" : '';
4942
        }
4943
4944
        $target = '_self';
4945
        $is_browser_viewable_file = false;
4946
4947
        if ($filetype == 'file') {
4948
            // Check the extension
4949
            $ext = explode('.', $path);
4950
            $ext = strtolower($ext[sizeof($ext) - 1]);
4951
4952
            // HTML-files an some other types are shown in a frameset by default.
4953
            $is_browser_viewable_file = self::isBrowserViewable($ext);
4954
            if ($is_browser_viewable_file) {
4955
                if ($ext == 'pdf' || in_array($ext, $webODFList)) {
4956
                    $url = api_get_self().'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
4957
                } else {
4958
                    $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
4959
                }
4960
            } else {
4961
                // url-encode for problematic characters (we may not call them dangerous characters...)
4962
                //$path = str_replace('%2F', '/', $url_path).'?'.$courseParams;
4963
                $url = $www.str_replace('%2F', '/', $url_path).'?'.$courseParams;
4964
            }
4965
        } else {
4966
            $url = api_get_self().'?'.$courseParams.'&id='.$document_data['id'];
4967
        }
4968
4969
        if ($isCertificateMode) {
4970
            $url .= '&certificate=true&selectcat='.(isset($_GET['selectcat']) ? $_GET['selectcat'] : '');
4971
        }
4972
4973
        // The little download icon
4974
        $tooltip_title = $title;
4975
        $tooltip_title_alt = $tooltip_title;
4976
4977
        if ($filetype == 'link') {
4978
            $tooltip_title_alt = $title;
4979
            $url = $document_data['comment'].'" target="_blank';
4980
        }
4981
4982
        if ($path == '/shared_folder') {
4983
            $tooltip_title_alt = get_lang('UserFolders');
4984
        } elseif (strstr($path, 'shared_folder_session_')) {
4985
            $tooltip_title_alt = get_lang('UserFolders').' ('.api_get_session_name(api_get_session_id()).')';
4986
        } elseif (strstr($tooltip_title, 'sf_user_')) {
4987
            $userinfo = api_get_user_info(substr($tooltip_title, 8));
4988
            $tooltip_title_alt = get_lang('UserFolder').' '.$userinfo['complete_name'];
4989
        } elseif ($path == '/chat_files') {
4990
            $tooltip_title_alt = get_lang('ChatFiles');
4991
        } elseif ($path == '/learning_path') {
4992
            $tooltip_title_alt = get_lang('LearningPaths');
4993
        } elseif ($path == '/video') {
4994
            $tooltip_title_alt = get_lang('Video');
4995
        } elseif ($path == '/audio') {
4996
            $tooltip_title_alt = get_lang('Audio');
4997
        } elseif ($path == '/flash') {
4998
            $tooltip_title_alt = get_lang('Flash');
4999
        } elseif ($path == '/images') {
5000
            $tooltip_title_alt = get_lang('Images');
5001
        } elseif ($path == '/images/gallery') {
5002
            $tooltip_title_alt = get_lang('DefaultCourseImages');
5003
        }
5004
5005
        $copyToMyFiles = $open_in_new_window_link = '';
5006
        $curdirpath = isset($_GET['curdirpath']) ? Security::remove_XSS($_GET['curdirpath']) : null;
5007
        $send_to = null;
5008
        $checkExtension = $path;
5009
        $extension = pathinfo($path, PATHINFO_EXTENSION);
5010
        $document_data['file_extension'] = $extension;
5011
5012
        if (!$show_as_icon) {
5013
            if ($filetype == 'folder') {
5014
                if ($isAllowedToEdit ||
5015
                    api_is_platform_admin() ||
5016
                    api_get_setting('students_download_folders') == 'true'
5017
                ) {
5018
                    // filter: when I am into a shared folder, I can only show "my shared folder" for donwload
5019
                    if (self::is_shared_folder($curdirpath, $sessionId)) {
5020
                        if (preg_match('/shared_folder\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
5021
                            preg_match('/shared_folder_session_'.$sessionId.'\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
5022
                            $isAllowedToEdit || api_is_platform_admin()
5023
                        ) {
5024
                            $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.'>'.
5025
                                Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
5026
                        }
5027
                    } elseif (!preg_match('/shared_folder/', urldecode($forcedownload_link)) ||
5028
                        $isAllowedToEdit ||
5029
                        api_is_platform_admin()
5030
                    ) {
5031
                        $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.'>'.
5032
                            Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
5033
                    }
5034
                }
5035
            } else {
5036
                $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.' download="'.$document_data['basename'].'">'.
5037
                    Display::return_icon($forcedownload_icon, get_lang('Download'), [], ICON_SIZE_SMALL).'</a>';
5038
            }
5039
5040
            // Copy files to user's myfiles
5041
            if (api_get_setting('allow_my_files') === 'true' &&
5042
                api_get_setting('users_copy_files') === 'true' && api_is_anonymous() === false
5043
            ) {
5044
                $copy_myfiles_link = $filetype == 'file' ? api_get_self().'?'.$courseParams.'&action=copytomyfiles&id='.$document_data['id'] : api_get_self().'?'.$courseParams;
5045
                if ($filetype == 'file') {
5046
                    /*$copyToMyFiles = '<a href="'.$copy_myfiles_link.'" style="float:right"'.$prevent_multiple_click.'>'.
5047
                        Display::return_icon('briefcase.png', get_lang('CopyToMyFiles'), [], ICON_SIZE_SMALL).'&nbsp;&nbsp;</a>';
5048
5049
                    if (api_get_setting('allow_my_files') === 'false') {
5050
                        $copyToMyFiles = '';
5051
                    }*/
5052
                }
5053
            }
5054
5055
            $pdf_icon = '';
5056
            if (!$isAllowedToEdit &&
5057
                api_get_setting('students_export2pdf') == 'true' &&
5058
                $filetype == 'file' &&
5059
                in_array($extension, ['html', 'htm'])
5060
            ) {
5061
                $pdf_icon = ' <a style="float:right".'.$prevent_multiple_click.' href="'.api_get_self().'?'.$courseParams.'&action=export_to_pdf&id='.$document_data['id'].'&curdirpath='.$curdirpath.'">'.
5062
                    Display::return_icon('pdf.png', get_lang('Export2PDF'), [], ICON_SIZE_SMALL).'</a> ';
5063
            }
5064
5065
            if ($is_browser_viewable_file) {
5066
                $open_in_new_window_link = '<a href="'.$www.str_replace('%2F', '/', $url_path).'?'.$courseParams.'" style="float:right"'.$prevent_multiple_click.' target="_blank">'.
5067
                    Display::return_icon('open_in_new_window.png', get_lang('OpenInANewWindow'), [], ICON_SIZE_SMALL).'&nbsp;&nbsp;</a>';
5068
            }
5069
5070
            if ($filetype == 'file') {
5071
                // Sound preview
5072
                if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
5073
                    (preg_match('/wav$/i', urldecode($checkExtension))) ||
5074
                    preg_match('/ogg$/i', urldecode($checkExtension))
5075
                ) {
5076
                    return '<span style="float:left" '.$visibility_class.'>'.
5077
                    $title.
5078
                    '</span>'.$force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
5079
                } elseif (
5080
                    // Show preview
5081
                    preg_match('/swf$/i', urldecode($checkExtension)) ||
5082
                    preg_match('/png$/i', urldecode($checkExtension)) ||
5083
                    preg_match('/gif$/i', urldecode($checkExtension)) ||
5084
                    preg_match('/jpg$/i', urldecode($checkExtension)) ||
5085
                    preg_match('/jpeg$/i', urldecode($checkExtension)) ||
5086
                    preg_match('/bmp$/i', urldecode($checkExtension)) ||
5087
                    preg_match('/svg$/i', urldecode($checkExtension))
5088
                ) {
5089
                    // Simpler version of showinframesmin.php with no headers
5090
                    $url = 'show_content.php?'.$courseParams.'&id='.$document_data['id'];
5091
                    $class = 'ajax';
5092
                    if ($visibility == false) {
5093
                        $class = "ajax text-muted";
5094
                    }
5095
5096
                    return Display::url(
5097
                        $title,
5098
                        $url,
5099
                        [
5100
                            'class' => $class,
5101
                            'title' => $tooltip_title_alt,
5102
                            'data-title' => $title,
5103
                            'style' => 'float:left;',
5104
                        ]
5105
                    )
5106
                    .$force_download_html.$send_to.$copyToMyFiles
5107
                    .$open_in_new_window_link.$pdf_icon;
5108
                } else {
5109
                    // For a "PDF Download" of the file.
5110
                    $pdfPreview = null;
5111
                    if ($ext != 'pdf' && !in_array($ext, $webODFList)) {
5112
                        $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
5113
                    } else {
5114
                        $pdfPreview = Display::url(
5115
                            Display::return_icon('preview.png', get_lang('Preview'), null, ICON_SIZE_SMALL),
5116
                            api_get_path(WEB_CODE_PATH).'document/showinframes.php?'.$courseParams.'&id='.$document_data['id'],
5117
                            ['style' => 'float:right']
5118
                        );
5119
                    }
5120
                    // No plugin just the old and good showinframes.php page
5121
                    return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" style="float:left" '.$visibility_class.' >'.$title.'</a>'.
5122
                    $pdfPreview.$force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
5123
                }
5124
            } else {
5125
                return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.$title.'</a>'.
5126
                $force_download_html.$send_to.$copyToMyFiles.$open_in_new_window_link.$pdf_icon;
5127
            }
5128
            // end copy files to users myfiles
5129
        } else {
5130
            // Icon column
5131
            if (preg_match('/shared_folder/', urldecode($checkExtension)) &&
5132
                preg_match('/shared_folder$/', urldecode($checkExtension)) == false &&
5133
                preg_match('/shared_folder_session_'.$sessionId.'$/', urldecode($url)) == false
5134
            ) {
5135
                if ($filetype == 'file') {
5136
                    //Sound preview
5137
                    if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
5138
                        (preg_match('/wav$/i', urldecode($checkExtension))) ||
5139
                        preg_match('/ogg$/i', urldecode($checkExtension))) {
5140
                        $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
5141
5142
                        return $soundPreview;
5143
                    } elseif (
5144
                        // Show preview
5145
                        preg_match('/swf$/i', urldecode($checkExtension)) ||
5146
                        preg_match('/png$/i', urldecode($checkExtension)) ||
5147
                        preg_match('/gif$/i', urldecode($checkExtension)) ||
5148
                        preg_match('/jpg$/i', urldecode($checkExtension)) ||
5149
                        preg_match('/jpeg$/i', urldecode($checkExtension)) ||
5150
                        preg_match('/bmp$/i', urldecode($checkExtension)) ||
5151
                        preg_match('/svg$/i', urldecode($checkExtension))
5152
                    ) {
5153
                        $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id'];
5154
5155
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5156
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5157
                            Display::return_icon('shared.png', get_lang('ResourceShared'), []).
5158
                        '</a>';
5159
                    } else {
5160
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5161
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5162
                            Display::return_icon('shared.png', get_lang('ResourceShared'), []).
5163
                        '</a>';
5164
                    }
5165
                } else {
5166
                    return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" target="'.$target.'"'.$visibility_class.' style="float:left">'.
5167
                        self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5168
                        Display::return_icon('shared.png', get_lang('ResourceShared'), []).
5169
                    '</a>';
5170
                }
5171
            } else {
5172
                if ($filetype == 'file') {
5173
                    // Sound preview with jplayer
5174
                    if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
5175
                        (preg_match('/wav$/i', urldecode($checkExtension))) ||
5176
                        preg_match('/ogg$/i', urldecode($checkExtension))) {
5177
                        $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
5178
5179
                        return $soundPreview;
5180
                    } elseif (
5181
                        //Show preview
5182
                        preg_match('/html$/i', urldecode($checkExtension)) ||
5183
                        preg_match('/htm$/i', urldecode($checkExtension)) ||
5184
                        preg_match('/swf$/i', urldecode($checkExtension)) ||
5185
                        preg_match('/png$/i', urldecode($checkExtension)) ||
5186
                        preg_match('/gif$/i', urldecode($checkExtension)) ||
5187
                        preg_match('/jpg$/i', urldecode($checkExtension)) ||
5188
                        preg_match('/jpeg$/i', urldecode($checkExtension)) ||
5189
                        preg_match('/bmp$/i', urldecode($checkExtension)) ||
5190
                        preg_match('/svg$/i', urldecode($checkExtension))
5191
                    ) {
5192
                        $url = 'showinframes.php?'.$courseParams.'&id='.$document_data['id']; //without preview
5193
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5194
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5195
                        '</a>';
5196
                    } else {
5197
                        return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" '.$visibility_class.' style="float:left">'.
5198
                            self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5199
                        '</a>';
5200
                    }
5201
                } else {
5202
                    return '<a href="'.$url.'" title="'.$tooltip_title_alt.'" target="'.$target.'"'.$visibility_class.' style="float:left">'.
5203
                        self::build_document_icon_tag($filetype, $path, $isAllowedToEdit).
5204
                    '</a>';
5205
                }
5206
            }
5207
        }
5208
    }
5209
5210
    /**
5211
     * Builds an img html tag for the file type.
5212
     *
5213
     * @param string $type            (file/folder)
5214
     * @param string $path
5215
     * @param bool   $isAllowedToEdit
5216
     *
5217
     * @return string img html tag
5218
     */
5219
    public static function build_document_icon_tag($type, $path, $isAllowedToEdit = null)
5220
    {
5221
        $basename = basename($path);
5222
        $sessionId = api_get_session_id();
5223
        if (is_null($isAllowedToEdit)) {
5224
            $isAllowedToEdit = api_is_allowed_to_edit(null, true);
5225
        }
5226
        $user_image = false;
5227
        if ($type == 'file') {
5228
            $icon = choose_image($basename);
5229
            $basename = substr(strrchr($basename, '.'), 1);
5230
        } elseif ($type == 'link') {
5231
            $icon = 'clouddoc.png';
5232
            $basename = get_lang('CloudFileLink');
5233
        } else {
5234
            if ($path == '/shared_folder') {
5235
                $icon = 'folder_users.png';
5236
                if ($isAllowedToEdit) {
5237
                    $basename = get_lang('HelpUsersFolder');
5238
                } else {
5239
                    $basename = get_lang('UserFolders');
5240
                }
5241
            } elseif (strstr($basename, 'sf_user_')) {
5242
                $userInfo = api_get_user_info(substr($basename, 8));
5243
                $icon = $userInfo['avatar_small'];
5244
                $basename = get_lang('UserFolder').' '.$userInfo['complete_name'];
5245
                $user_image = true;
5246
            } elseif (strstr($path, 'shared_folder_session_')) {
5247
                $sessionName = api_get_session_name($sessionId);
5248
                if ($isAllowedToEdit) {
5249
                    $basename = '***('.$sessionName.')*** '.get_lang('HelpUsersFolder');
5250
                } else {
5251
                    $basename = get_lang('UserFolders').' ('.$sessionName.')';
5252
                }
5253
                $icon = 'folder_users.png';
5254
            } else {
5255
                $icon = 'folder_document.png';
5256
5257
                if ($path == '/audio') {
5258
                    $icon = 'folder_audio.png';
5259
                    if ($isAllowedToEdit) {
5260
                        $basename = get_lang('HelpDefaultDirDocuments');
5261
                    } else {
5262
                        $basename = get_lang('Audio');
5263
                    }
5264
                } elseif ($path == '/flash') {
5265
                    $icon = 'folder_flash.png';
5266
                    if ($isAllowedToEdit) {
5267
                        $basename = get_lang('HelpDefaultDirDocuments');
5268
                    } else {
5269
                        $basename = get_lang('Flash');
5270
                    }
5271
                } elseif ($path == '/images') {
5272
                    $icon = 'folder_images.png';
5273
                    if ($isAllowedToEdit) {
5274
                        $basename = get_lang('HelpDefaultDirDocuments');
5275
                    } else {
5276
                        $basename = get_lang('Images');
5277
                    }
5278
                } elseif ($path == '/video') {
5279
                    $icon = 'folder_video.png';
5280
                    if ($isAllowedToEdit) {
5281
                        $basename = get_lang('HelpDefaultDirDocuments');
5282
                    } else {
5283
                        $basename = get_lang('Video');
5284
                    }
5285
                } elseif ($path == '/images/gallery') {
5286
                    $icon = 'folder_gallery.png';
5287
                    if ($isAllowedToEdit) {
5288
                        $basename = get_lang('HelpDefaultDirDocuments');
5289
                    } else {
5290
                        $basename = get_lang('Gallery');
5291
                    }
5292
                } elseif ($path == '/chat_files') {
5293
                    $icon = 'folder_chat.png';
5294
                    if ($isAllowedToEdit) {
5295
                        $basename = get_lang('HelpFolderChat');
5296
                    } else {
5297
                        $basename = get_lang('ChatFiles');
5298
                    }
5299
                } elseif ($path == '/learning_path') {
5300
                    $icon = 'folder_learningpath.png';
5301
                    if ($isAllowedToEdit) {
5302
                        $basename = get_lang('HelpFolderLearningPaths');
5303
                    } else {
5304
                        $basename = get_lang('LearningPaths');
5305
                    }
5306
                }
5307
            }
5308
        }
5309
5310
        if ($user_image) {
5311
            return Display::img($icon, $basename, [], false);
5312
        }
5313
5314
        return Display::return_icon($icon, $basename, [], ICON_SIZE_SMALL);
5315
    }
5316
5317
    /**
5318
     * Creates the row of edit icons for a file/folder.
5319
     *
5320
     * @param array $document_data
5321
     * @param int   $id
5322
     * @param bool  $is_template
5323
     * @param int   $is_read_only
5324
     * @param int   $visibility    (1/0)
5325
     *
5326
     * @return string html img tags with hyperlinks
5327
     */
5328
    public static function build_edit_icons($document_data, $id, $is_template, $is_read_only = 0, $visibility)
5329
    {
5330
        $sessionId = api_get_session_id();
5331
        $courseParams = api_get_cidreq();
5332
        $document_id = $document_data['id'];
5333
        $type = $document_data['filetype'];
5334
        $is_read_only = $document_data['readonly'];
5335
        $path = $document_data['path'];
5336
5337
        if ($type == 'link') {
5338
            $parent_id = self::get_document_id(
5339
                api_get_course_info(),
5340
                rtrim($path, '/'),
5341
                0
5342
            );
5343
        } else {
5344
            $parent_id = self::get_document_id(
5345
                api_get_course_info(),
5346
                dirname($path),
5347
                0
5348
            );
5349
        }
5350
5351
        if (empty($parent_id) && !empty($sessionId)) {
5352
            $parent_id = self::get_document_id(
5353
                api_get_course_info(),
5354
                dirname($path),
5355
                $sessionId
5356
            );
5357
        }
5358
5359
        $curdirpath = dirname($document_data['path']);
5360
        $is_certificate_mode = self::is_certificate_mode($path);
5361
        $curdirpath = urlencode($curdirpath);
5362
        $extension = pathinfo($path, PATHINFO_EXTENSION);
5363
        //@todo Implement remote support for converter
5364
        $usePpt2lp = api_get_setting('service_ppt2lp', 'active') == 'true' && api_get_setting('service_ppt2lp', 'host') == 'localhost';
5365
        $formatTypeList = self::getFormatTypeListConvertor('from', $extension);
5366
        $formatType = current($formatTypeList);
5367
5368
        // If document is read only *or* we're in a session and the document
5369
        // is from a non-session context, hide the edition capabilities
5370
        $modify_icons = [];
5371
        $modify_icons[] = self::getButtonEdit($is_read_only, $document_data, $extension, $is_certificate_mode);
5372
        $modify_icons[] = self::getButtonMove($is_read_only, $document_data, $is_certificate_mode, $parent_id);
5373
        $modify_icons[] = self::getButtonVisibility(
5374
            $is_read_only,
5375
            $visibility,
5376
            $document_data,
5377
            $is_certificate_mode,
5378
            $parent_id
5379
        );
5380
        $modify_icons[] = self::getButtonDelete(
5381
            $is_read_only,
5382
            $document_data,
5383
            $is_certificate_mode,
5384
            $curdirpath,
5385
            $parent_id
5386
        );
5387
5388
        if (!$is_read_only /* or ($session_id!=api_get_session_id()) */) {
5389
            // Add action to covert to PDF, will create a new document whit same filename but .pdf extension
5390
            // @TODO: add prompt to select a format target
5391
            if (!in_array($path, self::get_system_folders())) {
5392
                if ($usePpt2lp && $formatType) {
5393
                    $modify_icons[] = Display::url(
5394
                        Display::return_icon('convert.png', get_lang('Convert')),
5395
                        '#',
5396
                        ['class' => 'convertAction', 'data-documentId' => $document_id, 'data-formatType' => $formatType]
5397
                    );
5398
                }
5399
            }
5400
        }
5401
5402
        if ($type == 'file' && ($extension == 'html' || $extension == 'htm')) {
5403
            if ($is_template == 0) {
5404
                if ((isset($_GET['curdirpath']) && $_GET['curdirpath'] != '/certificates') || !isset($_GET['curdirpath'])) {
5405
                    $modify_icons[] = Display::url(
5406
                        Display::return_icon('wizard.png', get_lang('AddAsTemplate')),
5407
                        api_get_self()."?$courseParams&curdirpath=$curdirpath&add_as_template=$id"
5408
                    );
5409
                }
5410
                if ((isset($_GET['curdirpath']) && $_GET['curdirpath'] == '/certificates') || $is_certificate_mode) {//allow attach certificate to course
5411
                    $visibility_icon_certificate = 'nocertificate';
5412
                    if (self::get_default_certificate_id(api_get_course_int_id()) == $id) {
5413
                        $visibility_icon_certificate = 'certificate';
5414
                        $certificate = get_lang('DefaultCertificate');
5415
                        $preview = get_lang('PreviewCertificate');
5416
                        $is_preview = true;
5417
                    } else {
5418
                        $is_preview = false;
5419
                        $certificate = get_lang('NoDefaultCertificate');
5420
                    }
5421
                    if (isset($_GET['selectcat'])) {
5422
                        $modify_icons[] = Display::url(
5423
                            Display::return_icon($visibility_icon_certificate.'.png', $certificate),
5424
                            api_get_self()."?$courseParams&curdirpath=$curdirpath&selectcat=".intval($_GET['selectcat'])."&set_certificate=$id"
5425
                        );
5426
                        if ($is_preview) {
5427
                            $modify_icons[] = Display::url(
5428
                                Display::return_icon('preview_view.png', $preview),
5429
                                api_get_self()."?$courseParams&curdirpath=$curdirpath&set_preview=$id"
5430
                            );
5431
                        }
5432
                    }
5433
                }
5434
            } else {
5435
                $modify_icons[] = Display::url(
5436
                    Display::return_icon('wizard_na.png', get_lang('RemoveAsTemplate')),
5437
                    api_get_self()."?$courseParams&curdirpath=$curdirpath&remove_as_template=$id"
5438
                );
5439
            }
5440
5441
            $modify_icons[] = Display::url(
5442
                Display::return_icon('pdf.png', get_lang('Export2PDF')),
5443
                api_get_self()."?$courseParams&action=export_to_pdf&id=$id&curdirpath=$curdirpath"
5444
            );
5445
        }
5446
5447
        return implode(PHP_EOL, $modify_icons);
5448
    }
5449
5450
    /**
5451
     * @param $folders
5452
     * @param $curdirpath
5453
     * @param $move_file
5454
     * @param string $group_dir
5455
     *
5456
     * @return string
5457
     */
5458
    public static function build_move_to_selector($folders, $curdirpath, $move_file, $group_dir = '')
5459
    {
5460
        $form = new FormValidator('move_to', 'post', api_get_self().'?'.api_get_cidreq());
5461
5462
        // Form title
5463
        $form->addHidden('move_file', $move_file);
5464
5465
        $options = [];
5466
5467
        // Group documents cannot be uploaded in the root
5468
        if ($group_dir == '') {
5469
            if ($curdirpath != '/') {
5470
                $options['/'] = get_lang('Documents');
5471
            }
5472
5473
            if (is_array($folders)) {
5474
                foreach ($folders as &$folder) {
5475
                    // Hide some folders
5476
                    if ($folder == '/HotPotatoes_files' ||
5477
                        $folder == '/certificates' ||
5478
                        basename($folder) == 'css'
5479
                    ) {
5480
                        continue;
5481
                    }
5482
                    // Admin setting for Hide/Show the folders of all users
5483
                    if (api_get_setting('show_users_folders') == 'false' &&
5484
                        (strstr($folder, '/shared_folder') || strstr($folder, 'shared_folder_session_'))
5485
                    ) {
5486
                        continue;
5487
                    }
5488
5489
                    // Admin setting for Hide/Show Default folders to all users
5490
                    if (api_get_setting('show_default_folders') == 'false' &&
5491
                        (
5492
                            $folder == '/images' ||
5493
                            $folder == '/flash' ||
5494
                            $folder == '/audio' ||
5495
                            $folder == '/video' ||
5496
                            strstr($folder, '/images/gallery') ||
5497
                            $folder == '/video/flv'
5498
                        )
5499
                    ) {
5500
                        continue;
5501
                    }
5502
5503
                    // Admin setting for Hide/Show chat history folder
5504
                    if (api_get_setting('show_chat_folder') == 'false' &&
5505
                        $folder == '/chat_files') {
5506
                        continue;
5507
                    }
5508
5509
                    // You cannot move a file to:
5510
                    // 1. current directory
5511
                    // 2. inside the folder you want to move
5512
                    // 3. inside a subfolder of the folder you want to move
5513
                    if (($curdirpath != $folder) &&
5514
                        ($folder != $move_file) &&
5515
                        (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
5516
                    ) {
5517
                        $path_displayed = $folder;
5518
                        // If document title is used, we have to display titles instead of real paths...
5519
                        $path_displayed = self::get_titles_of_path($folder);
5520
5521
                        if (empty($path_displayed)) {
5522
                            $path_displayed = get_lang('Untitled');
5523
                        }
5524
                        $options[$folder] = $path_displayed;
5525
                    }
5526
                }
5527
            }
5528
        } else {
5529
            foreach ($folders as $folder) {
5530
                if (($curdirpath != $folder) &&
5531
                    ($folder != $move_file) &&
5532
                    (substr($folder, 0, strlen($move_file) + 1) != $move_file.'/')
5533
                ) {
5534
                    // Cannot copy dir into his own subdir
5535
                    $path_displayed = self::get_titles_of_path($folder);
5536
                    $display_folder = substr($path_displayed, strlen($group_dir));
5537
                    $display_folder = ($display_folder == '') ? get_lang('Documents') : $display_folder;
5538
                    //$form .= '<option value="'.$folder.'">'.$display_folder.'</option>';
5539
                    $options[$folder] = $display_folder;
5540
                }
5541
            }
5542
        }
5543
        $form->addElement('select', 'move_to', get_lang('MoveTo'), $options);
5544
        $form->addButtonNext(get_lang('MoveElement'), 'move_file_submit');
5545
5546
        return $form->returnForm();
5547
    }
5548
5549
    /**
5550
     * Gets the path translated with title of docs and folders.
5551
     *
5552
     * @param string $path the real path
5553
     *
5554
     * @return the path which should be displayed
5555
     */
5556
    public static function get_titles_of_path($path)
5557
    {
5558
        global $tmp_folders_titles;
5559
        $course_id = api_get_course_int_id();
5560
        $nb_slashes = substr_count($path, '/');
5561
        $current_slash_pos = 0;
5562
        $path_displayed = '';
5563
        for ($i = 0; $i < $nb_slashes; $i++) {
5564
            // For each folder of the path, retrieve title.
5565
            $current_slash_pos = strpos($path, '/', $current_slash_pos + 1);
5566
            $tmp_path = substr($path, strpos($path, '/', 0), $current_slash_pos);
5567
5568
            if (empty($tmp_path)) {
5569
                // If empty, then we are in the final part of the path
5570
                $tmp_path = $path;
5571
            }
5572
5573
            if (!empty($tmp_folders_titles[$tmp_path])) {
5574
                // If this path has soon been stored here we don't need a new query
5575
                $path_displayed .= $tmp_folders_titles[$tmp_path];
5576
            } else {
5577
                $sql = 'SELECT title FROM '.Database::get_course_table(TABLE_DOCUMENT).'
5578
                        WHERE c_id = '.$course_id.' AND path LIKE BINARY "'.$tmp_path.'"';
5579
                $rs = Database::query($sql);
5580
                $tmp_title = '/'.Database::result($rs, 0, 0);
5581
                $path_displayed .= $tmp_title;
5582
                $tmp_folders_titles[$tmp_path] = $tmp_title;
5583
            }
5584
        }
5585
5586
        return $path_displayed;
5587
    }
5588
5589
    /**
5590
     * Creates form that asks for the directory name.
5591
     *
5592
     * @return string html-output text for the form
5593
     */
5594
    public static function create_dir_form($dirId)
5595
    {
5596
        global $document_id;
5597
        $form = new FormValidator('create_dir_form', 'post', api_get_self().'?'.api_get_cidreq());
5598
        $form->addElement('hidden', 'create_dir', 1);
5599
        $form->addElement('hidden', 'dir_id', intval($document_id));
5600
        $form->addElement('hidden', 'id', intval($dirId));
5601
        $form->addElement('header', get_lang('CreateDir'));
5602
        $form->addText('dirname', get_lang('NewDir'), ['autofocus' => 'autofocus']);
5603
        $form->addButtonCreate(get_lang('CreateFolder'));
5604
5605
        return $form->returnForm();
5606
    }
5607
5608
    /**
5609
     * Checks whether the user is in shared folder.
5610
     *
5611
     * @param string $curdirpath
5612
     * @param int    $sessionId
5613
     *
5614
     * @return bool Return true when user is into shared folder
5615
     */
5616
    public static function is_shared_folder($curdirpath, $sessionId)
5617
    {
5618
        $clean_curdirpath = Security::remove_XSS($curdirpath);
5619
        if ($clean_curdirpath == '/shared_folder') {
5620
            return true;
5621
        } elseif ($clean_curdirpath == '/shared_folder_session_'.$sessionId) {
5622
            return true;
5623
        } else {
5624
            return false;
5625
        }
5626
    }
5627
5628
    /**
5629
     * Checks whether the user is into any user shared folder.
5630
     *
5631
     * @param string $path
5632
     * @param int    $sessionId
5633
     *
5634
     * @return bool Return true when user is in any user shared folder
5635
     */
5636
    public static function is_any_user_shared_folder($path, $sessionId)
5637
    {
5638
        $clean_path = Security::remove_XSS($path);
5639
        if (strpos($clean_path, 'shared_folder/sf_user_')) {
5640
            return true;
5641
        } elseif (strpos($clean_path, 'shared_folder_session_'.$sessionId.'/sf_user_')) {
5642
            return true;
5643
        } else {
5644
            return false;
5645
        }
5646
    }
5647
5648
    /**
5649
     * Create users shared folder for course.
5650
     *
5651
     * @param int   $userId
5652
     * @param array $courseInfo
5653
     * @param int   $sessionId
5654
     */
5655
    public static function createUserSharedFolder($userId, array $courseInfo, $sessionId = 0)
5656
    {
5657
        $documentDirectory = api_get_path(SYS_COURSE_PATH).$courseInfo['directory'].'/document';
5658
        $userInfo = api_get_user_info($userId);
5659
5660
        if (!$sessionId) {
5661
            //Create shared folder. Necessary for recycled courses.
5662
            if (!file_exists($documentDirectory.'/shared_folder')) {
5663
                create_unexisting_directory(
5664
                    $courseInfo,
5665
                    $userId,
5666
                    0,
5667
                    0,
5668
                    0,
5669
                    $documentDirectory,
5670
                    '/shared_folder',
5671
                    get_lang('UserFolders'),
5672
                    0,
5673
                    false,
5674
                    false
5675
                );
5676
            }
5677
            // Create dynamic user shared folder
5678
            if (!file_exists($documentDirectory.'/shared_folder/sf_user_'.$userId)) {
5679
                create_unexisting_directory(
5680
                    $courseInfo,
5681
                    $userId,
5682
                    0,
5683
                    0,
5684
                    0,
5685
                    $documentDirectory,
5686
                    '/shared_folder/sf_user_'.$userId,
5687
                    $userInfo['complete_name'],
5688
                    1,
5689
                    false,
5690
                    false
5691
                );
5692
            }
5693
5694
            return;
5695
        }
5696
5697
        // Create shared folder session.
5698
        if (!file_exists($documentDirectory.'/shared_folder_session_'.$sessionId)) {
5699
            create_unexisting_directory(
5700
                $courseInfo,
5701
                api_get_user_id(),
5702
                $sessionId,
5703
                0,
5704
                0,
5705
                $documentDirectory,
5706
                '/shared_folder_session_'.$sessionId,
5707
                get_lang('UserFolders').' ('.api_get_session_name($sessionId).')',
5708
                0,
5709
                false,
5710
                false
5711
            );
5712
        }
5713
        //Create dynamic user shared folder into a shared folder session
5714
        if (!file_exists($documentDirectory.'/shared_folder_session_'.$sessionId.'/sf_user_'.$userId)) {
5715
            create_unexisting_directory(
5716
                $courseInfo,
5717
                $userId,
5718
                $sessionId,
5719
                0,
5720
                0,
5721
                $documentDirectory,
5722
                '/shared_folder_session_'.$sessionId.'/sf_user_'.$userId,
5723
                $userInfo['complete_name'].'('.api_get_session_name($sessionId).')',
5724
                1,
5725
                false,
5726
                false
5727
            );
5728
        }
5729
    }
5730
5731
    /**
5732
     * Checks whether the user is into his shared folder or into a subfolder.
5733
     *
5734
     * @param int    $user_id
5735
     * @param string $path
5736
     * @param int    $sessionId
5737
     *
5738
     * @return bool Return true when user is in his user shared folder or into a subfolder
5739
     */
5740
    public static function is_my_shared_folder($user_id, $path, $sessionId)
5741
    {
5742
        $clean_path = Security::remove_XSS($path).'/';
5743
        //for security does not remove the last slash
5744
        $main_user_shared_folder = '/shared_folder\/sf_user_'.$user_id.'\//';
5745
        //for security does not remove the last slash
5746
        $main_user_shared_folder_session = '/shared_folder_session_'.$sessionId.'\/sf_user_'.$user_id.'\//';
5747
5748
        if (preg_match($main_user_shared_folder, $clean_path)) {
5749
            return true;
5750
        } elseif (preg_match($main_user_shared_folder_session, $clean_path)) {
5751
            return true;
5752
        } else {
5753
            return false;
5754
        }
5755
    }
5756
5757
    /**
5758
     * Check if the file name or folder searched exist.
5759
     *
5760
     * @return bool Return true when exist
5761
     */
5762
    public static function search_keyword($document_name, $keyword)
5763
    {
5764
        if (api_strripos($document_name, $keyword) !== false) {
5765
            return true;
5766
        } else {
5767
            return false;
5768
        }
5769
    }
5770
5771
    /**
5772
     * Checks whether a document can be previewed by using the browser.
5773
     *
5774
     * @param string $file_extension the filename extension of the document (it must be in lower case)
5775
     *
5776
     * @return bool returns TRUE or FALSE
5777
     */
5778
    public static function isBrowserViewable($file_extension)
5779
    {
5780
        static $allowed_extensions = [
5781
            'htm', 'html', 'xhtml',
5782
            'gif', 'jpg', 'jpeg', 'png', 'tif', 'tiff',
5783
            'pdf', 'svg', 'swf',
5784
            'txt', 'log',
5785
            'mp4', 'ogg', 'ogv', 'ogx', 'mpg', 'mpeg', 'mov', 'avi', 'webm', 'wmv',
5786
            'mp3', 'oga', 'wav', 'au', 'wma', 'mid', 'kar',
5787
        ];
5788
5789
        /*
5790
          //TODO: make a admin switch to strict mode
5791
          1. global default $allowed_extensions
5792
          if (in_array($file_extension, $allowed_extensions)) { // Assignment + a logical check.
5793
          return true;
5794
          }
5795
          2. check native support
5796
          3. check plugins: quicktime, mediaplayer, vlc, acrobat, flash, java
5797
         */
5798
5799
        if (!($result = in_array($file_extension, $allowed_extensions))) {
5800
            // Assignment + a logical check.
5801
            return false;
5802
        }
5803
5804
        //check native support (Explorer, Opera, Firefox, Chrome, Safari)
5805
        if ($file_extension == "pdf") {
5806
            return api_browser_support('pdf');
5807
        } elseif ($file_extension == "mp3") {
5808
            return api_browser_support('mp3');
5809
        } elseif ($file_extension == "mp4") {
5810
            return api_browser_support('mp4');
5811
        } elseif ($file_extension == "ogg" || $file_extension == "ogx" || $file_extension == "ogv" || $file_extension == "oga") {
5812
            return api_browser_support('ogg');
5813
        } elseif ($file_extension == "svg") {
5814
            return api_browser_support('svg');
5815
        } elseif ($file_extension == "mpg" || $file_extension == "mpeg") {
5816
            return api_browser_support('mpg');
5817
        } elseif ($file_extension == "mov") {
5818
            return api_browser_support('mov');
5819
        } elseif ($file_extension == "wav") {
5820
            return api_browser_support('wav');
5821
        } elseif ($file_extension == "mid" || $file_extension == "kar") {
5822
            return api_browser_support('mid');
5823
        } elseif ($file_extension == "avi") {
5824
            return api_browser_support('avi');
5825
        } elseif ($file_extension == "wma") {
5826
            return api_browser_support('wma');
5827
        } elseif ($file_extension == "wmv") {
5828
            return api_browser_support('wmv');
5829
        } elseif ($file_extension == "tif" || $file_extension == "tiff") {
5830
            return api_browser_support('tif');
5831
        } elseif ($file_extension == "mov") {
5832
            return api_browser_support('mov');
5833
        } elseif ($file_extension == "au") {
5834
            return api_browser_support('au');
5835
        } elseif ($file_extension == "webm") {
5836
            return api_browser_support('webm');
5837
        }
5838
5839
        return $result;
5840
    }
5841
5842
    /**
5843
     * @param array $courseInfo
5844
     * @param int   $sessionId
5845
     *
5846
     * @return array
5847
     */
5848
    public static function getDeletedDocuments($courseInfo, $sessionId = 0)
5849
    {
5850
        $table = Database::get_course_table(TABLE_DOCUMENT);
5851
        $courseId = $courseInfo['real_id'];
5852
        $sessionCondition = api_get_session_condition($sessionId);
5853
        $sql = "SELECT * FROM $table
5854
                WHERE
5855
                  path LIKE '%DELETED%' AND
5856
                  c_id = $courseId
5857
                  $sessionCondition
5858
                ORDER BY path
5859
        ";
5860
5861
        $result = Database::query($sql);
5862
        $files = [];
5863
        while ($document = Database::fetch_array($result, 'ASSOC')) {
5864
            $files[] = $document;
5865
        }
5866
5867
        return $files;
5868
    }
5869
5870
    /**
5871
     * @param int   $id
5872
     * @param array $courseInfo
5873
     * @param int   $sessionId
5874
     *
5875
     * @return array
5876
     */
5877
    public static function getDeletedDocument($id, $courseInfo, $sessionId = 0)
5878
    {
5879
        if (empty($courseInfo)) {
5880
            return false;
5881
        }
5882
5883
        $table = Database::get_course_table(TABLE_DOCUMENT);
5884
        $courseId = $courseInfo['real_id'];
5885
        $sessionCondition = api_get_session_condition($sessionId);
5886
        $sql = "SELECT * FROM $table
5887
                WHERE
5888
                  path LIKE '%DELETED%' AND
5889
                  id = $id AND
5890
                  c_id = $courseId
5891
                  $sessionCondition
5892
                LIMIT 1
5893
        ";
5894
        $result = Database::query($sql);
5895
        if (Database::num_rows($result)) {
5896
            $result = Database::fetch_array($result, 'ASSOC');
5897
5898
            return $result;
5899
        }
5900
5901
        return [];
5902
    }
5903
5904
    /**
5905
     * @param int   $id
5906
     * @param array $courseInfo
5907
     * @param int   $sessionId
5908
     *
5909
     * @return bool
5910
     */
5911
    public static function purgeDocument($id, $courseInfo, $sessionId = 0)
5912
    {
5913
        $document = self::getDeletedDocument($id, $courseInfo, $sessionId);
5914
        if (!empty($document)) {
5915
            $path = $document['path'];
5916
            $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/';
5917
            my_delete($coursePath.$path);
5918
            // Hard delete.
5919
            self::deleteDocumentFromDb($id, $courseInfo, $sessionId, true);
5920
5921
            return true;
5922
        }
5923
5924
        return false;
5925
    }
5926
5927
    /**
5928
     * @param array $courseInfo
5929
     * @param int   $sessionId
5930
     */
5931
    public static function purgeDocuments($courseInfo, $sessionId)
5932
    {
5933
        $files = self::getDeletedDocuments($courseInfo, $sessionId);
5934
        foreach ($files as $file) {
5935
            self::purgeDocument($file['id'], $courseInfo, $sessionId);
5936
        }
5937
    }
5938
5939
    /**
5940
     * @param int   $id
5941
     * @param array $courseInfo
5942
     * @param int   $sessionId
5943
     */
5944
    public static function downloadDeletedDocument($id, $courseInfo, $sessionId)
5945
    {
5946
        $document = self::getDeletedDocument($id, $courseInfo, $sessionId);
5947
        if (!empty($document)) {
5948
            $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document/';
5949
5950
            if (Security::check_abs_path($coursePath.$document['path'], $coursePath)) {
5951
                self::file_send_for_download($coursePath.$document['path']);
5952
                exit;
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...
5953
            }
5954
        }
5955
    }
5956
5957
    /**
5958
     * @param array $courseInfo
5959
     * @param int   $sessionId
5960
     *
5961
     * @return bool
5962
     */
5963
    public static function downloadAllDeletedDocument($courseInfo, $sessionId)
5964
    {
5965
        $files = self::getDeletedDocuments($courseInfo, $sessionId);
5966
5967
        if (empty($files)) {
5968
            return false;
5969
        }
5970
5971
        $coursePath = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
5972
5973
        // Creating a ZIP file.
5974
        $tempZipFile = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().".zip";
5975
        $zip = new PclZip($tempZipFile);
5976
        foreach ($files as $file) {
5977
            $zip->add(
5978
                $coursePath.$file['path'],
5979
                PCLZIP_OPT_REMOVE_PATH,
5980
                $coursePath
5981
            );
5982
        }
5983
5984
        if (Security::check_abs_path($tempZipFile, api_get_path(SYS_ARCHIVE_PATH))) {
5985
            self::file_send_for_download($tempZipFile, true);
5986
            @unlink($tempZipFile);
5987
            exit;
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...
5988
        }
5989
    }
5990
5991
    /**
5992
     * Delete documents from a session in a course.
5993
     *
5994
     * @param array $courseInfo
5995
     * @param int   $sessionId
5996
     *
5997
     * @return bool
5998
     */
5999
    public static function deleteDocumentsFromSession($courseInfo, $sessionId)
6000
    {
6001
        if (empty($courseInfo)) {
6002
            return false;
6003
        }
6004
6005
        if (empty($sessionId)) {
6006
            return false;
6007
        }
6008
6009
        $itemPropertyTable = Database::get_course_table(TABLE_ITEM_PROPERTY);
6010
        $documentTable = Database::get_course_table(TABLE_DOCUMENT);
6011
6012
        $conditionSession = api_get_session_condition($sessionId, true, false, 'd.session_id');
6013
        $courseId = $courseInfo['real_id'];
6014
6015
        // get invisible folders
6016
        $sql = "SELECT DISTINCT d.id, path
6017
                FROM $itemPropertyTable i
6018
                INNER JOIN $documentTable d
6019
                ON (i.c_id = d.c_id)
6020
                WHERE
6021
                    d.id = i.ref AND
6022
                    i.tool = '".TOOL_DOCUMENT."'
6023
                    $conditionSession AND
6024
                    i.c_id = $courseId AND
6025
                    d.c_id = $courseId ";
6026
6027
        $result = Database::query($sql);
6028
        $documents = Database::store_result($result, 'ASSOC');
6029
        if ($documents) {
6030
            $course_dir = $courseInfo['directory'].'/document';
6031
            $sys_course_path = api_get_path(SYS_COURSE_PATH);
6032
            $base_work_dir = $sys_course_path.$course_dir;
6033
6034
            foreach ($documents as $document) {
6035
                $documentId = $document['id'];
6036
                self::delete_document(
6037
                    $courseInfo,
6038
                    null,
6039
                    $base_work_dir,
6040
                    $sessionId,
6041
                    $documentId
6042
                );
6043
            }
6044
        }
6045
6046
        $sql = "DELETE FROM $documentTable
6047
                WHERE c_id = $courseId AND session_id = $sessionId";
6048
        Database::query($sql);
6049
6050
        $sql = "DELETE FROM $itemPropertyTable
6051
                WHERE c_id = $courseId AND session_id = $sessionId AND tool = '".TOOL_DOCUMENT."'";
6052
        Database::query($sql);
6053
    }
6054
6055
    /**
6056
     * Update the file or directory path in the document db document table.
6057
     *
6058
     * @author - Hugues Peeters <[email protected]>
6059
     *
6060
     * @param string $action   - action type require : 'delete' or 'update'
6061
     * @param string $old_path - old path info stored to change
6062
     * @param string $new_path - new path info to substitute
6063
     *
6064
     * @desc Update the file or directory path in the document db document table
6065
     */
6066
    public static function updateDbInfo($action, $old_path, $new_path = '')
6067
    {
6068
        $dbTable = Database::get_course_table(TABLE_DOCUMENT);
6069
        $course_id = api_get_course_int_id();
6070
        $old_path = Database::escape_string($old_path);
6071
        switch ($action) {
6072
            case 'delete':
6073
                $query = "DELETE FROM $dbTable
6074
                          WHERE
6075
                            c_id = $course_id AND
6076
                            (
6077
                                path LIKE BINARY '".$old_path."' OR
6078
                                path LIKE BINARY '".$old_path."/%'
6079
                            )";
6080
                Database::query($query);
6081
                break;
6082
            case 'update':
6083
                if ($new_path[0] == '.') {
6084
                    $new_path = substr($new_path, 1);
6085
                }
6086
                $new_path = str_replace('//', '/', $new_path);
6087
6088
                // Attempt to update	- tested & working for root	dir
6089
                $new_path = Database::escape_string($new_path);
6090
                $query = "UPDATE $dbTable SET
6091
                            path = CONCAT('".$new_path."', SUBSTRING(path, LENGTH('".$old_path."')+1) )
6092
                          WHERE 
6093
                                c_id = $course_id AND 
6094
                                (path LIKE BINARY '".$old_path."' OR path LIKE BINARY '".$old_path."/%')";
6095
                Database::query($query);
6096
                break;
6097
        }
6098
    }
6099
6100
    /**
6101
     * This function calculates the resized width and resized heigt
6102
     * according to the source and target widths
6103
     * and heights, height so that no distortions occur
6104
     * parameters.
6105
     *
6106
     * @param $image = the absolute path to the image
0 ignored issues
show
Documentation Bug introduced by
The doc comment = at position 0 could not be parsed: Unknown type name '=' at position 0 in =.
Loading history...
6107
     * @param $target_width = how large do you want your resized image
6108
     * @param $target_height = how large do you want your resized image
6109
     * @param $slideshow (default=0) =
6110
     *      indicates weither we are generating images for a slideshow or not,
6111
     *		this overrides the $_SESSION["image_resizing"] a bit so that a thumbnail
6112
     *	    view is also possible when you choose not to resize the source images
6113
     *
6114
     * @return array
6115
     */
6116
    public static function resizeImageSlideShow(
6117
        $image,
6118
        $target_width,
6119
        $target_height,
6120
        $slideshow = 0
6121
    ) {
6122
        // Modifications by Ivan Tcholakov, 04-MAY-2009.
6123
        $result = [];
6124
        $imageResize = Session::read('image_resizing');
6125
        if ($imageResize == 'resizing' || $slideshow == 1) {
6126
            $new_sizes = api_resize_image($image, $target_width, $target_height);
6127
            $result[] = $new_sizes['height'];
6128
            $result[] = $new_sizes['width'];
6129
        } else {
6130
            $size = api_getimagesize($image);
6131
            $result[] = $size['height'];
6132
            $result[] = $size['width'];
6133
        }
6134
6135
        return $result;
6136
    }
6137
6138
    /**
6139
     * Calculates the total size of a directory by adding the sizes (that
6140
     * are stored in the database) of all files & folders in this directory.
6141
     *
6142
     * @param string $path
6143
     * @param bool   $can_see_invisible
6144
     *
6145
     * @return int Total size
6146
     */
6147
    public static function getTotalFolderSize($path, $can_see_invisible = false)
6148
    {
6149
        $table_itemproperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6150
        $table_document = Database::get_course_table(TABLE_DOCUMENT);
6151
        $tool_document = TOOL_DOCUMENT;
6152
6153
        $course_id = api_get_course_int_id();
6154
        $session_id = api_get_session_id();
6155
        $session_condition = api_get_session_condition(
6156
            $session_id,
6157
            true,
6158
            true,
6159
            'props.session_id'
6160
        );
6161
6162
        if (empty($course_id)) {
6163
            return 0;
6164
        }
6165
6166
        $path = Database::escape_string($path);
6167
        $visibility_rule = ' props.visibility '.($can_see_invisible ? '<> 2' : '= 1');
6168
6169
        $sql = "SELECT SUM(table1.size) FROM (
6170
                SELECT props.ref, size
6171
                FROM $table_itemproperty AS props 
6172
                INNER JOIN $table_document AS docs
6173
                ON (docs.id = props.ref AND docs.c_id = props.c_id)
6174
                WHERE
6175
                    docs.c_id = $course_id AND                    
6176
                    docs.path LIKE '$path/%' AND
6177
                    props.c_id = $course_id AND
6178
                    props.tool = '$tool_document' AND
6179
                    $visibility_rule
6180
                    $session_condition
6181
                GROUP BY ref
6182
            ) as table1";
6183
6184
        $result = Database::query($sql);
6185
        if ($result && Database::num_rows($result) != 0) {
6186
            $row = Database::fetch_row($result);
6187
6188
            return $row[0] == null ? 0 : $row[0];
6189
        } else {
6190
            return 0;
6191
        }
6192
    }
6193
6194
    /**
6195
     * Adds a cloud link to the database.
6196
     *
6197
     * @author - Aquilino Blanco Cores <[email protected]>
6198
     *
6199
     * @param array  $_course
6200
     * @param string $path
6201
     * @param string $url
6202
     * @param string $name
6203
     *
6204
     * @return int id of document or 0 if already exists or there was a problem creating it
6205
     */
6206
    public static function addCloudLink($_course, $path, $url, $name)
6207
    {
6208
        $file_path = $path;
6209
        if (!self::cloudLinkExists($_course, $path, $url)) {
6210
            $doc = self::addDocument($_course, $file_path, 'link', 0, $name, $url);
6211
6212
            return $doc->getId();
6213
        } else {
6214
            return 0;
6215
        }
6216
    }
6217
6218
    /**
6219
     * Deletes a cloud link from the database.
6220
     *
6221
     * @author - Aquilino Blanco Cores <[email protected]>
6222
     *
6223
     * @param array  $courseInfo
6224
     * @param string $documentId
6225
     *
6226
     * @return bool true if success / false if an error occurred
6227
     */
6228
    public static function deleteCloudLink($courseInfo, $documentId)
6229
    {
6230
        if (empty($documentId) || empty($courseInfo)) {
6231
            return false;
6232
        }
6233
6234
        $documentId = (int) $documentId;
6235
        $fileDeletedFromDb = false;
6236
        if (!empty($documentId)) {
6237
            self::deleteDocumentFromDb($documentId, $courseInfo, 0, true);
6238
            // checking
6239
            $table = Database::get_course_table(TABLE_DOCUMENT);
6240
            $courseId = $courseInfo['real_id'];
6241
            echo $sql = "SELECT * FROM $table WHERE id = $documentId AND c_id = $courseId";
6242
            $result = Database::query($sql);
6243
            $exists = Database::num_rows($result) > 0;
6244
            $fileDeletedFromDb = !$exists;
6245
        }
6246
6247
        return $fileDeletedFromDb;
6248
    }
6249
6250
    /**
6251
     * Gets the id of a cloud link with a given path.
6252
     *
6253
     * @author - Aquilino Blanco Cores <[email protected]>
6254
     *
6255
     * @param array  $courseInfo
6256
     * @param string $path
6257
     * @param string $url
6258
     *
6259
     * @return int link's id / false if no link found
6260
     */
6261
    public static function getCloudLinkId($courseInfo, $path, $url)
6262
    {
6263
        $table = Database::get_course_table(TABLE_DOCUMENT);
6264
6265
        if (empty($courseInfo)) {
6266
            return false;
6267
        }
6268
6269
        $courseId = (int) $courseInfo['real_id'];
6270
        $path = Database::escape_string($path);
6271
6272
        if (substr($path, -1) != '/') {
6273
            // Add final slash to path if not present
6274
            $path .= '/';
6275
        }
6276
6277
        if (!empty($courseId) && !empty($path)) {
6278
            $sql = "SELECT id FROM $table 
6279
                    WHERE 
6280
                        c_id = $courseId AND 
6281
                        path LIKE BINARY '$path' AND 
6282
                        comment = '$url' AND 
6283
                        filetype = 'link' 
6284
                    LIMIT 1";
6285
            $result = Database::query($sql);
6286
            if ($result && Database::num_rows($result)) {
6287
                $row = Database::fetch_array($result);
6288
6289
                return intval($row[0]);
6290
            }
6291
        }
6292
6293
        return false;
6294
    }
6295
6296
    /**
6297
     * Checks if a cloud link exists.
6298
     *
6299
     * @author - Aquilino Blanco Cores <[email protected]>
6300
     *
6301
     * @param array  $courseInfo
6302
     * @param string $path
6303
     * @param string $url
6304
     *
6305
     * @return bool true if it exists false in other case
6306
     */
6307
    public static function cloudLinkExists($courseInfo, $path, $url)
6308
    {
6309
        $exists = self::getCloudLinkId($courseInfo, $path, $url);
6310
6311
        return $exists;
6312
    }
6313
6314
    /**
6315
     * Gets the wellformed URLs regular expression in order to use it on forms' verifications.
6316
     *
6317
     * @author Aquilino Blanco Cores <[email protected]>
6318
     *
6319
     * @return string the well formed URLs regular expressions string
6320
     */
6321
    public static function getWellFormedUrlRegex()
6322
    {
6323
        return '/\(?((http|https|ftp):\/\/)(?:((?:[^\W\s]|\.|-|[:]{1})+)@{1})?((?:www.)?(?:[^\W\s]|\.|-)+[\.][^\W\s]{2,4}|localhost(?=\/)|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::(\d*))?([\/]?[^\s\?]*[\/]{1})*(?:\/?([^\s\n\?\[\]\{\}\#]*(?:(?=\.)){1}|[^\s\n\?\[\]\{\}\.\#]*)?([\.]{1}[^\s\?\#]*)?)?(?:\?{1}([^\s\n\#\[\]]*))?([\#][^\s\n]*)?\)?/i';
6324
    }
6325
6326
    /**
6327
     * Gets the files hosting sites' whitelist.
6328
     *
6329
     * @author Aquilino Blanco Cores <[email protected]>
6330
     *
6331
     * @return array the sites list
6332
     */
6333
    public static function getFileHostingWhiteList()
6334
    {
6335
        return [
6336
            'asuswebstorage.com',
6337
            'dropbox.com',
6338
            'dropboxusercontent.com',
6339
            'fileserve.com',
6340
            'drive.google.com',
6341
            'icloud.com',
6342
            'mediafire.com',
6343
            'mega.nz',
6344
            'onedrive.live.com',
6345
            'slideshare.net',
6346
            'scribd.com',
6347
            'wetransfer.com',
6348
            'box.com',
6349
            'livefilestore.com', // OneDrive
6350
        ];
6351
    }
6352
6353
    /**
6354
     * @param int $userId
6355
     *
6356
     * @return array Example [ 0 => ['code' => 'ABC', 'directory' => 'ABC0', 'path' => '/images/gallery/test.png', 'code_path' => 'ABC:/images/gallery/test.png'], 1 => ...]
6357
     */
6358
    public static function getAllDocumentsCreatedByUser($userId)
6359
    {
6360
        $tblItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
6361
        $tblDocument = Database::get_course_table(TABLE_DOCUMENT);
6362
        $tblCourse = Database::get_main_table(TABLE_MAIN_COURSE);
6363
        $userId = (int) $userId;
6364
6365
        $sql = "SELECT DISTINCT c.code, c.directory, docs.path
6366
                FROM $tblItemProperty AS last
6367
                INNER JOIN $tblDocument AS docs
6368
                ON (
6369
                    docs.id = last.ref AND
6370
                    docs.c_id = last.c_id AND
6371
                    docs.filetype <> 'folder'
6372
                )
6373
                INNER JOIN $tblCourse as c
6374
                ON (
6375
                    docs.c_id = c.id
6376
                )
6377
                WHERE                                
6378
                    last.tool = '".TOOL_DOCUMENT."' AND   
6379
                    last.insert_user_id = $userId AND
6380
                    docs.path NOT LIKE '%_DELETED_%'                     
6381
                ORDER BY c.directory, docs.path
6382
                ";
6383
        $result = Database::query($sql);
6384
6385
        $list = [];
6386
        if (Database::num_rows($result) != 0) {
6387
            while ($row = Database::fetch_array($result, 'ASSOC')) {
6388
                $row['code_path'] = $row['code'].':'.$row['path'];
6389
                $list[] = $row;
6390
            }
6391
        }
6392
6393
        return $list;
6394
    }
6395
6396
    /**
6397
     * Parse file information into a link.
6398
     *
6399
     * @param array  $userInfo        Current user info
6400
     * @param array  $course_info
6401
     * @param int    $session_id
6402
     * @param array  $resource
6403
     * @param int    $lp_id
6404
     * @param bool   $add_move_button
6405
     * @param string $target
6406
     * @param string $overwrite_url
6407
     *
6408
     * @return null|string
6409
     */
6410
    private static function parseFile(
6411
        $userInfo,
6412
        $course_info,
6413
        $session_id,
6414
        $resource,
6415
        $lp_id,
6416
        $add_move_button,
6417
        $target,
6418
        $overwrite_url
6419
    ) {
6420
        $img_sys_path = api_get_path(SYS_CODE_PATH).'img/';
6421
        $web_code_path = api_get_path(WEB_CODE_PATH);
6422
6423
        $documentId = $resource['id'];
6424
        $path = $resource['path'];
6425
6426
        if (empty($path)) {
6427
            $num = 0;
6428
        } else {
6429
            $num = substr_count($path, '/') - 1;
6430
        }
6431
6432
        // It's a file.
6433
        $icon = choose_image($path);
6434
        $position = strrpos($icon, '.');
6435
        $icon = substr($icon, 0, $position).'_small.gif';
6436
        $my_file_title = $resource['title'];
6437
        $visibility = $resource['visibility'];
6438
6439
        // If title is empty we try to use the path
6440
        if (empty($my_file_title)) {
6441
            $my_file_title = basename($path);
6442
        }
6443
6444
        // Show the "image name" not the filename of the image.
6445
        if ($lp_id) {
6446
            // LP URL
6447
            $url = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq().'&action=add_item&type='.TOOL_DOCUMENT.'&file='.$documentId.'&lp_id='.$lp_id;
6448
            if (!empty($overwrite_url)) {
6449
                $url = $overwrite_url.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'&document_id='.$documentId.'';
6450
            }
6451
        } else {
6452
            // Direct document URL
6453
            $url = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
6454
            if (!empty($overwrite_url)) {
6455
                $url = $overwrite_url.'&cidReq='.$course_info['code'].'&id_session='.$session_id.'&document_id='.$documentId;
6456
            }
6457
        }
6458
6459
        $img = Display::returnIconPath($icon);
6460
        if (!file_exists($img_sys_path.$icon)) {
6461
            $img = Display::returnIconPath('default_small.gif');
6462
        }
6463
6464
        $link = Display::url(
6465
            '<img alt="" src="'.$img.'" title="" />&nbsp;'.$my_file_title,
6466
            $url,
6467
            ['target' => $target, 'class' => 'moved']
6468
        );
6469
6470
        $directUrl = $web_code_path.'document/document.php?cidReq='.$course_info['code'].'&id_session='.$session_id.'&id='.$documentId;
6471
        $link .= '&nbsp;'.Display::url(
6472
            Display::return_icon('preview_view.png', get_lang('Preview')),
6473
            $directUrl,
6474
            ['target' => '_blank']
6475
        );
6476
6477
        $visibilityClass = null;
6478
        if ($visibility == 0) {
6479
            $visibilityClass = ' text-muted ';
6480
        }
6481
        $return = null;
6482
6483
        if ($lp_id == false) {
6484
            $return .= '<li class="doc_resource '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
6485
        } else {
6486
            $return .= '<li class="doc_resource lp_resource_element '.$visibilityClass.' " data_id="'.$documentId.'" data_type="document" title="'.$my_file_title.'" >';
6487
        }
6488
6489
        $return .= '<div class="item_data" style="margin-left:'.($num * 5).'px;margin-right:5px;">';
6490
        if ($add_move_button) {
6491
            $return .= '<a class="moved" href="#">';
6492
            $return .= Display::return_icon('move_everywhere.png', get_lang('Move'), [], ICON_SIZE_TINY);
6493
            $return .= '</a> ';
6494
        }
6495
        $return .= $link;
6496
        $sessionStar = api_get_session_image($resource['session_id'], $userInfo['status']);
6497
        $return .= $sessionStar;
6498
6499
        $return .= '</div></li>';
6500
6501
        return $return;
6502
    }
6503
6504
    /**
6505
     * @param int   $folderId
6506
     * @param array $resource
6507
     * @param int   $lp_id
6508
     *
6509
     * @return null|string
6510
     */
6511
    private static function parseFolder($folderId, $resource, $lp_id)
6512
    {
6513
        $title = isset($resource['title']) ? $resource['title'] : null;
6514
        $path = isset($resource['path']) ? $resource['path'] : null;
6515
6516
        if (empty($path)) {
6517
            $num = 0;
6518
        } else {
6519
            $num = substr_count($path, '/');
6520
        }
6521
6522
        // It's a folder.
6523
        //hide some folders
6524
        if (in_array(
6525
            $path,
6526
            ['shared_folder', 'chat_files', 'HotPotatoes_files', 'css', 'certificates']
6527
        )) {
6528
            return null;
6529
        } elseif (preg_match('/_groupdocs/', $path)) {
6530
            return null;
6531
        } elseif (preg_match('/sf_user_/', $path)) {
6532
            return null;
6533
        } elseif (preg_match('/shared_folder_session_/', $path)) {
6534
            return null;
6535
        }
6536
6537
        $onclick = '';
6538
        // if in LP, hidden folder are displayed in grey
6539
        $folder_class_hidden = '';
6540
        if ($lp_id) {
6541
            if (isset($resource['visible']) && $resource['visible'] == 0) {
6542
                $folder_class_hidden = "doc_folder_hidden"; // in base.css
6543
            }
6544
            $onclick = 'onclick="javascript: testResources(\'res_'.$resource['id'].'\',\'img_'.$resource['id'].'\')"';
6545
        }
6546
        $return = null;
6547
6548
        if (empty($path)) {
6549
            $return = '<ul class="lp_resource">';
6550
        }
6551
6552
        $return .= '<li class="doc_folder '.$folder_class_hidden.'" id="doc_id_'.$resource['id'].'"  style="margin-left:'.($num * 18).'px; ">';
6553
6554
        $image = Display::returnIconPath('nolines_plus.gif');
6555
        if (empty($path)) {
6556
            $image = Display::returnIconPath('nolines_minus.gif');
6557
        }
6558
        $return .= '<img style="cursor: pointer;" src="'.$image.'" align="absmiddle" id="img_'.$resource['id'].'" '.$onclick.'>';
6559
        $return .= Display::return_icon('lp_folder.gif').'&nbsp;';
6560
        $return .= '<span '.$onclick.' style="cursor: pointer;" >'.$title.'</span>';
6561
        $return .= '</li>';
6562
6563
        if (empty($path)) {
6564
            if ($folderId == false) {
6565
                $return .= '<div id="res_'.$resource['id'].'" >';
6566
            } else {
6567
                $return .= '<div id="res_'.$resource['id'].'" style="display: none;" >';
6568
            }
6569
        }
6570
6571
        return $return;
6572
    }
6573
6574
    /**
6575
     * Get the button to edit document.
6576
     *
6577
     * @param bool   $isReadOnly
6578
     * @param array  $documentData
6579
     * @param string $extension
6580
     * @param bool   $isCertificateMode
6581
     *
6582
     * @return string
6583
     */
6584
    private static function getButtonEdit($isReadOnly, array $documentData, $extension, $isCertificateMode)
6585
    {
6586
        $extension = strtolower($extension);
6587
        $iconEn = Display::return_icon('edit.png', get_lang('Modify'));
6588
        $iconDis = Display::return_icon('edit_na.png', get_lang('Modify'));
6589
        $courseParams = api_get_cidreq();
6590
        $webOdfExtensionList = self::get_web_odf_extension_list();
6591
        $path = $documentData['path'];
6592
        $document_id = $documentData['id'];
6593
6594
        if ($isReadOnly) {
6595
            if (!api_is_course_admin() && !api_is_platform_admin()) {
6596
                return $iconDis;
6597
            }
6598
6599
            if (
6600
                $extension == 'svg' && api_browser_support('svg') &&
6601
                api_get_setting('enabled_support_svg') == 'true'
6602
            ) {
6603
                return Display::url($iconEn, "edit_draw.php?$courseParams&id=$document_id");
6604
            }
6605
6606
            if (
6607
                in_array($extension, $webOdfExtensionList) &&
6608
                api_get_configuration_value('enabled_support_odf') === true
6609
            ) {
6610
                return Display::url($iconEn, "edit_odf.php?$courseParams&id=$document_id");
6611
            }
6612
6613
            if (
6614
                in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
6615
                    api_get_setting('enabled_support_pixlr') == 'true'
6616
            ) {
6617
                return Display::url($iconEn, "edit_paint.php?$courseParams&id=$document_id");
6618
            }
6619
6620
            return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id");
6621
        }
6622
6623
        if (in_array($path, self::get_system_folders())) {
6624
            return $iconDis;
6625
        }
6626
6627
        if ($isCertificateMode) {
6628
            return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id&curdirpath=/certificates");
6629
        }
6630
6631
        $sessionId = api_get_session_id();
6632
6633
        if ($sessionId && $documentData['session_id'] != $sessionId) {
6634
            return $iconDis;
6635
        }
6636
6637
        if (
6638
            $extension == 'svg' && api_browser_support('svg') &&
6639
            api_get_setting('enabled_support_svg') == 'true'
6640
        ) {
6641
            return Display::url($iconEn, "edit_draw.php?$courseParams&id=$document_id");
6642
        }
6643
6644
        if (
6645
            in_array($extension, $webOdfExtensionList) &&
6646
            api_get_configuration_value('enabled_support_odf') === true
6647
        ) {
6648
            return Display::url($iconEn, "edit_odf.php?$courseParams&id=$document_id");
6649
        }
6650
6651
        if (
6652
            in_array($extension, ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'pxd']) &&
6653
                api_get_setting('enabled_support_pixlr') == 'true'
6654
        ) {
6655
            return Display::url($iconEn, "edit_paint.php?$courseParams&id=$document_id");
6656
        }
6657
6658
        return Display::url($iconEn, "edit_document.php?$courseParams&id=$document_id");
6659
    }
6660
6661
    /**
6662
     * Get the button to move document.
6663
     *
6664
     * @param bool  $isReadOnly
6665
     * @param array $documentData
6666
     * @param bool  $isCertificateMode
6667
     * @param int   $parentId
6668
     *
6669
     * @return string
6670
     */
6671
    private static function getButtonMove($isReadOnly, array $documentData, $isCertificateMode, $parentId)
6672
    {
6673
        $iconEn = Display::return_icon('move.png', get_lang('Move'));
6674
        $iconDis = Display::return_icon('move_na.png', get_lang('Move'));
6675
6676
        if ($isReadOnly) {
6677
            return $iconDis;
6678
        }
6679
6680
        $path = $documentData['path'];
6681
        $document_id = $documentData['id'];
6682
        $sessionId = api_get_session_id();
6683
        $courseParams = api_get_cidreq();
6684
6685
        if ($isCertificateMode || in_array($path, self::get_system_folders())) {
6686
            return $iconDis;
6687
        }
6688
6689
        if ($sessionId) {
6690
            if ($documentData['session_id'] != $sessionId) {
6691
                return $iconDis;
6692
            }
6693
        }
6694
6695
        $urlMoveParams = http_build_query(['id' => $parentId, 'move' => $document_id]);
6696
6697
        return Display::url(
6698
            $iconEn,
6699
            api_get_self()."?$courseParams&$urlMoveParams"
6700
        );
6701
    }
6702
6703
    /**
6704
     * Get the button to set visibility to document.
6705
     *
6706
     * @param bool  $isReadOnly
6707
     * @param int   $visibility
6708
     * @param array $documentData
6709
     * @param bool  $isCertificateMode
6710
     * @param int   $parentId
6711
     *
6712
     * @return null|string
6713
     */
6714
    private static function getButtonVisibility(
6715
        $isReadOnly,
6716
        $visibility,
6717
        array $documentData,
6718
        $isCertificateMode,
6719
        $parentId
6720
    ) {
6721
        $visibility_icon = $visibility == 0 ? 'invisible' : 'visible';
6722
        $visibility_command = $visibility == 0 ? 'set_visible' : 'set_invisible';
6723
        $courseParams = api_get_cidreq();
6724
6725
        if ($isReadOnly) {
6726
            if (api_is_allowed_to_edit() || api_is_platform_admin()) {
6727
                return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
6728
            }
6729
6730
            return null;
6731
        }
6732
6733
        if ($isCertificateMode) {
6734
            return Display::return_icon($visibility_icon.'.png', get_lang('VisibilityCannotBeChanged'));
6735
        }
6736
6737
        if (api_is_allowed_to_edit() || api_is_platform_admin()) {
6738
            $tip_visibility = $visibility_icon == 'invisible' ? get_lang('Show') : get_lang('Hide');
6739
6740
            return Display::url(
6741
                Display::return_icon($visibility_icon.'.png', $tip_visibility),
6742
                api_get_self()."?$courseParams&id=$parentId&$visibility_command={$documentData['id']}"
6743
            );
6744
        }
6745
6746
        return null;
6747
    }
6748
6749
    /**
6750
     * GEt the button to delete a document.
6751
     *
6752
     * @param bool   $isReadOnly
6753
     * @param array  $documentData
6754
     * @param bool   $isCertificateMode
6755
     * @param string $curDirPath
6756
     * @param int    $parentId
6757
     *
6758
     * @return string
6759
     */
6760
    private static function getButtonDelete(
6761
        $isReadOnly,
6762
        array $documentData,
6763
        $isCertificateMode,
6764
        $curDirPath,
6765
        $parentId
6766
    ) {
6767
        $iconEn = Display::return_icon('delete.png', get_lang('Delete'));
6768
        $iconDis = Display::return_icon('delete_na.png', get_lang('ThisFolderCannotBeDeleted'));
6769
        $path = $documentData['path'];
6770
        $id = $documentData['id'];
6771
        $courseParams = api_get_cidreq();
6772
6773
        if ($isReadOnly) {
6774
            return $iconDis;
6775
        }
6776
6777
        if (in_array($path, self::get_system_folders())) {
6778
            return $iconDis;
6779
        }
6780
6781
        $titleToShow = addslashes(basename($documentData['title']));
6782
        $urlDeleteParams = http_build_query([
6783
            'curdirpath' => $curDirPath,
6784
            'action' => 'delete_item',
6785
            'id' => $parentId,
6786
            'deleteid' => $documentData['id'],
6787
        ]);
6788
6789
        $btn = Display::url(
6790
            $iconEn,
6791
            '#',
6792
            [
6793
                'data-item-title' => $titleToShow,
6794
                'data-href' => api_get_self()."?$courseParams&$urlDeleteParams",
6795
                'data-toggle' => 'modal',
6796
                'data-target' => '#confirm-delete',
6797
            ]
6798
        );
6799
6800
        if (
6801
            isset($_GET['curdirpath']) &&
6802
            $_GET['curdirpath'] == '/certificates' &&
6803
            self::get_default_certificate_id(api_get_course_int_id()) == $id
6804
        ) {
6805
            return $btn;
6806
        }
6807
6808
        if ($isCertificateMode) {
6809
            return $btn;
6810
        }
6811
6812
        $sessionId = api_get_session_id();
6813
6814
        if ($sessionId) {
6815
            if ($documentData['session_id'] != $sessionId) {
6816
                return $iconDis;
6817
            }
6818
        }
6819
6820
        return $btn;
6821
    }
6822
6823
6824
    /**
6825
     * Adds a new document to the database.
6826
     *
6827
     * @param array  $courseInfo
6828
     * @param string $path
6829
     * @param string $fileType
6830
     * @param int    $fileSize
6831
     * @param string $title
6832
     * @param string $comment
6833
     * @param int    $readonly
6834
     * @param int    $visibility       see ResourceLink constants
6835
     * @param int    $group_id         group.id
6836
     * @param int    $sessionId        Session ID, if any
6837
     * @param int    $userId           creator user id
6838
     * @param bool   $sendNotification
6839
     * @param string $content
6840
     * @param int    $parentId
6841
     *
6842
     * @return CDocument|false
6843
     */
6844
    public static function addDocument(
6845
        $courseInfo,
6846
        $path,
6847
        $fileType,
6848
        $fileSize,
6849
        $title,
6850
        $comment = null,
6851
        $readonly = 0,
6852
        $visibility = null,
6853
        $group_id = 0,
6854
        $sessionId = 0,
6855
        $userId = 0,
6856
        $sendNotification = true,
6857
        $content = '',
6858
        $parentId = 0
6859
    ) {
6860
        $userId = empty($userId) ? api_get_user_id() : $userId;
6861
6862
        if (empty($userId)) {
6863
            return false;
6864
        }
6865
6866
        $userEntity = api_get_user_entity($userId);
6867
        if (empty($userEntity)) {
6868
            return false;
6869
        }
6870
6871
        $courseEntity = api_get_course_entity($courseInfo['real_id']);
6872
6873
        if (empty($courseEntity)) {
6874
            return false;
6875
        }
6876
6877
        $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
6878
        $session = api_get_session_entity($sessionId);
6879
        $group = api_get_group_entity($group_id);
6880
        $readonly = (int) $readonly;
6881
6882
        $em = Database::getManager();
6883
        $documentRepo = $em->getRepository('ChamiloCourseBundle:CDocument');
6884
6885
        $parentNode = null;
6886
        if (!empty($parentId)) {
6887
            $parent = $documentRepo->find($parentId);
6888
            if ($parent) {
6889
                $parentNode = $parent->getResourceNode();
6890
            }
6891
        }
6892
6893
        $document = new CDocument();
6894
        $document
6895
            ->setCourse($courseEntity)
6896
            ->setPath($path)
6897
            ->setFiletype($fileType)
6898
            ->setSize($fileSize)
6899
            ->setTitle($title)
6900
            ->setComment($comment)
6901
            ->setReadonly($readonly)
6902
            ->setSession($session)
6903
        ;
6904
6905
        $em->persist($document);
6906
        $em->flush();
6907
6908
        $resourceNode = $documentRepo->addResourceNode($document, $userEntity);
6909
        $resourceNode->setParent($parentNode);
6910
        $document->setResourceNode($resourceNode);
6911
6912
        // Only create a ResourseFile and Media if there's a file involved
6913
        if ($fileType === 'file') {
6914
            $mediaManager = Container::$container->get('sonata.media.manager.media');
6915
            /** @var \Chamilo\MediaBundle\Entity\Media $media */
6916
            $media = $mediaManager->create();
6917
            $media->setName($title);
6918
6919
            $fileName = basename($path);
6920
            $extension = pathinfo($fileName, PATHINFO_EXTENSION);
6921
            $media->setContext('default');
6922
6923
            $provider = 'sonata.media.provider.image';
6924
            if (!in_array($extension, ['jpeg', 'jpg', 'gif', 'png'])) {
6925
                $provider = 'sonata.media.provider.file';
6926
            }
6927
6928
            $media->setProviderName($provider);
6929
            $media->setEnabled(true);
6930
6931
            if ($content instanceof UploadedFile) {
6932
                $file = $content;
6933
                $media->setSize($file->getSize());
6934
            } else {
6935
                $handle = tmpfile();
6936
                fwrite($handle, $content);
6937
                $file = new \Sonata\MediaBundle\Extra\ApiMediaFile($handle);
6938
                $file->setMimetype($media->getContentType());
6939
            }
6940
6941
            $media->setBinaryContent($file);
6942
            $mediaManager->save($media, true);
6943
6944
            $resourceFile = new ResourceFile();
6945
            $resourceFile->setMedia($media);
6946
            $resourceFile->setName($title);
6947
            $em->persist($resourceFile);
6948
6949
            $resourceNode->setResourceFile($resourceFile);
6950
            $em->persist($resourceNode);
6951
        }
6952
6953
        // By default visibility is published
6954
        // @todo change visibility
6955
        //$newVisibility = ResourceLink::VISIBILITY_PUBLISHED;
6956
6957
        if (is_null($visibility)) {
6958
            $visibility = ResourceLink::VISIBILITY_PUBLISHED;
6959
        }
6960
6961
        $link = new ResourceLink();
6962
        $link
6963
            ->setCourse($courseEntity)
6964
            ->setSession($session)
6965
            ->setGroup($group)
6966
            //->setUser($toUser)
6967
            ->setResourceNode($resourceNode)
6968
            ->setVisibility($visibility)
6969
        ;
6970
6971
        $rights = [];
6972
        switch ($visibility) {
6973
            case ResourceLink::VISIBILITY_PENDING:
6974
            case ResourceLink::VISIBILITY_DRAFT:
6975
                $editorMask = ResourceNodeVoter::getEditorMask();
6976
                $resourceRight = new ResourceRight();
6977
                $resourceRight
6978
                    ->setMask($editorMask)
6979
                    ->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
6980
                ;
6981
                $rights[] = $resourceRight;
6982
6983
                break;
6984
        }
6985
6986
        if (!empty($rights)) {
6987
            foreach ($rights as $right) {
6988
                $link->addResourceRight($right);
6989
            }
6990
        }
6991
6992
        $em->persist($link);
6993
        $em->persist($document);
6994
        $em->flush();
6995
6996
        $documentId = $document->getIid();
6997
        if ($documentId) {
6998
            $table = Database::get_course_table(TABLE_DOCUMENT);
6999
            $sql = "UPDATE $table SET id = iid WHERE iid = $documentId";
7000
            Database::query($sql);
7001
7002
            /*if ($saveVisibility) {
7003
                api_set_default_visibility(
7004
                    $documentId,
7005
                    TOOL_DOCUMENT,
7006
                    $group_id,
7007
                    $courseInfo,
7008
                    $sessionId,
7009
                    $userId
7010
                );
7011
            }*/
7012
7013
            $allowNotification = api_get_configuration_value('send_notification_when_document_added');
7014
            if ($sendNotification && $allowNotification) {
7015
                $courseTitle = $courseInfo['title'];
7016
                if (!empty($sessionId)) {
7017
                    $sessionInfo = api_get_session_info($sessionId);
7018
                    $courseTitle .= ' ( '.$sessionInfo['name'].') ';
7019
                }
7020
7021
                $url = api_get_path(WEB_CODE_PATH).
7022
                    'document/showinframes.php?cidReq='.$courseInfo['code'].'&id_session='.$sessionId.'&id='.$documentId;
7023
                $link = Display::url(basename($title), $url, ['target' => '_blank']);
7024
                $userInfo = api_get_user_info($userId);
7025
7026
                $message = sprintf(
7027
                    get_lang('DocumentXHasBeenAddedToDocumentInYourCourseXByUserX'),
7028
                    $link,
7029
                    $courseTitle,
7030
                    $userInfo['complete_name']
7031
                );
7032
                $subject = sprintf(get_lang('NewDocumentAddedToCourseX'), $courseTitle);
7033
                MessageManager::sendMessageToAllUsersInCourse($subject, $message, $courseInfo, $sessionId);
7034
            }
7035
7036
            return $document;
7037
        }
7038
7039
        return false;
7040
    }
7041
}
7042